2020年9月

早些前写了Cacheable的自定义缓存啥的, 这次优化了一下Cacheable注解错误时缓存

需缓存的方法

@Cacheable(key = "#cardNo + '_' + #unifTranId", cacheNames = "bill.usTrade")
public TradeSkinResDto<StmtTradeResDto> usTrade(String cardNo, String unifTranId) {
    return null;
}

AOP

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * redis缓存调用切面
 * <p>
 * 由于服务调用时, 返回的可能是错误的信息, 因此需要将错误信息也缓存起来
 * <p>
 * 方法中使用这个 @Cacheable 注解, 就会处理返回的参数
 *
 * @author roothk
 * @date 2020/4/23 8:53
 */
@Slf4j
@Order(1)
@Aspect
@Component
public class CacheableHandlerAspect {

    @Autowired
    private CacheableUtil cacheableUtil;

    @Pointcut("@annotation(org.springframework.cache.annotation.Cacheable)")
    public void feignAspectPointCut() {
    }

    /**
     * 环绕通知 @Around  , 当然也可以使用 @Before (前置通知)  @After (后置通知)
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("feignAspectPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Cacheable cacheable = cacheableUtil.getCacheable(point);
        String cacheName = cacheable.cacheNames()[0];
        String key = cacheableUtil.getValueByKey(cacheable.key(), point);

        try {
            // 错误处理
            handlerException(key, cacheName);

            Object o = point.proceed();
            // 其他正常返回, 如空对象
            if (EsbThreadLocal.get()) {
                // 也依旧缓存, 防止缓存穿透
                cacheableUtil.saveCache(o, key, cacheName);
            }
            return o;
        } catch (EsbException e) {
            cacheableUtil.saveCache(e, key, cacheName);
            throw e;
        }
    }

    /**
     * 如果缓存报错的是Exception, 则直接抛出Exception
     *
     * @param key
     * @param cacheName
     */
    private void handlerException(Object key, String cacheName) {
        Object o = cacheableUtil.getCache(key, cacheName);
        if (o == null) {
            return;
        }
        // 如果是错误就直接输出
        if (o instanceof EsbException) {
            throw (EsbException) o;
        } else if (o instanceof EsbHystrixException) {
            throw (EsbHystrixException) o;
        } else if (o instanceof EsbServiceException) {
            throw (EsbServiceException) o;
        }
    }

}

CacheableUtil工具类

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author RootHK
 */
@Slf4j
@Component
public class CacheableUtil {

    private final SpelExpressionParser parserSpel = new SpelExpressionParser();
    private final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    // 错误时的缓存时间
    @Value("${esb.cache.not.result.time}")
    private Long exceptionTimeout;

    @Autowired
    private CacheManager cacheManager;
    @Autowired
    private RedisCacheManager redisCacheManager;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取方法上的 @Cacheable
     *
     * @param point
     * @return
     */
    public Cacheable getCacheable(ProceedingJoinPoint point) {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        return targetMethod.getAnnotation(Cacheable.class);
    }

    /**
     * 获取Spring Sl语法的值
     * @param key
     * @param pjp
     * @return
     */
    public String getValueByKey(String key, ProceedingJoinPoint pjp) {
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        return getValueByKey(key, methodSignature.getMethod(), pjp.getArgs());
    }

    /**
     * 获取Spring Sl语法的值
     * @param key
     * @param m
     * @param args
     * @return
     */
    public String getValueByKey(String key, Method m, Object[] args) {
        Expression expression = parserSpel.parseExpression(key);
        EvaluationContext context = new StandardEvaluationContext();
        String[] paramNames = parameterNameDiscoverer.getParameterNames(m);
        for (int i = 0; i < args.length; i++) {
            if (paramNames == null) {
                continue;
            }
            context.setVariable(paramNames[i], args[i]);
        }
        Object o = expression.getValue(context);
        return o != null ? o.toString() : null;
    }

    public Object getCache(Object key, String cacheName) {
        // 获取指定命名空间的cache
        Cache cache = cacheManager.getCache(cacheName);
        if (cache == null) {
            if (log.isDebugEnabled()) {
                log.debug("------ 获取缓存: {} 失败", cacheName);
            }
            return null;
        }
        Cache.ValueWrapper wrapper = cache.get(key);
        if (wrapper == null) {
            // 空的
            return null;
        }
        return wrapper.get();
    }

    public Cache getCache(String cacheName) {
        return cacheManager.getCache(cacheName);
    }

    public void saveCache(Object o, Object key, String cacheName) {
        // 获取指定命名空间的cache
        Cache cache = this.getCache(cacheName);
        if (cache == null) {
            log.warn("获得cacheName失败, {}", cacheName);
            return;
        }
        // 加入缓存
        cache.put(key, o);
        try {
            // 获取redis的配置
            RedisCacheConfiguration configuration = redisCacheManager.getCacheConfigurations().get(cacheName);
            String redisKey = configuration.getKeyPrefixFor(cacheName).concat(key.toString());
            log.info("save exception|not result redis, key:{} timeout:{}", redisKey, exceptionTimeout);
            stringRedisTemplate.expire(redisKey, exceptionTimeout, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("获取RedisCacheConfiguration失败", e);
        }
    }
}

缓存配置 CacheConfig


import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.Duration;
import java.util.Objects;

/**
 * redis 缓存设置
 * @author RootHK
 */
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    // 正常缓存的时间
    @Value("${esb.cache.result.time}")
    private Long timeout;

    /**
     * 设置缓存策略
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public CacheManager cacheManager(StringRedisTemplate redisTemplate) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .prefixCacheNameWith(SystemConstant.REDIS_PREFIX)
                .entryTtl(Duration.ofSeconds(timeout));
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisTemplate.getConnectionFactory()));
        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }

}

Spring Boot: 2.1.9.RELEASE
Spring Cloud: Greenwich.SR3
Weblogic: 12c(12.2.1.3.0)

重点

MAVEN POM文件

<packaging>war</packaging>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <exclusions>
            <exclusion>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-client</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-core</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jersey.contribs</groupId>
                <artifactId>jersey-apache-client4</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>jsr311-api</artifactId>
        <version>1.1.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
<build>
    <finalName>${project.artifactId}</finalName>
</build>

SpringBootServletInitializer

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(EurekaClientApplication.class);
    }

}

weblogic.xml

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app
        xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
                            http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">
    <context-root>/client</context-root>
    <container-descriptor>
        <prefer-application-packages>
            <package-name>net.minidev.json.*</package-name>
            <package-name>com.jayway.*</package-name>
            <package-name>org.slf4j.*</package-name>
            <package-name>com.sun.jersey.*</package-name>
            <package-name>org.springframework.*</package-name>
            <package-name>aj.org.objectweb.*</package-name>
            <package-name>antlr.*</package-name>
            <package-name>antlr.ASdebug.*</package-name>
            <package-name>antlr.actions.cpp.*</package-name>
            <package-name>antlr.actions.csharp.*</package-name>
            <package-name>antlr.actions.java.*</package-name>
            <package-name>antlr.actions.python.*</package-name>
            <package-name>antlr.build.*</package-name>
            <package-name>antlr.collections.*</package-name>
            <package-name>antlr.collections.impl.*</package-name>
            <package-name>antlr.debug.*</package-name>
            <package-name>antlr.debug.misc.*</package-name>
            <package-name>antlr.preprocessor.*</package-name>
            <package-name>com.ctc.wstx.*</package-name>
            <package-name>com.fasterxml.classmate.*</package-name>
            <package-name>com.fasterxml.jackson.*</package-name>
            <package-name>com.google.common.*</package-name>
            <package-name>com.google.thirdparty.*</package-name>
            <package-name>com.sun.research.*</package-name>
            <package-name>com.sun.ws.*</package-name>
            <package-name>javax.annotation.*</package-name>
            <package-name>javax.annotation.security.*</package-name>
            <package-name>javax.annotation.sql.*</package-name>
            <package-name>javax.inject.*</package-name>
            <package-name>javax.validation.*</package-name>
            <package-name>javax.validation.bootstrap.*</package-name>
            <package-name>javax.validation.constraints.*</package-name>
            <package-name>javax.validation.constraintvalidation.*</package-name>
            <package-name>javax.validation.executable.*</package-name>
            <package-name>javax.validation.groups.*</package-name>
            <package-name>javax.validation.metadata.*</package-name>
            <package-name>javax.validation.spi.*</package-name>
<!--            <package-name>javax.ws.rs.*</package-name>-->
            <package-name>jersey.repackaged.org.*</package-name>
            <package-name>org.antlr.runtime.*</package-name>
            <package-name>org.aopalliance.aop.*</package-name>
            <package-name>org.aopalliance.intercept.*</package-name>
            <package-name>org.apache.commons.*</package-name>
            <package-name>org.bouncycastle.*</package-name>
            <package-name>org.bouncycastle.asn1.*</package-name>
            <package-name>org.bouncycastle.cert.*</package-name>
            <package-name>org.bouncycastle.cms.*</package-name>
            <package-name>org.bouncycastle.crypto.*</package-name>
            <package-name>org.bouncycastle.dvcs.*</package-name>
            <package-name>org.bouncycastle.eac.*</package-name>
            <package-name>org.bouncycastle.i18n.*</package-name>
            <package-name>org.bouncycastle.jcajce.*</package-name>
            <package-name>org.bouncycastle.jce.*</package-name>
            <package-name>org.bouncycastle.math.*</package-name>
            <package-name>org.bouncycastle.mozilla.*</package-name>
            <package-name>org.bouncycastle.openssl.*</package-name>
            <package-name>org.bouncycastle.operator.*</package-name>
            <package-name>org.bouncycastle.pkcs.*</package-name>
            <package-name>org.bouncycastle.pkix.*</package-name>
            <package-name>org.bouncycastle.pqc.*</package-name>
            <package-name>org.bouncycastle.tsp.*</package-name>
            <package-name>org.bouncycastle.util.*</package-name>
            <package-name>org.bouncycastle.voms.*</package-name>
            <package-name>org.bouncycastle.x509.*</package-name>
            <package-name>org.codehaus.jettison.*</package-name>
            <package-name>org.codehaus.stax2.*</package-name>
            <package-name>org.hibernate.validator.*</package-name>
            <package-name>org.jboss.logging.*</package-name>
            <package-name>org.joda.time.*</package-name>
        </prefer-application-packages>
    </container-descriptor>
</weblogic-web-app>

jsr311-api-1.1.1.jar

将jsr311-api-1.1.1.jar放入WebLogic的公共模块目录中,具体位置为:
${WEBLOGIC_HOME}/Middleware/wlserver/modules/

Spring Boot: 2.1.9.RELEASE
Spring Cloud: Greenwich.SR3
Weblogic: 12c(12.2.1.3.0)

重点

MAVEN POM文件

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>jsr311-api</artifactId>
        <version>1.1.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
<build>
    <finalName>${project.artifactId}</finalName>
</build>

SpringBootServletInitializer

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(EurekaserverApplication.class);
    }

}

weblogic.xml

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app
        xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
                            http://xmlns.oracle.com/weblogic/weblogic-web-app/1.9/weblogic-web-app.xsd">
    <context-root>/eureka</context-root>
    <container-descriptor>
        <prefer-application-packages>
            <package-name>org.slf4j.*</package-name>
            <package-name>com.sun.jersey.*</package-name>
            <package-name>org.springframework.*</package-name>
            <package-name>aj.org.objectweb.*</package-name>
            <package-name>antlr.*</package-name>
            <package-name>antlr.ASdebug.*</package-name>
            <package-name>antlr.actions.cpp.*</package-name>
            <package-name>antlr.actions.csharp.*</package-name>
            <package-name>antlr.actions.java.*</package-name>
            <package-name>antlr.actions.python.*</package-name>
            <package-name>antlr.build.*</package-name>
            <package-name>antlr.collections.*</package-name>
            <package-name>antlr.collections.impl.*</package-name>
            <package-name>antlr.debug.*</package-name>
            <package-name>antlr.debug.misc.*</package-name>
            <package-name>antlr.preprocessor.*</package-name>
            <package-name>com.ctc.wstx.*</package-name>
            <package-name>com.fasterxml.classmate.*</package-name>
            <package-name>com.fasterxml.jackson.*</package-name>
            <package-name>com.google.common.*</package-name>
            <package-name>com.google.thirdparty.*</package-name>
            <package-name>com.sun.research.*</package-name>
            <package-name>com.sun.ws.*</package-name>
            <package-name>javax.annotation.*</package-name>
            <package-name>javax.annotation.security.*</package-name>
            <package-name>javax.annotation.sql.*</package-name>
            <package-name>javax.inject.*</package-name>
            <package-name>javax.validation.*</package-name>
            <package-name>javax.validation.bootstrap.*</package-name>
            <package-name>javax.validation.constraints.*</package-name>
            <package-name>javax.validation.constraintvalidation.*</package-name>
            <package-name>javax.validation.executable.*</package-name>
            <package-name>javax.validation.groups.*</package-name>
            <package-name>javax.validation.metadata.*</package-name>
            <package-name>javax.validation.spi.*</package-name>
<!--            <package-name>javax.ws.rs.*</package-name>-->
            <package-name>jersey.repackaged.org.*</package-name>
            <package-name>org.antlr.runtime.*</package-name>
            <package-name>org.aopalliance.aop.*</package-name>
            <package-name>org.aopalliance.intercept.*</package-name>
            <package-name>org.apache.commons.*</package-name>
            <package-name>org.bouncycastle.*</package-name>
            <package-name>org.bouncycastle.asn1.*</package-name>
            <package-name>org.bouncycastle.cert.*</package-name>
            <package-name>org.bouncycastle.cms.*</package-name>
            <package-name>org.bouncycastle.crypto.*</package-name>
            <package-name>org.bouncycastle.dvcs.*</package-name>
            <package-name>org.bouncycastle.eac.*</package-name>
            <package-name>org.bouncycastle.i18n.*</package-name>
            <package-name>org.bouncycastle.jcajce.*</package-name>
            <package-name>org.bouncycastle.jce.*</package-name>
            <package-name>org.bouncycastle.math.*</package-name>
            <package-name>org.bouncycastle.mozilla.*</package-name>
            <package-name>org.bouncycastle.openssl.*</package-name>
            <package-name>org.bouncycastle.operator.*</package-name>
            <package-name>org.bouncycastle.pkcs.*</package-name>
            <package-name>org.bouncycastle.pkix.*</package-name>
            <package-name>org.bouncycastle.pqc.*</package-name>
            <package-name>org.bouncycastle.tsp.*</package-name>
            <package-name>org.bouncycastle.util.*</package-name>
            <package-name>org.bouncycastle.voms.*</package-name>
            <package-name>org.bouncycastle.x509.*</package-name>
            <package-name>org.codehaus.jettison.*</package-name>
            <package-name>org.codehaus.stax2.*</package-name>
            <package-name>org.hibernate.validator.*</package-name>
            <package-name>org.jboss.logging.*</package-name>
            <package-name>org.joda.time.*</package-name>
        </prefer-application-packages>
    </container-descriptor>
</weblogic-web-app>

jsr311-api-1.1.1.jar

将jsr311-api-1.1.1.jar放入WebLogic的公共模块目录中,具体位置为:
${WEBLOGIC_HOME}/Middleware/wlserver/modules/

项目源码

参考文章: https://blog.csdn.net/syau552king/article/details/107840747

多子项目打包
# CORE_NUMBER获取系统逻辑处理器数量
CORE_NUMBER=$(cat /proc/cpuinfo | grep "processor" | wc -l)
# 子项目路径
fullPath=service/base
# -pl 按项目名编译 -am 编译该项目依赖的项目 -DskipTests=true 跳过测试 -T 多线程设置
mvn clean package -pl $fullPath -am -DskipTests=true -T $CORE_NUMBER

最近在出差啊, 就有遇到说甲方机器是内网的, linux这些没法用yum的包管理器在线安装一些软件

解决方案

一. 下载源码编译

这个方法当然这样是最好的啦, 但是我懒, 所以看方法二

二. 用YumDownloader获取离线安装包

1) 安装YumDownloader

找一台centos系统的机器(对应你要离线安装的系统), 可以是服务器,可以是虚拟机,实体机啥的. 而且是要已联网的,并执行命令

# 安装
yum install yum-utils -y
# 建立一个空文件夹
mkdir install_file & cd install_file
2) 使用YumDownloader获取离线安装包

运行下面命令获取, 可以自己替换后面的软件名称, 这里以git做演示

yumDownloader git
3) 打包离线安装包

这是时候你ll一下你的目录就会看到有许多的.rpm文件, 我们可以把它们都打包起来,塞入需要安装的服务器执行安装就可以了

# 打包
zip –q –r install_file.zip *
4) 安装

这时候你把刚刚压缩的文件放到你需要离线安装的服务器里面(并cd到对应目录),解压

unzip install_file.zip

然后执行安装

rpm -ivh *.rpm --force --nodeps