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

事情是这样的, 有这么一个需求: 使用@Cacheable注解, 要求方法正常返回时保存x时间, 非正常返回时保存y时间
然后我就四处找解决方法啊, 什么@Cacheable.unless啊, RedisCacheManager啊, RedisCacheConfiguration啊找了一遍
最后还是用了AOP的方式解决了, 下面是实际代码, 大家可以参考一下
// 实际需要缓存的方法入口, 在方法类不使用@CacheConfig
@Cacheable(key = "#s", cacheNames = "account.getStr")
public String getStr(String s) {
    // ...省略方法具体实现, 这里可能会throw Exception
    return s;
}
这里需要说明为什么不使用@CacheConfig,
因为我懒, 你完全可以把cacheNames参数放到类上面
只是你在AOP的时候就要多操作一下
// redis配置
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    // 缓存的前缀
    private static final String REDIS_PREFIX = "cache:";
    // 默认的缓存有效期时长(秒)
    private static final Long TIME_OUT = 3600L;

    @Autowired
    Environment env;

    /**
     * 设置缓存策略
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public CacheManager cacheManager(StringRedisTemplate redisTemplate) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                // 前缀设置
                .prefixCacheNameWith(REDIS_PREFIX)
                // 有效期
                .entryTtl(Duration.ofSeconds(TIME_OUT));
        RedisCacheWriter redisCacheWriter = 
            RedisCacheWriter.nonLockingRedisCacheWriter(
                Objects.requireNonNull(redisTemplate.getConnectionFactory())
            );
        return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
    }
}
上面的有效期可以使用@Value来设置, 写死完全是因为懒
// 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.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/8/23 8:53
 */
@Slf4j
@Aspect
@Component
public class CacheableHandlerAspect {

    // 错误时的缓存时间
    @Value("${system.cache.exception.timeout}")
    private Long exceptionTimeout;
    @Autowired
    private CacheManager cacheManager;
    @Autowired
    private RedisCacheManager redisCacheManager;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // 用于解析Sl语法
    private final SpelExpressionParser parserSpel = new SpelExpressionParser();
    private final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    @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的相关can'shu
        Cacheable cacheable = getCacheable(point);
        String cacheName = cacheable.cacheNames()[0];
        String key = getValueByKey(cacheable.key(), point);
        
        try {
            // 程序直接执行
            return point.proceed();
        } catch (Exception e) {
            // 如果出错就进行报错的保存
            saveCache(e, key, cacheName);
            throw e;
        }
    }

    private void handlerException(Object key, String cacheName) {
        Object o = 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;
        }
    }

    private void saveCache(Object o, Object key, String cacheName) {
        // 获取指定命名空间的cache
        Cache cache = cacheManager.getCache(cacheName);
        // 为空就不操作, 程序设置有问题
        if (cache == null) {
            log.debug("------ 获取缓存: {} 失败", cacheName);
            return;
        }
        // 加入缓存
        cache.put(key, o);
        try {
            // 获取redis的配置
            log.debug("------ 准备获取RedisCacheConfiguration");
            RedisCacheConfiguration configuration = redisCacheManager.getCacheConfigurations().get(cacheName);
            log.debug("------ 准备拼接缓存key");
            String redisKey = configuration.getKeyPrefixFor(cacheName).concat(key.toString());
            log.debug("------ 拼接成功, 缓存key: {}, 准备设置reis有效时间: {}秒", redisKey, exceptionTimeout);
            stringRedisTemplate.expire(redisKey, exceptionTimeout, TimeUnit.SECONDS);
            log.debug("------ 设置失败时的缓存时间");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("获取RedisCacheConfiguration失败", e);
        }
    }

    /**
      * 获取方法上的 @Cacheable
      *
      * @param point
      * @return
      */
     private 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
     */
    private String getValueByKey(String key, ProceedingJoinPoint pjp) {
        Expression expression = parserSpel.parseExpression(key);
        EvaluationContext context = new StandardEvaluationContext();
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        Object[] args = pjp.getArgs();
        String[] paramNames = parameterNameDiscoverer.getParameterNames(methodSignature.getMethod());
        for (int i = 0; i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        return expression.getValue(context).toString();
    }

}

面向百度变成老是告诉我用ResourceUtils.getFile(), 打成jar包就会报错
用下面的就可以了

// 需要Apache Common包
// 文件夹初始
public static final String BASE_PATH = "db/";
// 对应文件转String
public static String getString(String name) {
    ClassPathResource c = new ClassPathResource(BASE_PATH.concat(name));
    InputStream i = c.getInputStream();
    return IOUtils.toString(i, CHAR);
}