LiTaohong 7 years ago
parent
commit
db2c49af4d
22 changed files with 1605 additions and 29 deletions
  1. 7 2
      base/common-cache/pom.xml
  2. 0 4
      base/common-cache/src/main/java/com/yihu/base/cache/adapter/CacheAdapter.java
  3. 67 0
      base/common-cache/src/main/java/com/yihu/base/cache/cache/CustomMapCache.java
  4. 153 0
      base/common-cache/src/main/java/com/yihu/base/cache/cache/CustomRedisCache.java
  5. 17 0
      base/common-cache/src/main/java/com/yihu/base/cache/config/CacheKeyGenerator.java
  6. 315 0
      base/common-cache/src/main/java/com/yihu/base/cache/lock/CacheLock.java
  7. 29 0
      base/common-cache/src/main/java/com/yihu/base/cache/manager/CacheManagerFactory.java
  8. 0 20
      base/common-cache/src/main/java/com/yihu/base/cache/manager/CommonCacheManager.java
  9. 25 0
      base/common-cache/src/main/java/com/yihu/base/cache/manager/CustomCacheManager.java
  10. 113 0
      base/common-cache/src/main/java/com/yihu/base/cache/manager/CustomMapCacheManager.java
  11. 181 0
      base/common-cache/src/main/java/com/yihu/base/cache/manager/CustomRedisCacheManager.java
  12. 75 0
      base/common-cache/src/main/java/com/yihu/base/cache/support/CacheInvocation.java
  13. 33 0
      base/common-cache/src/main/java/com/yihu/base/cache/support/CacheSupport.java
  14. 111 0
      base/common-cache/src/main/java/com/yihu/base/cache/support/CacheSupportImpl.java
  15. 83 0
      base/common-cache/src/main/java/com/yihu/base/cache/support/CachingAnnoationAspect.java
  16. 51 0
      base/common-cache/src/main/java/com/yihu/base/cache/support/MapCacheSupportImpl.java
  17. 63 0
      base/common-cache/src/main/java/com/yihu/base/cache/support/RedisCacheSupportImpl.java
  18. 34 0
      base/common-cache/src/main/java/com/yihu/base/cache/util/RedisTemplateUtils.java
  19. 145 0
      base/common-cache/src/main/java/com/yihu/base/cache/util/ReflectionUtils.java
  20. 68 0
      base/common-cache/src/main/java/com/yihu/base/cache/util/SpringContextUtils.java
  21. 32 0
      base/common-cache/src/main/java/com/yihu/base/cache/util/ThreadTaskUtils.java
  22. 3 3
      svr/svr-base/src/main/java/com/yihu/jw/business/user/contorller/EmployController.java

+ 7 - 2
base/common-cache/pom.xml

@ -10,8 +10,8 @@
        <relativePath>../../common-lib-parent-pom/pom.xml</relativePath>
    </parent>
    <groupId>common-cache</groupId>
    <artifactId>common-cache</artifactId>
    <groupId>common-customCache</groupId>
    <artifactId>common-customCache</artifactId>
    <version>1.0.0</version>
    <dependencies>
@ -19,6 +19,11 @@
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.10</version>
        </dependency>
    </dependencies>
    
</project>

+ 0 - 4
base/common-cache/src/main/java/com/yihu/base/cache/adapter/CacheAdapter.java

@ -1,4 +0,0 @@
package com.yihu.base.cache.adapter;
public class CacheAdapter {
}

+ 67 - 0
base/common-cache/src/main/java/com/yihu/base/cache/cache/CustomMapCache.java

@ -0,0 +1,67 @@
package com.yihu.base.cache.cache;
import com.yihu.base.cache.config.CacheKeyGenerator;
import com.yihu.base.cache.lock.CacheLock;
import com.yihu.base.cache.util.ThreadTaskUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.cache.RedisCacheElement;
import org.springframework.data.redis.cache.RedisCacheKey;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
public class CustomMapCache extends ConcurrentMapCache{
    @Value("expire-time")
    private Long expireTime;
    @Value("refresh-time")
    private Long refreshTime;
    public CustomMapCache(String name) {
        super(name);
    }
    public Long getExpireTime() {
        return expireTime;
    }
    public Long getRefreshTime() {
        return refreshTime;
    }
    public CustomMapCache(String name,Long expireTime, Long refreshTime){
        super(name);
        this.expireTime = expireTime;
        this.refreshTime = refreshTime;
    }
    /**
     * 重写get方法,获取到缓存后再次取缓存剩余的时间,如果时间小余我们配置的刷新时间就手动刷新缓存。
     * 为了不影响get的性能,启用后台线程去完成缓存的刷。
     * 并且只放一个线程去刷新数据。
     *
     * @param key
     * @return
     */
    @Override
    public ValueWrapper get(Object key) {
        ValueWrapper valueWrapper = this.get(key);
        if (null != valueWrapper) {
            // 刷新缓存数据
        }
        return valueWrapper;
    }
}

+ 153 - 0
base/common-cache/src/main/java/com/yihu/base/cache/cache/CustomRedisCache.java

@ -0,0 +1,153 @@
package com.yihu.base.cache.cache;
import com.yihu.base.cache.config.CacheKeyGenerator;
import com.yihu.base.cache.support.CacheSupport;
import com.yihu.base.cache.lock.CacheLock;
import com.yihu.base.cache.util.SpringContextUtils;
import com.yihu.base.cache.util.ThreadTaskUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheElement;
import org.springframework.data.redis.cache.RedisCacheKey;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;
public class CustomRedisCache extends RedisCache{
    @Value("expire-time")
    private Long expireTime;
    @Value("refresh-time")
    private Long refreshTime;
    private RedisOperations redisOperations;
    private CacheSupport getCacheSupport() {
        return SpringContextUtils.getBean(CacheSupport.class);
    }
    private byte[] prefix;
    public CustomRedisCache(String name, byte[] prefix, RedisOperations<?, ?> redisOperations, long expiration) {
        super(name, prefix, redisOperations, expiration);
    }
    public CustomRedisCache(String name, byte[] prefix, RedisOperations<? extends Object, ? extends Object> redisOperations, long expiration, long refreshTime) {
        super(name, prefix, redisOperations, expiration);
        this.redisOperations = redisOperations;
        this.refreshTime = refreshTime;
        this.prefix = prefix;
    }
    public CustomRedisCache(String name, byte[] prefix, RedisOperations<? extends Object, ? extends Object> redisOperations, long expiration, long refreshTime, boolean allowNullValues) {
        super(name, prefix, redisOperations, expiration, allowNullValues);
        this.redisOperations = redisOperations;
        this.refreshTime = refreshTime;
        this.prefix = prefix;
    }
    /**
     * 重写get方法,获取到缓存后再次取缓存剩余的时间,如果时间小余我们配置的刷新时间就手动刷新缓存。
     * 为了不影响get的性能,启用后台线程去完成缓存的刷。
     * 并且只放一个线程去刷新数据。
     *
     * @param key
     * @return
     */
    @Override
    public ValueWrapper get(final Object key) {
        String cacheKey = CacheKeyGenerator.getCacheKey();
        ValueWrapper valueWrapper = this.get(cacheKey);
        if (null != valueWrapper) {
            // 刷新缓存数据
            refreshCache(key, cacheKey);
        }
        return valueWrapper;
    }
    /**
     * 重写父类的get函数。
     * 父类的get方法,是先使用exists判断key是否存在,不存在返回null,存在再到redis缓存中去取值。这样会导致并发问题,
     * 假如有一个请求调用了exists函数判断key存在,但是在下一时刻这个缓存过期了,或者被删掉了。
     * 这时候再去缓存中获取值的时候返回的就是null了。
     * 可以先获取缓存的值,再去判断key是否存在。
     *
     * @param cacheKey
     * @return
     */
    @Override
    public RedisCacheElement get(final RedisCacheKey cacheKey) {
        Assert.notNull(cacheKey, "CacheKey must not be null!");
        // 根据key获取缓存值
        RedisCacheElement redisCacheElement = new RedisCacheElement(cacheKey, fromStoreValue(lookup(cacheKey)));
        // 判断key是否存在
        Boolean exists = (Boolean) redisOperations.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.exists(cacheKey.getKeyBytes());
            }
        });
        if (!exists.booleanValue()) {
            return null;
        }
        return redisCacheElement;
    }
    /**
     * 刷新缓存数据
     */
    private void refreshCache(Object key, String cacheKeyStr) {
        Long ttl = this.redisOperations.getExpire(cacheKeyStr);
        if (null != ttl && ttl <= CustomRedisCache.this.refreshTime) {
            // 尽量少的去开启线程,因为线程池是有限的
            ThreadTaskUtils.run(new Runnable() {
                @Override
                public void run() {
                    // 加一个分布式锁,只放一个请求去刷新缓存
                    CacheLock cacheLock = new CacheLock((RedisTemplate) redisOperations, cacheKeyStr + "_lock");
                    try {
                        if (cacheLock.lock()) {
                            // 获取锁之后再判断一下过期时间,看是否需要加载数据
                            Long ttl = CustomRedisCache.this.redisOperations.getExpire(cacheKeyStr);
                            if (null != ttl && ttl <= CustomRedisCache.this.refreshTime) {
                                // 通过获取代理方法信息重新加载缓存数据
                                CustomRedisCache.this.getCacheSupport().refreshCacheByKey(CustomRedisCache.super.getName(), key.toString());
                            }
                        }
                    } catch (Exception e) {
                    } finally {
                        cacheLock.unlock();
                    }
                }
            });
        }
    }
    public Long getExpireTime() {
        return expireTime;
    }
    public Long getRefreshTime() {
        return refreshTime;
    }
    public void setExpireTime(Long expireTime) {
        this.expireTime = expireTime;
    }
    public void setRefreshTime(Long refreshTime) {
        this.refreshTime = refreshTime;
    }
}

+ 17 - 0
base/common-cache/src/main/java/com/yihu/base/cache/config/CacheKeyGenerator.java

@ -1,4 +1,21 @@
package com.yihu.base.cache.config;
/**
 * 生成缓存的key
 */
public class CacheKeyGenerator {
    private static String cacheKey;
    public static void setCacheKey(String moduleName,String saasId,String bussinessModuleName) {
        StringBuilder str = new StringBuilder();
        str.append(moduleName + "-");
        str.append(saasId + "-");
        str.append(bussinessModuleName);
        cacheKey = str.toString();
    }
    public static String getCacheKey(){
        return cacheKey;
    }
}

+ 315 - 0
base/common-cache/src/main/java/com/yihu/base/cache/lock/CacheLock.java

@ -0,0 +1,315 @@
package com.yihu.base.cache.lock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisCommands;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
/**
 * 缓存锁
 */
public class CacheLock {
    private static Logger logger = LoggerFactory.getLogger(CacheLock.class);
    private RedisTemplate redisTemplate;
    /**
     * 将key 的值设为value ,当且仅当key 不存在,等效于 SETNX。
     */
    public static final String NX = "NX";
    /**
     * seconds — 以秒为单位设置 key 的过期时间,等效于EXPIRE key seconds
     */
    public static final String EX = "EX";
    /**
     * 调用set后的返回值
     */
    public static final String OK = "OK";
    /**
     * 默认请求锁的超时时间(ms 毫秒)
     */
    private static final long TIME_OUT = 100;
    /**
     * 默认锁的有效时间(s)
     */
    public static final int EXPIRE = 60;
    /**
     * 解锁的lua脚本
     */
    public static final String UNLOCK_LUA;
    static {
        StringBuilder sb = new StringBuilder();
        sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
        sb.append("then ");
        sb.append("    return redis.call(\"del\",KEYS[1]) ");
        sb.append("else ");
        sb.append("    return 0 ");
        sb.append("end ");
        UNLOCK_LUA = sb.toString();
    }
    /**
     * 锁标志对应的key
     */
    private String lockKey;
    /**
     * 记录到日志的锁标志对应的key
     */
    private String lockKeyLog = "";
    /**
     * 锁对应的值
     */
    private String lockValue;
    /**
     * 锁的有效时间(s)
     */
    private int expireTime = EXPIRE;
    /**
     * 请求锁的超时时间(ms)
     */
    private long timeOut = TIME_OUT;
    /**
     * 锁标记
     */
    private volatile boolean locked = false;
    final Random random = new Random();
    /**
     * 使用默认的锁过期时间和请求锁的超时时间
     *
     * @param redisTemplate
     * @param lockKey       锁的key(Redis的Key)
     */
    public CacheLock(RedisTemplate redisTemplate, String lockKey) {
        this.redisTemplate = redisTemplate;
        this.lockKey = lockKey + "_lock";
    }
    /**
     * 使用默认的请求锁的超时时间,指定锁的过期时间
     *
     * @param redisTemplate
     * @param lockKey       锁的key(Redis的Key)
     * @param expireTime    锁的过期时间(单位:秒)
     */
    public CacheLock(RedisTemplate redisTemplate, String lockKey, int expireTime) {
        this(redisTemplate, lockKey);
        this.expireTime = expireTime;
    }
    /**
     * 使用默认的锁的过期时间,指定请求锁的超时时间
     *
     * @param redisTemplate
     * @param lockKey       锁的key(Redis的Key)
     * @param timeOut       请求锁的超时时间(单位:毫秒)
     */
    public CacheLock(RedisTemplate redisTemplate, String lockKey, long timeOut) {
        this(redisTemplate, lockKey);
        this.timeOut = timeOut;
    }
    /**
     * 锁的过期时间和请求锁的超时时间都是用指定的值
     *
     * @param redisTemplate
     * @param lockKey       锁的key(Redis的Key)
     * @param expireTime    锁的过期时间(单位:秒)
     * @param timeOut       请求锁的超时时间(单位:毫秒)
     */
    public CacheLock(RedisTemplate redisTemplate, String lockKey, int expireTime, long timeOut) {
        this(redisTemplate, lockKey, expireTime);
        this.timeOut = timeOut;
    }
    /**
     * 尝试获取锁 超时返回
     *
     * @return
     */
    public boolean tryLock() {
        // 生成随机key
        lockValue = UUID.randomUUID().toString();
        // 请求锁超时时间,纳秒
        long timeout = timeOut * 1000000;
        // 系统当前时间,纳秒
        long nowTime = System.nanoTime();
        while ((System.nanoTime() - nowTime) < timeout) {
            if (OK.equalsIgnoreCase(this.set(lockKey, lockValue, expireTime))) {
                locked = true;
                // 上锁成功结束请求
                return locked;
            }
            // 每次请求等待一段时间
            seleep(10, 50000);
        }
        return locked;
    }
    /**
     * 尝试获取锁 立即返回
     *
     * @return 是否成功获得锁
     */
    public boolean lock() {
        lockValue = UUID.randomUUID().toString();
        //不存在则添加 且设置过期时间(单位ms)
        String result = set(lockKey, lockValue, expireTime);
        locked = OK.equalsIgnoreCase(result);
        return locked;
    }
    /**
     * 以阻塞方式的获取锁
     *
     * @return 是否成功获得锁
     */
    public boolean lockBlock() {
        lockValue = UUID.randomUUID().toString();
        while (true) {
            //不存在则添加 且设置过期时间(单位ms)
            String result = set(lockKey, lockValue, expireTime);
            if (OK.equalsIgnoreCase(result)) {
                locked = true;
                return locked;
            }
            // 每次请求等待一段时间
            seleep(10, 50000);
        }
    }
    /**
     * 解锁
     * 不使用固定的字符串作为键的值,而是设置一个不可猜测(non-guessable)的长随机字符串,作为口令串(token)。
     * 不使用 DEL 命令来释放锁,而是发送一个 Lua 脚本,这个脚本只在客户端传入的值和键的口令串相匹配时,才对键进行删除。
     * 这两个改动可以防止持有过期锁的客户端误删现有锁的情况出现。
     */
    public Boolean unlock() {
        // 只有加锁成功并且锁还有效才去释放锁
        if (locked) {
            return (Boolean) redisTemplate.execute(new RedisCallback<Boolean>() {
                @Override
                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                    Object nativeConnection = connection.getNativeConnection();
                    Long result = 0L;
                    List<String> keys = new ArrayList<>();
                    keys.add(lockKey);
                    List<String> values = new ArrayList<>();
                    values.add(lockValue);
                    // 集群模式
                    if (nativeConnection instanceof JedisCluster) {
                        result = (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, values);
                    }
                    // 单机模式
                    if (nativeConnection instanceof Jedis) {
                        result = (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, values);
                    }
                    if (result == 0 && !StringUtils.isEmpty(lockKeyLog)) {
                        logger.info("Redis分布式锁,解锁{}失败!解锁时间:{}", lockKeyLog, System.currentTimeMillis());
                    }
                    locked = result == 0;
                    return result == 1;
                }
            });
        }
        return true;
    }
    /**
     * @param key     锁的Key
     * @param value   锁里面的值
     * @param seconds 过去时间(秒)
     * @return
     */
    private String set(final String key, final String value, final long seconds) {
        Assert.isTrue(!StringUtils.isEmpty(key), "key不能为空");
        return (String) redisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                Object nativeConnection = connection.getNativeConnection();
                String result = null;
                if (nativeConnection instanceof JedisCommands) {
                    result = ((JedisCommands) nativeConnection).set(key, value, NX, EX, seconds);
                }
                if (!StringUtils.isEmpty(lockKeyLog) && !StringUtils.isEmpty(result)) {
                    logger.info("获取锁{}的时间:{}", lockKeyLog, System.currentTimeMillis());
                }
                return result;
            }
        });
    }
    /**
     * @param millis 毫秒
     * @param nanos  纳秒
     * @Title: seleep
     * @Description: 线程等待时间
     * @author yuhao.wang
     */
    private void seleep(long millis, int nanos) {
        try {
            Thread.sleep(millis, random.nextInt(nanos));
        } catch (InterruptedException e) {
            logger.info("获取分布式锁休眠被中断:", e);
        }
    }
    public String getLockKeyLog() {
        return lockKeyLog;
    }
    public void setLockKeyLog(String lockKeyLog) {
        this.lockKeyLog = lockKeyLog;
    }
    public int getExpireTime() {
        return expireTime;
    }
    public void setExpireTime(int expireTime) {
        this.expireTime = expireTime;
    }
    public long getTimeOut() {
        return timeOut;
    }
    public void setTimeOut(long timeOut) {
        this.timeOut = timeOut;
    }
}

+ 29 - 0
base/common-cache/src/main/java/com/yihu/base/cache/manager/CacheManagerFactory.java

@ -0,0 +1,29 @@
package com.yihu.base.cache.manager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
public class CacheManagerFactory {
    @Value("cache")
    private String caceType;
    public CacheManager getCacheManager(){
        CacheManager cacheManager = null;
        if(StringUtils.isEmpty(caceType)){
            return cacheManager;
        }
        switch (Integer.parseInt(caceType)){
            case 1:
                cacheManager = new CustomMapCacheManager();
                break;
            case 2:
                cacheManager = new CustomRedisCacheManager(new RedisTemplate());
                break;
        }
        return cacheManager;
    }
}

+ 0 - 20
base/common-cache/src/main/java/com/yihu/base/cache/manager/CommonCacheManager.java

@ -1,20 +0,0 @@
package com.yihu.base.cache.manager;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import java.util.Collection;
@EnableCaching
public class CommonCacheManager implements CacheManager{
    @Override
    public Cache getCache(String s) {
        return null;
    }
    @Override
    public Collection<String> getCacheNames() {
        return null;
    }
}

+ 25 - 0
base/common-cache/src/main/java/com/yihu/base/cache/manager/CustomCacheManager.java

@ -0,0 +1,25 @@
package com.yihu.base.cache.manager;
import org.springframework.cache.CacheManager;
public interface CustomCacheManager extends CacheManager{
    /**
     * 注解分隔符
     */
    String SEPARATOR = "#";
    /**
     * SpEL标示符
     */
     String MARK = "$";
    Long getExpireTime();
    Long getRefreshTime();
    Long getExpireTime(String cacheName,String[] cacheParams);
    Long getAutoRefreshTime(String[] cacheParams);
}

+ 113 - 0
base/common-cache/src/main/java/com/yihu/base/cache/manager/CustomMapCacheManager.java

@ -0,0 +1,113 @@
package com.yihu.base.cache.manager;
import com.yihu.base.cache.cache.CustomMapCache;
import com.yihu.base.cache.cache.CustomRedisCache;
import com.yihu.base.cache.util.ReflectionUtils;
import com.yihu.base.cache.util.SpringContextUtils;
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.concurrent.ConcurrentMapCacheManager;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class CustomMapCacheManager extends ConcurrentMapCacheManager implements CustomCacheManager{
    @Value("expire-time")
    private Long expireTime;
    @Value("refresh-time")
    private Long refreshTime;
    @Autowired
    private ConcurrentMapCacheManager concurrentMapCacheManager;
    private static final String SUPER_CACHEMAP = "cacheMap";
    public ConcurrentMapCacheManager getInstance(){
        if(null == concurrentMapCacheManager){
            concurrentMapCacheManager = SpringContextUtils.getBean(ConcurrentMapCacheManager.class);
        }
        return concurrentMapCacheManager;
    }
    @Override
    public Long getExpireTime() {
        return null;
    }
    @Override
    public Long getRefreshTime() {
        return null;
    }
    @Override
    public Long getExpireTime(String cacheName, String[] cacheParams) {
        if(cacheParams.length > 1){
            this.expireTime = Long.parseLong(cacheParams[1]);
        }
        return expireTime;
    }
    @Override
    public Long getAutoRefreshTime(String[] cacheParams) {
        if(cacheParams.length > 2){
            this.refreshTime = Long.parseLong(cacheParams[2]);
        }
        return refreshTime;
    }
    @Override
    public Cache getCache(String name){
        String[] cacheParams = name.split(CustomCacheManager.SEPARATOR);
        String cacheName = cacheParams[0];
        if(StringUtils.isEmpty(cacheName)){
            return null;
        }
        //注解里面的过期时间覆盖默认的过期时间
        long expireTime = getExpireTime(name,cacheParams);
        //注解里面的刷新时间
        long refreshTime = getAutoRefreshTime(cacheParams);
        Object obj =  ReflectionUtils.getFieldValue(getInstance(),SUPER_CACHEMAP);
        if(null != obj && obj instanceof ConcurrentHashMap){
            ConcurrentHashMap<String,Cache> cacheMap = (ConcurrentHashMap<String,Cache>)obj;
            return getCache(name,expireTime,refreshTime,cacheMap);
        }else{
            return super.getCache(name);
        }
    }
    /**
     * @param cacheName
     * @param expireTime
     * @param refreshTime
     * @param cacheMap
     * @return
     */
    public Cache getCache(String cacheName, long expireTime, long refreshTime, ConcurrentHashMap<String,Cache> cacheMap){
        Cache cache = cacheMap.get(cacheName);
        if(null != cache){
            return cache;
        }else {
            synchronized (cacheMap){
                cache = cacheMap.get(cacheName);
                if(null == cache){
                    cache = createConcurrentMapCache(cacheName,expireTime,refreshTime);
                }
            }
        }
        return cache;
    }
    public CustomMapCache createConcurrentMapCache(String cacheName, long expirationTime, long refreshTime) {
        return new CustomMapCache(cacheName,expirationTime,refreshTime);
    }
}

+ 181 - 0
base/common-cache/src/main/java/com/yihu/base/cache/manager/CustomRedisCacheManager.java

@ -0,0 +1,181 @@
package com.yihu.base.cache.manager;
import com.yihu.base.cache.util.ReflectionUtils;
import com.yihu.base.cache.util.SpringContextUtils;
import com.yihu.base.cache.cache.CustomRedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.StringUtils;
import java.util.concurrent.ConcurrentHashMap;
public class CustomRedisCacheManager extends RedisCacheManager implements CustomCacheManager{
    private RedisCacheManager redisCacheManager = null;
    @Autowired
    private DefaultListableBeanFactory beanFactory;
    private static final String SUPER_CACHEMAP = "cacheMap";
    private static final String SUPER_DYNAMIC = "dynamic";
    /**
     * 父类cacheNullValues字段
     */
    private static final String SUPER_CACHENULLVALUES = "cacheNullValues";
    /**
     * 父类updateCacheNames方法
     */
    private static final String SUPER_METHOD_UPDATECACHENAMES = "updateCacheNames";
    @Value("expire-time")
    private Long expireTime;
    @Value("refresh-time")
    private Long refreshTime;
    @Override
    public Long getExpireTime() {
        return expireTime;
    }
    @Override
    public Long getRefreshTime() {
        return refreshTime;
    }
    public void setExpireTime(Long expireTime) {
        this.expireTime = expireTime;
    }
    public void setRefreshTime(Long refreshTime) {
        this.refreshTime = refreshTime;
    }
    public CustomRedisCacheManager(RedisOperations redisOperations) {
        super(redisOperations);
    }
    public RedisCacheManager getInstance(){
        if(null == redisCacheManager){
            redisCacheManager = SpringContextUtils.getBean(RedisCacheManager.class);
        }
        return redisCacheManager;
    }
    @Override
    public Cache getCache(String name){
        String[] cacheParams = name.split(CustomCacheManager.SEPARATOR);
        String cacheName = cacheParams[0];
        if(StringUtils.isEmpty(cacheName)){
            return null;
        }
        //注解里面的过期时间覆盖默认的过期时间
        long expireTime = getExpireTime(name,cacheParams);
        //注解里面的刷新时间
        long refreshTime = getAutoRefreshTime(cacheParams);
        Object obj =  ReflectionUtils.getFieldValue(getInstance(),SUPER_CACHEMAP);
        if(null != obj && obj instanceof ConcurrentHashMap){
            ConcurrentHashMap<String,Cache> cacheMap = (ConcurrentHashMap<String,Cache>)obj;
            return getCache(name,expireTime,refreshTime,cacheMap);
        }else{
            return super.getCache(name);
        }
    }
    /**
     * @param cacheName
     * @param expireTime
     * @param refreshTime
     * @param cacheMap
     * @return
     */
    public Cache getCache(String cacheName, long expireTime, long refreshTime, ConcurrentHashMap<String,Cache> cacheMap){
        Cache cache = cacheMap.get(cacheName);
        if(null != cache){
            return cache;
        }else {
            synchronized (cacheMap){
                cache = cacheMap.get(cacheName);
                if(null == cache){
                    cache = getMissingCache(cacheName,expireTime,refreshTime);
                    if(null != cache){
                        cache = decorateCache(cache);
                        cacheMap.put(cacheName,cache);
                        Class<?>[] parameterTypes = {String.class};
                        Object[] paramters = {cacheName};
                        ReflectionUtils.invokeMethod(getInstance(),SUPER_METHOD_UPDATECACHENAMES,parameterTypes,paramters);
                    }
                }
            }
        }
        return cache;
    }
    public CustomRedisCache getMissingCache(String cacheName, long expirationSecondTime, long preloadSecondTime) {
        Boolean dynamic = (Boolean) ReflectionUtils.getFieldValue(getInstance(),SUPER_DYNAMIC);
        Boolean cacheNullValues = (Boolean) ReflectionUtils.getFieldValue(getInstance(), SUPER_CACHENULLVALUES);
        return dynamic ? new CustomRedisCache(cacheName, (this.isUsePrefix() ? this.getCachePrefix().prefix(cacheName) : null),
                this.getRedisOperations(), expirationSecondTime, preloadSecondTime, cacheNullValues) : null;
    }
    /**
     * 获取过期时间
     * @return
     */
    @Override
    public Long getExpireTime(String cacheName, String[] cacheParams) {
        // 有效时间,初始化获取默认的有效时间
        Long expirationSecondTime = this.computeExpiration(cacheName);
        // 设置key有效时间
        if (cacheParams.length > 1) {
            String expirationStr = cacheParams[1];
            if (!StringUtils.isEmpty(expirationStr)) {
                // 支持配置过期时间使用EL表达式读取配置文件时间
                if (expirationStr.contains(MARK)) {
                    expirationStr = beanFactory.resolveEmbeddedValue(expirationStr);
                }
                expirationSecondTime = Long.parseLong(expirationStr);
            }
        }
        return expirationSecondTime;
    }
    /**
     * 获取自动刷新时间
     * @return
     */
    @Override
    public Long getAutoRefreshTime(String[] cacheParams) {
        // 自动刷新时间,默认是0
        Long refreshTime = 0L;
        // 设置自动刷新时间
        if (cacheParams.length > 2) {
            String preloadStr = cacheParams[2];
            if (!StringUtils.isEmpty(preloadStr)) {
                // 支持配置刷新时间使用EL表达式读取配置文件时间
                if (preloadStr.contains(MARK)) {
                    preloadStr = beanFactory.resolveEmbeddedValue(preloadStr);
                }
                refreshTime = Long.parseLong(preloadStr);
            }
        }
        return refreshTime;
    }
}

+ 75 - 0
base/common-cache/src/main/java/com/yihu/base/cache/support/CacheInvocation.java

@ -0,0 +1,75 @@
package com.yihu.base.cache.support;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class CacheInvocation {
    private Object key;
    private Object targetBean;
    private Method targetMethod;
    private Object[] arguments;
    private List<String> parameterTypes = new ArrayList<>();
    public CacheInvocation(Object key,Object targetBean,Method targetMethod,Object[] arguments,Class[] parameterTypes){
        this.key = key;
        this.targetBean = targetBean;
        this.targetMethod = targetMethod;
        if(null != arguments && arguments.length > 0){
            this.arguments = Arrays.copyOf(arguments,arguments.length);
        }
        if(null != parameterTypes && parameterTypes.length > 0){
            for( Class cls:parameterTypes){
                this.parameterTypes.add(cls.getName());
            }
        }
    }
    /**
     * 重写equals方法
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj){
        if(obj == this){
            return true;
        }
        if(null == obj || obj.getClass() != getClass()){
            return false;
        }
        CacheInvocation cacheInvocation = (CacheInvocation)obj;
        return key.equals(cacheInvocation.key);
    }
    /**
     * 重写hashCode方法
     * @return
     */
    @Override
    public int hashCode(){
        return key.hashCode();
    }
    public Object getKey() {
        return key;
    }
    public Object getTargetBean() {
        return targetBean;
    }
    public Method getTargetMethod() {
        return targetMethod;
    }
    public Object[] getArguments() {
        return arguments;
    }
}

+ 33 - 0
base/common-cache/src/main/java/com/yihu/base/cache/support/CacheSupport.java

@ -0,0 +1,33 @@
package com.yihu.base.cache.support;
import java.lang.reflect.Method;
import java.util.Set;
/**
 * 注册和刷新缓存接口
 */
public interface CacheSupport {
    String SPERATOR = "#";
    /**
     * 注册缓存方法信息
     *
     * @param invokedBean          代理Bean
     * @param invokedMethod        代理方法名称
     * @param invocationParamTypes 代理方法参数类型
     * @param invocationArgs       代理方法参数
     * @param annoationCacheNames           缓存名称(@Cacheable注解的value)
     * @param cacheKey             缓存key(@Cacheable注解的key)
     */
    void registerInvocation(Object invokedBean, Method invokedMethod, Class[] invocationParamTypes, Object[] invocationArgs, Set<String> annoationCacheNames, String cacheKey);
    /**
     * 按容器以及指定键更新缓存
     *
     * @param cacheName
     * @param cacheKey
     */
    void refreshCacheByKey(String cacheName, String cacheKey);
}

+ 111 - 0
base/common-cache/src/main/java/com/yihu/base/cache/support/CacheSupportImpl.java

@ -0,0 +1,111 @@
package com.yihu.base.cache.support;
import com.yihu.base.cache.manager.CacheManagerFactory;
import com.yihu.base.cache.manager.CustomCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MethodInvoker;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class CacheSupportImpl implements CacheSupport {
    // 记录缓存执行方法信息的容器。
    public Map<String,Set<CacheInvocation>> cacheInvocationMap = new ConcurrentHashMap<>();
    @Autowired
    private CustomCacheManager customCacheManager;
    /**
     * 根据name获取cache列表
     * @param annoationCacheName
     * @return
     */
    public Collection<? extends Cache> getCache(Set<String> annoationCacheName){
        Collection<String> cacheNames = getAnnoationValues(annoationCacheName);
        if(null == cacheNames){
            return Collections.EMPTY_LIST;
        }
        Collection<Cache> cacheResults = new ArrayList<>();
        CacheManagerFactory cacheManagerFactory = new CacheManagerFactory();
        for(String cacheName:cacheNames){
            Cache cache = cacheManagerFactory.getCacheManager().getCache(cacheName);
            if(null == cache){
                throw new IllegalArgumentException("cannot find cache named "+cacheName);
            }
            cacheResults.add(cache);
        }
        return cacheResults;
    }
    /**
     * 获取注解上的cacheName值
     * @param annoationNames
     * @return
     */
    public Collection<String> getAnnoationValues(Set<String> annoationNames){
        Collection<String> cacheNames = new HashSet<>();
        for(String cacheName:annoationNames){
            String[] cacheParams =  cacheName.split(CacheSupport.SPERATOR);
            //注解的“#”前的第一个为缓存的name
            String realCacheName = cacheParams[0];
            cacheNames.add(realCacheName);
        }
        return  cacheNames;
    }
    /**
     * 调用方法
     * @param cacheInvocation
     * @return
     */
    public Object invoke(CacheInvocation cacheInvocation){
        Object object = null;
        MethodInvoker methodInvoker =  new MethodInvoker();
        methodInvoker.setTargetObject(cacheInvocation.getTargetBean());
        methodInvoker.setTargetMethod(cacheInvocation.getTargetMethod().getName());
        methodInvoker.setArguments(cacheInvocation.getArguments());
        try {
            methodInvoker.prepare();
            object = methodInvoker.invoke();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return object;
    }
    public void refreshCache(String cacheName,CacheInvocation cacheInvocation){
        boolean invocation;
        Object computed = null;
        try {
            computed = invoke(cacheInvocation);
            invocation = true;
        }catch (Exception e){
            invocation = false;
            e.printStackTrace();
        }
        if(invocation){
            if(!CollectionUtils.isEmpty(cacheInvocationMap.get(cacheName))){
                Cache cache = customCacheManager.getCache(cacheName);
                cache.put(cacheInvocation.getKey(),computed);
            }
        }
    }
    @Override
    public void registerInvocation(Object invokedBean, Method invokedMethod, Class[] invocationParamTypes, Object[] invocationArgs, Set<String> annoationCacheNames, String cacheKey) {
    }
    @Override
    public void refreshCacheByKey(String cacheName, String cacheKey) {
    }
}

+ 83 - 0
base/common-cache/src/main/java/com/yihu/base/cache/support/CachingAnnoationAspect.java

@ -0,0 +1,83 @@
package com.yihu.base.cache.support;
import com.yihu.base.cache.support.CacheSupport;
import org.aspectj.lang.ProceedingJoinPoint;
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.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.*;
@Aspect
@Component
public class CachingAnnoationAspect {
    @Autowired
    private CacheSupport cacheSupport;
    private <T extends Annotation> List<T> getMethodAnnotations(AnnotatedElement annotatedElement,Class<T> annotationType){
        List<T> anns = new ArrayList<T>();
        T ann = annotatedElement.getAnnotation(annotationType);
        if (null != ann) {
            anns.add(ann);
        }
        for(Annotation annotation:annotatedElement.getAnnotations()){
            ann = annotation.annotationType().getAnnotation(annotationType);
            if(null != ann){
                anns.add(ann);
            }
        }
        return anns.isEmpty() ? null : anns;
    }
    private Method getSpecificMethod(ProceedingJoinPoint proceedingJoinPoint){
        MethodSignature methodSignature = (MethodSignature)proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Class<?> targetClass = AopProxyUtils.ultimateTargetClass(proceedingJoinPoint.getTarget());
        if(null == targetClass && null != proceedingJoinPoint.getTarget()){
            targetClass = proceedingJoinPoint.getTarget().getClass();
        }
        Method specificMethod = ClassUtils.getMostSpecificMethod(method,targetClass);
        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
        return specificMethod;
    }
    @Pointcut("@annotation(org.springframework.cache.annotation.Cacheable)")
    public void pointcut(){}
    @Around("pointcut()")
    public Object registerInvocation(ProceedingJoinPoint proceedingJoinPoint){
        Object object = null;
        Method method = getSpecificMethod(proceedingJoinPoint);
        List<Cacheable> annotations =  getMethodAnnotations(method,Cacheable.class);
        Set<String> cacheSet = new HashSet<>();
        String cacheKey = "";
        for (Cacheable cacheables:annotations) {
             cacheSet.addAll(Arrays.asList(cacheables.value()));
             cacheKey = cacheables.key();
        }
        if(proceedingJoinPoint.getSignature() instanceof MethodSignature){
            Class[] parameterTpyes = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes();
            cacheSupport.registerInvocation(proceedingJoinPoint.getTarget(),method,parameterTpyes,proceedingJoinPoint.getArgs(),cacheSet,cacheKey);
        }
        try {
            object = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return object;
    }
}

+ 51 - 0
base/common-cache/src/main/java/com/yihu/base/cache/support/MapCacheSupportImpl.java

@ -0,0 +1,51 @@
package com.yihu.base.cache.support;
import com.yihu.base.cache.cache.CustomMapCache;
import com.yihu.base.cache.config.CacheKeyGenerator;
import com.yihu.base.cache.manager.CustomCacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.*;
@Component
public class MapCacheSupportImpl extends CacheSupportImpl implements CacheSupport {
    @Autowired
    private CustomCacheManager customCacheManager;
    @Override
    public void registerInvocation(Object invokedBean, Method invokedMethod, Class[] invocationParamTypes, Object[] invocationArgs, Set<String> annoationCacheNames, String cacheKey) {
        Collection<? extends Cache> caches = getCache(annoationCacheNames);
        CacheInvocation cacheInvocation = new CacheInvocation(CacheKeyGenerator.getCacheKey(),invokedBean,invokedMethod,invocationArgs,invocationParamTypes);
        for(Cache cache:caches){
            if(cache instanceof CustomMapCache){
                CustomMapCache customMapCache = (CustomMapCache)cache;
            }
        }
    }
    @Override
    public void refreshCacheByKey(String cacheName, String cacheKey) {
//        RedisTemplate redisTemplate = RedisTemplateUtils.getRedisTemplate(redisConnectionFactory);
//        CacheInvocation cacheInvocation = (CacheInvocation)redisTemplate.opsForValue().get(cacheKey);
//        if(null != cacheInvocation){
//            refreshCache(cacheInvocation,cacheName);
//        }
    }
    private void refreshCache(CacheInvocation cacheInvocation,String cacheName){
        Object computed = invoke(cacheInvocation);
        //获取缓存对象
        Cache cache = customCacheManager.getCache(cacheName);
        //更新缓存
        cache.put(cacheInvocation.getKey(),computed);
        CustomMapCache customMapCache = (CustomMapCache)cache;
    }
}

+ 63 - 0
base/common-cache/src/main/java/com/yihu/base/cache/support/RedisCacheSupportImpl.java

@ -0,0 +1,63 @@
package com.yihu.base.cache.support;
import com.yihu.base.cache.cache.CustomRedisCache;
import com.yihu.base.cache.config.CacheKeyGenerator;
import com.yihu.base.cache.manager.CustomCacheManager;
import com.yihu.base.cache.util.RedisTemplateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Component
public class RedisCacheSupportImpl extends CacheSupportImpl implements CacheSupport {
    @Autowired
    private CustomCacheManager customCacheManager;
    @Autowired
    private CacheKeyGenerator cacheKeyGenerator;
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;
    @Override
    public void registerInvocation(Object invokedBean, Method invokedMethod, Class[] invocationParamTypes, Object[] invocationArgs, Set<String> annoationCacheNames, String cacheKey) {
        Collection<? extends Cache> caches = getCache(annoationCacheNames);
        CacheInvocation cacheInvocation = new CacheInvocation(CacheKeyGenerator.getCacheKey(),invokedBean,invokedMethod,invocationArgs,invocationParamTypes);
        for(Cache cache:caches){
            if(cache instanceof CustomRedisCache){
                CustomRedisCache customRedisCache = (CustomRedisCache)cache;
                RedisTemplate redisTemplate = RedisTemplateUtils.getRedisTemplate(redisConnectionFactory);
                redisTemplate.opsForValue().set(CacheKeyGenerator.getCacheKey(),cacheInvocation,customRedisCache.getExpireTime(), TimeUnit.SECONDS);
            }
        }
    }
    @Override
    public void refreshCacheByKey(String cacheName, String cacheKey) {
        RedisTemplate redisTemplate = RedisTemplateUtils.getRedisTemplate(redisConnectionFactory);
        CacheInvocation cacheInvocation = (CacheInvocation)redisTemplate.opsForValue().get(cacheKey);
        if(null != cacheInvocation){
            refreshCache(cacheInvocation,cacheName);
        }
    }
    private void refreshCache(CacheInvocation cacheInvocation,String cacheName){
        Object computed = invoke(cacheInvocation);
        //获取缓存对象
        Cache cache = customCacheManager.getCache(cacheName);
        //更新缓存
        cache.put(cacheInvocation.getKey(),computed);
        RedisTemplate redisTemplate = RedisTemplateUtils.getRedisTemplate(redisConnectionFactory);
        CustomRedisCache customRedisCache = (CustomRedisCache)cache;
        redisTemplate.expire(cacheInvocation.getKey(),customRedisCache.getExpireTime(),TimeUnit.SECONDS);
    }
}

+ 34 - 0
base/common-cache/src/main/java/com/yihu/base/cache/util/RedisTemplateUtils.java

@ -0,0 +1,34 @@
package com.yihu.base.cache.util;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
public class RedisTemplateUtils {
    private static RedisTemplate redisTemplate;
    public static RedisTemplate getRedisTemplate(RedisConnectionFactory redisConnectionFactory){
        if(null == redisTemplate){
            synchronized (RedisTemplateUtils.class){
                if(null == redisTemplate){
                    redisTemplate = new RedisTemplate();
                    redisTemplate.setConnectionFactory(redisConnectionFactory);
                    JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
                    redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
                    redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);
                    //key采用StringRedisSserializer来序列化
                    redisTemplate.setKeySerializer(new StringRedisSerializer());
                    redisTemplate.setHashKeySerializer(new StringRedisSerializer());
                    redisTemplate.afterPropertiesSet();
                }
            }
        }
        return redisTemplate;
    }
}

+ 145 - 0
base/common-cache/src/main/java/com/yihu/base/cache/util/ReflectionUtils.java

@ -0,0 +1,145 @@
package com.yihu.base.cache.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionUtils {
    /**
     * 循环向上转型, 获取对象的 DeclaredMethod
     * @param object : 子类对象
     * @param methodName : 父类中的方法名
     * @param parameterTypes : 父类中的方法参数类型
     * @return 父类中的方法对象
     */
    public static Method getDeclaredMethod(Object object, String methodName, Class<?> ... parameterTypes){
        Method method = null ;
        for(Class<?> clazz = object.getClass() ; clazz != Object.class ; clazz = clazz.getSuperclass()) {
            try {
                method = clazz.getDeclaredMethod(methodName, parameterTypes) ;
                return method ;
            } catch (Exception e) {
                //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
                //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
            }
        }
        return null;
    }
    /**
     * 直接调用对象方法, 而忽略修饰符(private, protected, default)
     * @param object : 子类对象
     * @param methodName : 父类中的方法名
     * @param parameterTypes : 父类中的方法参数类型
     * @param parameters : 父类中的方法参数
     * @return 父类中方法的执行结果
     */
    public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,
                                      Object [] parameters) {
        //根据 对象、方法名和对应的方法参数 通过反射 调用上面的方法获取 Method 对象
        Method method = getDeclaredMethod(object, methodName, parameterTypes) ;
        //抑制Java对方法进行检查,主要是针对私有方法而言
        method.setAccessible(true) ;
        try {
            if(null != method) {
                //调用object 的 method 所代表的方法,其方法的参数是 parameters
                return method.invoke(object, parameters) ;
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 循环向上转型, 获取对象的 DeclaredField
     * @param object : 子类对象
     * @param fieldName : 父类中的属性名
     * @return 父类中的属性对象
     */
    public static Field getDeclaredField(Object object, String fieldName){
        Field field = null ;
        Class<?> clazz = object.getClass() ;
        for(; clazz != Object.class ; clazz = clazz.getSuperclass()) {
            try {
                field = clazz.getDeclaredField(fieldName) ;
                return field ;
            } catch (Exception e) {
                //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
                //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
            }
        }
        return null;
    }
    /**
     * 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
     * @param object : 子类对象
     * @param fieldName : 父类中的属性名
     * @param value : 将要设置的值
     */
    public static void setFieldValue(Object object, String fieldName, Object value){
        //根据 对象和属性名通过反射 调用上面的方法获取 Field对象
        Field field = getDeclaredField(object, fieldName) ;
        //抑制Java对其的检查
        field.setAccessible(true) ;
        try {
            //将 object 中 field 所代表的值 设置为 value
            field.set(object, value) ;
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    /**
     * 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
     * @param object : 子类对象
     * @param fieldName : 父类中的属性名
     * @return : 父类中的属性值
     */
    public static Object getFieldValue(Object object, String fieldName){
        //根据 对象和属性名通过反射 调用上面的方法获取 Field对象
        Field field = getDeclaredField(object, fieldName) ;
        //抑制Java对其的检查
        field.setAccessible(true) ;
        try {
            //获取 object 中 field 所代表的属性值
            return field.get(object) ;
        } catch(Exception e) {
            e.printStackTrace() ;
        }
        return null;
    }
}

+ 68 - 0
base/common-cache/src/main/java/com/yihu/base/cache/util/SpringContextUtils.java

@ -0,0 +1,68 @@
package com.yihu.base.cache.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * Spring上下文管理器
 * @author LiTaohong
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {
    private static ApplicationContext springContext = null;
    /**
     * 获取Spring应用上下文环境
     *
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return springContext;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        springContext = applicationContext;
    }
    /**
     * 获取Bean
     *
     * @param serviceName
     * @param <T>
     * @return
     */
    public static <T> T getBean(String serviceName) {
        return (T) springContext.getBean(serviceName);
    }
    public static <T> T getBean(Class<T> beanCls) {
        return (T) springContext.getBean(beanCls);
    }
    /**
     * 获取服务,并用参数初始化对象。
     *
     * @param serviceName
     * @param args
     * @param <T>
     * @return
     */
    public static <T> T getBean(String serviceName, Object... args) {
        T ref = (T)springContext.getBean(serviceName, args);
        if (ref == null) return null;
        return ref;
    }
    public static <T> T getBean(Class<T> beanCls, Object... args){
        T ref = (T)springContext.getBean(beanCls, args);
        if (ref == null) return null;
        return ref;
    }
}

+ 32 - 0
base/common-cache/src/main/java/com/yihu/base/cache/util/ThreadTaskUtils.java

@ -0,0 +1,32 @@
package com.yihu.base.cache.util;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
 *
 */
public class ThreadTaskUtils {
    private static ThreadPoolTaskExecutor taskExecutor = null;
    static {
        taskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程数
        taskExecutor.setCorePoolSize(5);
        // 最大线程数
        taskExecutor.setMaxPoolSize(50);
        // 队列最大长度
        taskExecutor.setQueueCapacity(1000);
        // 线程池维护线程所允许的空闲时间(单位秒)
        taskExecutor.setKeepAliveSeconds(120);
        // 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃.
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        taskExecutor.initialize();
    }
    public static void run(Runnable runnable) {
        taskExecutor.execute(runnable);
    }
}

+ 3 - 3
svr/svr-base/src/main/java/com/yihu/jw/business/user/contorller/EmployController.java

@ -26,7 +26,6 @@ public class EmployController extends EnvelopRestController {
    @Autowired
    private EmployService employService;
    @PostMapping(value = BaseUserRequestMapping.BaseEmploy.api_create, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "创建用户", notes = "创建单个用户")
    public Envelop createBaseEmployDO(@ApiParam(name = "json_data", value = "", defaultValue = "") @RequestBody String jsonData){
@ -71,9 +70,10 @@ public class EmployController extends EnvelopRestController {
    @ApiOperation(value = "根据name模糊查询某saasId平台下的所有用户")
    @GetMapping(value = BaseUserRequestMapping.BaseEmploy.api_getList)
    public Envelop getListByNameAndSaasId(@ApiParam(name = "saasId", value = "saasId", required = true) @RequestParam(value = "saasId", required = true) String saasId) {
    public Envelop getListByNameAndSaasId(@ApiParam(name = "saasId", value = "saasId", required = true) @RequestParam(value = "saasId", required = true) String saasId,
                                          @ApiParam(name = "name", value = "name", required = true) @RequestParam(value = "name", required = true) String name) {
        try{
            return Envelop.getSuccess(BaseUserRequestMapping.BaseRole.message_success_find,this.employService.findAllBySaasId(saasId));
            return Envelop.getSuccess(BaseUserRequestMapping.BaseRole.message_success_find,this.employService.findAllByNameAndSaasId(name,saasId));
        } catch (ApiException e){
            return Envelop.getError(e.getMessage(), e.getErrorCode());
        }