Commit 603cf3fb2f78f56142026bc40c39bf8d765406ae

Authored by ci-aliyun
2 parents 4162469d a476e3ab

Release 1.2.4

.gitignore
... ... @@ -4,3 +4,5 @@
4 4 target/
5 5  
6 6 \.DS_Store
  7 +
  8 +*.iml
... ...
README.md
1   -sass-common-lib:公共项目库
  1 +## sass-common-lib:公共项目库
  2 +
  3 +### v 1.2.0版本更新记录
  4 +- 利用redis和ehcache增加了缓存支持,redis为L2级缓存,ehcache为L1级cache;
  5 +> application.yml基本配置如下:
  6 +```json
  7 +#开启ehcache和redis两级缓存
  8 +springext:
  9 + cache:
  10 + enable: true
  11 + cacheL1:
  12 + enable: true
  13 + topic: cache #同步L1缓存的topic
  14 + key: "keys"
  15 +```
  16 +```json
  17 +#redis配置
  18 +spring:
  19 + redis:
  20 + database: 10
  21 + host: 192.168.2.252
  22 + port: 6379
  23 +# password: zhnf@123
  24 + pool:
  25 + max-wait: 1
  26 +```
  27 +
  28 +### v1.2.1
  29 +- 增加了KeyGenerator实现类,实现类中使用className.methodName:params拼接成key
  30 +
  31 +### v1.2.2
  32 +- 增加了对@CacheEvict(allEntries = true)的支持
2 33 \ No newline at end of file
... ...
... ... @@ -6,19 +6,22 @@
6 6  
7 7 <groupId>com.irrigation</groupId>
8 8 <artifactId>common-lib</artifactId>
9   - <version>1.0-SNAPSHOT</version>
  9 + <version>1.2.4</version>
10 10  
11 11 <properties>
12 12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13 13 <java.version>1.8</java.version>
  14 + <spring-boot.version>1.5.10.RELEASE</spring-boot.version>
14 15 <swagger.version>2.7.0</swagger.version>
15 16 <lombok.version>1.16.20</lombok.version>
16 17 <commons-codec.version>1.11</commons-codec.version>
17 18 <guava.vsersion>20.0</guava.vsersion>
18 19 <slf4j.version>1.7.24</slf4j.version>
19   - <fastjson.version>1.2.46</fastjson.version>
  20 + <fastjson.version>1.2.49</fastjson.version>
20 21 <spring-web.version>4.3.14.RELEASE</spring-web.version>
21 22 <spring-security-core.version>4.2.4.RELEASE</spring-security-core.version>
  23 + <ehcache.version>2.6.11</ehcache.version>
  24 +
22 25 </properties>
23 26  
24 27  
... ... @@ -83,6 +86,36 @@
83 86 <version>${spring-security-core.version}</version>
84 87 <scope>provided</scope>
85 88 </dependency>
  89 + <dependency>
  90 + <groupId>net.sf.ehcache</groupId>
  91 + <artifactId>ehcache-core</artifactId>
  92 + <version>${ehcache.version}</version>
  93 + <exclusions>
  94 + <exclusion>
  95 + <groupId>org.slf4j</groupId>
  96 + <artifactId>slf4j-api</artifactId>
  97 + </exclusion>
  98 + </exclusions>
  99 + <!--<scope>provided</scope>-->
  100 + </dependency>
  101 + <dependency>
  102 + <groupId>org.springframework.boot</groupId>
  103 + <artifactId>spring-boot-starter-cache</artifactId>
  104 + <version>${spring-boot.version}</version>
  105 + <!--<scope>provided</scope>-->
  106 + </dependency>
  107 + <dependency>
  108 + <groupId>org.springframework.boot</groupId>
  109 + <artifactId>spring-boot-starter-data-redis</artifactId>
  110 + <version>${spring-boot.version}</version>
  111 + <!--<scope>provided</scope>-->
  112 + </dependency>
  113 + <dependency>
  114 + <groupId>org.springframework.boot</groupId>
  115 + <artifactId>spring-boot-configuration-processor</artifactId>
  116 + <version>${spring-boot.version}</version>
  117 + <!--<scope>provided</scope>-->
  118 + </dependency>
86 119  
87 120 </dependencies>
88 121 <build>
... ...
src/main/java/com/irrigation/icl/cache/Command.java 0 → 100644
  1 +package com.irrigation.icl.cache;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.io.Serializable;
  6 +
  7 +/**
  8 + * Command
  9 + */
  10 +@Data
  11 +public class Command implements Serializable {
  12 +
  13 + private static final long serialVersionUID = 7126530485423286910L;
  14 +
  15 + // 设置本地缓存
  16 + public final static byte OPT_SET = 0x01;
  17 + // 删除本地缓存Key
  18 + public final static byte OPT_DEL = 0x02;
  19 + // 删除本地缓存
  20 + public final static byte OPT_REM = 0x03;
  21 +
  22 + public byte oper;
  23 + public String name;
  24 + public String key;
  25 + public String src;
  26 +
  27 + public Command() {
  28 + }
  29 +
  30 + public Command(String src, byte oper, String name, String key) {
  31 + this.src = src;
  32 + this.oper = oper;
  33 + this.name = name;
  34 + this.key = key;
  35 + }
  36 +
  37 + /**
  38 + * 更新本地缓存
  39 + *
  40 + * @param cacheName
  41 + * @param key
  42 + * @return
  43 + */
  44 + public static Command set(String src, String cacheName, String key) {
  45 + return new Command(src, OPT_SET, cacheName, key);
  46 + }
  47 +
  48 + /**
  49 + * 删除本地缓存Key
  50 + *
  51 + * @param cacheName
  52 + * @param key
  53 + * @return
  54 + */
  55 + public static Command del(String src, String cacheName, String key) {
  56 + return new Command(src, OPT_DEL, cacheName, key);
  57 + }
  58 +
  59 + /**
  60 + * 删除本地缓存
  61 + *
  62 + * @param cacheName
  63 + * @return
  64 + */
  65 + public static Command rem(String src, String cacheName) {
  66 + return new Command(src, OPT_REM, cacheName, null);
  67 + }
  68 +}
0 69 \ No newline at end of file
... ...
src/main/java/com/irrigation/icl/cache/LayeringCacheAutoFactory.java 0 → 100644
  1 +package com.irrigation.icl.cache;
  2 +
  3 +import com.irrigation.icl.cache.core.LayeringCacheLoadCondition;
  4 +import com.irrigation.icl.cache.core.LayeringCacheManager;
  5 +import com.irrigation.icl.cache.core.LayeringCacheProperties;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
  8 +import org.springframework.cache.CacheManager;
  9 +import org.springframework.context.annotation.Bean;
  10 +import org.springframework.context.annotation.Conditional;
  11 +import org.springframework.context.annotation.Configuration;
  12 +import org.springframework.data.redis.connection.Message;
  13 +import org.springframework.data.redis.connection.MessageListener;
  14 +import org.springframework.data.redis.connection.RedisConnectionFactory;
  15 +import org.springframework.data.redis.core.RedisTemplate;
  16 +import org.springframework.data.redis.listener.PatternTopic;
  17 +import org.springframework.data.redis.listener.RedisMessageListenerContainer;
  18 +import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
  19 +
  20 +/**
  21 + * @Author: boni
  22 + * @Date: 2018/8/24-下午2:37
  23 + */
  24 +@Configuration
  25 +@Conditional(LayeringCacheLoadCondition.class)
  26 +@EnableConfigurationProperties(LayeringCacheProperties.class)
  27 +@Slf4j
  28 +public class LayeringCacheAutoFactory {
  29 + @Bean
  30 + public LayeringCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate,
  31 + LayeringCacheProperties layeringCacheProperties) {
  32 + LayeringCacheManager cacheManager = new LayeringCacheManager(redisTemplate, layeringCacheProperties);
  33 + cacheManager.setUsePrefix(true);
  34 + long expire = layeringCacheProperties.getExpire() > 0L ? layeringCacheProperties.getExpire() : 120L;
  35 + cacheManager.setExpires(layeringCacheProperties.getExpires());
  36 + cacheManager.setDefaultExpiration(expire);
  37 + return cacheManager;
  38 + }
  39 +
  40 + @Bean
  41 + RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
  42 + LayeringCacheProperties layeringCacheProperties,
  43 + MessageListenerAdapter listenerAdapter) {
  44 + RedisMessageListenerContainer container = new RedisMessageListenerContainer();
  45 + container.setConnectionFactory(connectionFactory);
  46 + container.addMessageListener(listenerAdapter, new PatternTopic(layeringCacheProperties.getCacheL1().getTopic()));
  47 +
  48 + return container;
  49 + }
  50 +
  51 + @Bean
  52 + LayeringCacheSyncCommandHandler layeringCacheSyncCommandHandler(CacheManager cacheManager) {
  53 + LayeringCacheSyncCommandHandler handler = new LayeringCacheSyncCommandHandler(cacheManager);
  54 + return handler;
  55 + }
  56 +
  57 + @Bean
  58 + MessageListenerAdapter listenerAdapter(LayeringCacheSyncCommandHandler handler,
  59 + RedisTemplate<Object, Object> redisTemplate) {
  60 +
  61 + return new MessageListenerAdapter(new MessageListener() {
  62 + @Override
  63 + public void onMessage(Message message, byte[] pattern) {
  64 + byte[] content = message.getBody();
  65 + if (content != null) {
  66 +// String commandString = new String(content, Charset.defaultCharset());
  67 +// Command command = JSON.parseObject(commandString, Command.class);
  68 + Command command = (Command) redisTemplate.getValueSerializer().deserialize(content);
  69 + if (command != null) {
  70 + log.debug(command.toString());
  71 + handler.handle(command);
  72 + }
  73 + }
  74 + }
  75 +
  76 + });
  77 + }
  78 +}
0 79 \ No newline at end of file
... ...
src/main/java/com/irrigation/icl/cache/LayeringCacheSyncCommandHandler.java 0 → 100644
  1 +package com.irrigation.icl.cache;
  2 +
  3 +import com.irrigation.icl.cache.core.LayeringCache;
  4 +import lombok.Getter;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import org.springframework.cache.CacheManager;
  7 +
  8 +/**
  9 + * @Author: boni
  10 + * @Date: 2018/8/29-下午5:44
  11 + */
  12 +@Slf4j
  13 +@Getter
  14 +public class LayeringCacheSyncCommandHandler {
  15 + CacheManager cacheManager;
  16 +
  17 + public LayeringCacheSyncCommandHandler(CacheManager cacheManager) {
  18 + this.cacheManager = cacheManager;
  19 + }
  20 +
  21 + public void handle(Command command) {
  22 + if (cacheManager != null) {
  23 + LayeringCache layeringCache = (LayeringCache) cacheManager.getCache(command.getName());
  24 + if (layeringCache == null) {
  25 + return;
  26 + }
  27 + layeringCache.updateL1Cache(command);
  28 + }
  29 + }
  30 +}
... ...
src/main/java/com/irrigation/icl/cache/config/CacheConfig.java 0 → 100644
  1 +package com.irrigation.icl.cache.config;
  2 +
  3 +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  4 +import org.springframework.context.annotation.Bean;
  5 +import org.springframework.context.annotation.Configuration;
  6 +import org.springframework.data.redis.connection.RedisConnectionFactory;
  7 +import org.springframework.data.redis.core.RedisTemplate;
  8 +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
  9 +import org.springframework.data.redis.serializer.StringRedisSerializer;
  10 +
  11 +/**
  12 + * @Author: boni
  13 + * @Date: 2018/8/24-下午2:03
  14 + */
  15 +@Configuration
  16 +public class CacheConfig {
  17 +
  18 + @ConditionalOnMissingBean(RedisTemplate.class)
  19 + @Bean
  20 + public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
  21 + RedisTemplate<Object, Object> template = new RedisTemplate<>();
  22 + template.setConnectionFactory(connectionFactory);
  23 +// Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
  24 +// ObjectMapper om = new ObjectMapper();
  25 +// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  26 +// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  27 +// jackson2JsonRedisSerializer.setObjectMapper(om);
  28 +//
  29 + template.setValueSerializer(new JdkSerializationRedisSerializer());
  30 + //使用StringRedisSerializer来序列化和反序列化redis的key值
  31 + template.setKeySerializer(new StringRedisSerializer());
  32 + template.afterPropertiesSet();
  33 + return template;
  34 + }
  35 +
  36 +}
... ...
src/main/java/com/irrigation/icl/cache/core/CustomCacheKeyGenerator.java 0 → 100644
  1 +package com.irrigation.icl.cache.core;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.springframework.cache.interceptor.KeyGenerator;
  5 +import org.springframework.util.StringUtils;
  6 +
  7 +import java.lang.reflect.Method;
  8 +
  9 +/**
  10 + * @Author: boni
  11 + * @Date: 2018/9/4-下午3:20
  12 + */
  13 +@Slf4j
  14 +public class CustomCacheKeyGenerator implements KeyGenerator {
  15 + public static final int NO_PARAM_KEY = 0;
  16 +
  17 + @Override
  18 + public Object generate(Object target, Method method, Object... params) {
  19 + StringBuilder key = new StringBuilder();
  20 + key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":");
  21 + if (params.length == 0) {
  22 + return key.append(NO_PARAM_KEY).toString();
  23 + }
  24 + key.append(StringUtils.arrayToCommaDelimitedString(params));
  25 + //String finalKey = key.toString();
  26 + //log.debug("using cache key={}", finalKey);
  27 + return key.toString();
  28 + }
  29 +}
... ...
src/main/java/com/irrigation/icl/cache/core/LayeringCache.java 0 → 100644
  1 +package com.irrigation.icl.cache.core;
  2 +
  3 +import com.irrigation.icl.cache.Command;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import net.sf.ehcache.CacheException;
  6 +import net.sf.ehcache.CacheManager;
  7 +import net.sf.ehcache.Ehcache;
  8 +import net.sf.ehcache.Element;
  9 +import net.sf.ehcache.config.CacheConfiguration;
  10 +import net.sf.ehcache.config.Configuration;
  11 +import net.sf.ehcache.config.DiskStoreConfiguration;
  12 +import net.sf.ehcache.config.PersistenceConfiguration;
  13 +import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
  14 +import org.springframework.cache.Cache;
  15 +import org.springframework.cache.support.SimpleValueWrapper;
  16 +import org.springframework.data.redis.cache.RedisCache;
  17 +import org.springframework.data.redis.core.RedisOperations;
  18 +import org.springframework.util.StopWatch;
  19 +
  20 +import java.text.SimpleDateFormat;
  21 +import java.util.Date;
  22 +import java.util.concurrent.Callable;
  23 +import java.util.concurrent.ConcurrentHashMap;
  24 +import java.util.concurrent.Future;
  25 +import java.util.concurrent.FutureTask;
  26 +
  27 +/**
  28 + * @Author: boni
  29 + * @Date: 2018/8/24-下午2:27
  30 + */
  31 +@Slf4j
  32 +public class LayeringCache extends RedisCache {
  33 + private final ConcurrentHashMap<String, Future<Ehcache>> layeringL1CacheContainer = new ConcurrentHashMap<>();
  34 + private LayeringCacheProperties layeringCacheProperties;
  35 + private LayeringCacheManager layeringCacheManager;
  36 + private CacheManager layeringL1CacheManager;
  37 + private boolean layerL1Enable;
  38 + private String ID;
  39 +// private String HOST;
  40 +// private String CACHE_STORE;
  41 +// private String CACHE_STORE_SYNC;
  42 +
  43 +
  44 + public LayeringCache(LayeringCacheManager layeringCacheManager, String name, byte[] prefix,
  45 + RedisOperations<? extends Object, ? extends Object> redisOperations, long expiration) {
  46 + super(name, prefix, redisOperations, expiration);
  47 + this.layeringCacheManager = layeringCacheManager;
  48 + this.layeringCacheProperties = layeringCacheManager.getLayeringCacheProperties();
  49 + this.layerL1Enable = layeringCacheProperties.getCacheL1().isEnable();
  50 + initEhcache();
  51 + }
  52 +
  53 + @Override
  54 + public Cache.ValueWrapper get(Object key) {
  55 + StopWatch stopWatch = new StopWatch();
  56 + stopWatch.start();
  57 + Ehcache ehCache = null;
  58 + if (layerL1Enable) {
  59 + ehCache = getL1Cache(super.getName());
  60 + Element value = ehCache.get(key);
  61 + if (value != null) {
  62 + log.debug("Hit Cache L1 (ehcache) :{}={}", key, value);
  63 + return new SimpleValueWrapper(value.getObjectValue());
  64 + }
  65 + }
  66 + Cache.ValueWrapper wrapper = super.get(key);
  67 + if (layerL1Enable && ehCache != null && wrapper != null) {
  68 + ehCache.put(new Element(key, wrapper.get()));
  69 + log.debug("Hit Cache L2 (redis) :{}={}", key, wrapper);
  70 + }
  71 + stopWatch.stop();
  72 + log.debug("get use {} ms", stopWatch.getTotalTimeMillis());
  73 + return wrapper;
  74 + }
  75 +
  76 + @Override
  77 + public void put(final Object key, final Object value) {
  78 + StopWatch stopWatch = new StopWatch();
  79 + stopWatch.start();
  80 + // 先更新1级然后再更新2级;允许短时间内的数据不一致
  81 + if (layerL1Enable) {
  82 + Ehcache ehCache = getL1Cache(super.getName());
  83 + ehCache.put(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties.getCacheL1()
  84 + .getLocalTimeToLiveSeconds()));
  85 + layeringCacheManager.publishMessage(Command.set(this.ID, super.getName(), String.valueOf(key)));
  86 + }
  87 + super.put(key, value);
  88 + stopWatch.stop();
  89 + log.debug("put use {} ms", stopWatch.getTotalTimeMillis());
  90 + }
  91 +
  92 + @Override
  93 + public void evict(Object key) {
  94 + // 先删除2级缓存,然后再删除1级缓存;
  95 + super.evict(key);
  96 + if (layerL1Enable) {
  97 + Ehcache ehCache = getL1Cache(super.getName());
  98 + ehCache.remove(key);
  99 + layeringCacheManager.publishMessage(Command.del(this.ID, super.getName(), String.valueOf(key)));
  100 + }
  101 + }
  102 +
  103 + @Override
  104 + public Cache.ValueWrapper putIfAbsent(Object key, final Object value) {
  105 + if (layerL1Enable) {
  106 + Ehcache ehCache = getL1Cache(super.getName());
  107 + ehCache.putIfAbsent(new Element(key, value, false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(), layeringCacheProperties
  108 + .getCacheL1().getLocalTimeToLiveSeconds()));
  109 + layeringCacheManager.publishMessage(Command.set(this.ID, super.getName(), String.valueOf(key)));
  110 + }
  111 + Cache.ValueWrapper wrapper = super.putIfAbsent(key, value);
  112 + return wrapper;
  113 + }
  114 +
  115 + @Override
  116 + public void clear() {
  117 + super.clear();
  118 + if (layerL1Enable) {
  119 + Ehcache ehCache = getL1Cache(super.getName());
  120 + ehCache.removeAll();
  121 + layeringCacheManager.publishMessage(Command.rem(this.ID, super.getName()));
  122 + }
  123 + }
  124 +
  125 + public void updateL1Cache(Command command) {
  126 + if (layerL1Enable && command != null && !this.ID.equals(command.getSrc())) {
  127 + switch (command.getOper()) {
  128 + case Command.OPT_DEL:
  129 + getL1Cache(command.getName()).remove(command.getKey());
  130 + log.debug("Remove Cache L1 {} - {}", command.getName(), command.getKey());
  131 + break;
  132 + case Command.OPT_REM:
  133 + getL1Cache(command.getName()).removeAll();
  134 + log.debug("Clear Cache L1 {}", command.getName());
  135 + break;
  136 + case Command.OPT_SET:
  137 + Cache.ValueWrapper wrapper = super.get(command.getKey());
  138 + if (wrapper != null) {
  139 + Ehcache ehCache = getL1Cache(super.getName());
  140 + ehCache.put(new Element(command.getKey(), wrapper.get(), false, layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds(),
  141 + layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds()));
  142 + log.debug("Update Cache L1 {} - {}", command.getKey(), wrapper.get());
  143 + }
  144 + break;
  145 + default:
  146 + break;
  147 + }
  148 + }
  149 + }
  150 +
  151 + /**
  152 + * 创建本地缓存
  153 + */
  154 + private Ehcache getL1Cache(final String name) {
  155 + Future<Ehcache> future = this.layeringL1CacheContainer.get(name);
  156 + if (future == null) {
  157 + Callable<Ehcache> callable = () -> {
  158 + Ehcache cache = layeringL1CacheManager.getCache(name);
  159 + if (cache == null) {
  160 + CacheConfiguration cacheConfiguration = getCacheConfiguration();
  161 + cacheConfiguration.setName(name);
  162 + Ehcache ehcache = new net.sf.ehcache.Cache(cacheConfiguration);
  163 + layeringL1CacheManager.addCache(ehcache);
  164 + cache = layeringL1CacheManager.getEhcache(name);
  165 + }
  166 + return cache;
  167 + };
  168 + FutureTask<Ehcache> task = new FutureTask<>(callable);
  169 + future = this.layeringL1CacheContainer.putIfAbsent(name, task);
  170 + if (future == null) {
  171 + future = task;
  172 + task.run();
  173 + }
  174 + }
  175 + try {
  176 + return future.get();
  177 + } catch (Exception e) {
  178 + this.layeringL1CacheContainer.remove(name);
  179 + throw new CacheException(e);
  180 + }
  181 +
  182 + }
  183 +
  184 +
  185 + private String getDate() {
  186 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
  187 +
  188 + return simpleDateFormat.format(new Date());
  189 + }
  190 +
  191 + private CacheConfiguration getCacheConfiguration() {
  192 + // Cache
  193 + CacheConfiguration cacheConfiguration = new CacheConfiguration();
  194 + cacheConfiguration.setEternal(false);
  195 +
  196 + PersistenceConfiguration persistenceConfiguration = new PersistenceConfiguration();
  197 + persistenceConfiguration.setStrategy(PersistenceConfiguration.Strategy.NONE.name());
  198 +
  199 + cacheConfiguration.persistence(persistenceConfiguration);
  200 + cacheConfiguration.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU);
  201 + cacheConfiguration.setDiskExpiryThreadIntervalSeconds(layeringCacheProperties.getCacheL1().getLocalDiskExpiryThreadIntervalSeconds());
  202 + // 默认false,使用引用.设置为true,避免外部代码修改了缓存对象.造成EhCache的缓存对象也随之改变
  203 + // 但是设置为true后,将引起element的tti不自动刷新.如果直接新建element去覆盖原值.则本地ttl和远程ttl会产生一定的误差.
  204 + // 因此,使用时放弃手动覆盖方式刷新本地tti,当本地tti过期后,自动从Redis中再获取即可.
  205 + cacheConfiguration.copyOnRead(true);
  206 + cacheConfiguration.copyOnWrite(true);
  207 +
  208 +// CopyStrategyConfiguration copyStrategyConfiguration = new CopyStrategyConfiguration();
  209 +// copyStrategyConfiguration.setClass(MyCopyStrategy.class.getName());
  210 +// copyStrategyConfiguration.setCopyStrategyInstance(new MyCopyStrategy());
  211 +
  212 +// cacheConfiguration.addCopyStrategy(copyStrategyConfiguration);
  213 +
  214 + cacheConfiguration.setTimeToIdleSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToIdleSeconds());
  215 + cacheConfiguration.setTimeToLiveSeconds(layeringCacheProperties.getCacheL1().getLocalTimeToLiveSeconds());
  216 +
  217 + return cacheConfiguration;
  218 + }
  219 +
  220 + private void initEhcache() {
  221 + if (layerL1Enable) {
  222 + this.ID = layeringCacheProperties.getCacheL1().getKey() + "." + getDate();
  223 +// this.HOST = Utils.getLocalHostIP();
  224 +// this.CACHE_STORE = layeringCacheProperties.getCacheL1().getKey()
  225 +// + layeringCacheProperties.getCacheL1().getSeparator()
  226 +// + "cache"
  227 +// + layeringCacheProperties.getCacheL1().getSeparator()
  228 +// + "store";
  229 +// this.CACHE_STORE_SYNC = this.CACHE_STORE + layeringCacheProperties.getCacheL1().getSeparator() + "sync";
  230 +
  231 + Configuration configuration = new Configuration();
  232 + configuration.setName(this.ID);
  233 + configuration.setMaxBytesLocalHeap(layeringCacheProperties.getCacheL1().getLocalMaxBytesLocalHeap());
  234 + configuration.setMaxBytesLocalDisk(layeringCacheProperties.getCacheL1().getLocalMaxBytesLocalDisk());
  235 + // DiskStore
  236 + // 每次启动设置新的文件地址,以避免重启期间一级缓存未同步,以及单机多应用启动造成EhcacheManager重复的问题.
  237 + DiskStoreConfiguration dsc = new DiskStoreConfiguration();
  238 + dsc.setPath(layeringCacheProperties.getCacheL1().getLocalStoreLocation() + this.ID);
  239 + configuration.diskStore(dsc);
  240 +
  241 + CacheConfiguration cacheConfiguration = getCacheConfiguration();
  242 +
  243 + configuration.setDefaultCacheConfiguration(cacheConfiguration);
  244 + configuration.setDynamicConfig(false);
  245 + configuration.setUpdateCheck(false);
  246 +
  247 +
  248 + layeringL1CacheManager = new CacheManager(configuration);
  249 + }
  250 + }
  251 +//
  252 +// class MyCopyStrategy implements ReadWriteCopyStrategy<Element> {
  253 +// @Override
  254 +// public Element copyForWrite(Element value) {
  255 +// if (value != null) {
  256 +// Object temp = (Serializable) value.getObjectValue();
  257 +// return new Element(value.getObjectKey(), temp);
  258 +// }
  259 +// return value;
  260 +// }
  261 +//
  262 +// @Override
  263 +// public Element copyForRead(Element storedValue) {
  264 +// if (storedValue != null) {
  265 +// Object temp = (Serializable) storedValue.getObjectValue();
  266 +// return new Element(storedValue.getObjectKey(), temp);
  267 +// }
  268 +// return storedValue;
  269 +//
  270 +// }
  271 +// }
  272 +}
... ...
src/main/java/com/irrigation/icl/cache/core/LayeringCacheLoadCondition.java 0 → 100644
  1 +package com.irrigation.icl.cache.core;
  2 +
  3 +import org.springframework.boot.bind.RelaxedPropertyResolver;
  4 +import org.springframework.context.annotation.Condition;
  5 +import org.springframework.context.annotation.ConditionContext;
  6 +import org.springframework.core.type.AnnotatedTypeMetadata;
  7 +
  8 +/**
  9 + * @Author: boni
  10 + * @Date: 2018/8/24-下午2:52
  11 + */
  12 +public class LayeringCacheLoadCondition implements Condition {
  13 + @Override
  14 + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  15 + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
  16 + context.getEnvironment(), "springext.cache.");
  17 +
  18 + Boolean enable = resolver.getProperty("enable",Boolean.class);
  19 + if(enable == null){
  20 + return false;
  21 + }
  22 + return enable.booleanValue();
  23 +
  24 + }
  25 +}
... ...
src/main/java/com/irrigation/icl/cache/core/LayeringCacheManager.java 0 → 100644
  1 +package com.irrigation.icl.cache.core;
  2 +
  3 +import com.irrigation.icl.cache.Command;
  4 +import org.springframework.data.redis.cache.RedisCache;
  5 +import org.springframework.data.redis.cache.RedisCacheManager;
  6 +import org.springframework.data.redis.core.RedisOperations;
  7 +
  8 +/**
  9 + * @Author: boni
  10 + * @Date: 2018/8/24-下午2:29
  11 + */
  12 +public class LayeringCacheManager extends RedisCacheManager {
  13 +
  14 + private LayeringCacheProperties layeringCacheProperties;
  15 +
  16 + public LayeringCacheProperties getLayeringCacheProperties() {
  17 + return layeringCacheProperties;
  18 + }
  19 +
  20 + public void setLayeringCacheProperties(LayeringCacheProperties layeringCacheProperties) {
  21 + this.layeringCacheProperties = layeringCacheProperties;
  22 + }
  23 +
  24 + public LayeringCacheManager(RedisOperations redisOperations, LayeringCacheProperties layeringCacheProperties) {
  25 + super(redisOperations);
  26 + this.layeringCacheProperties = layeringCacheProperties;
  27 + }
  28 +
  29 + @SuppressWarnings("unchecked")
  30 + @Override
  31 + protected RedisCache createCache(String cacheName) {
  32 + long expiration = computeExpiration(cacheName);
  33 + return new LayeringCache(
  34 + this,
  35 + cacheName,
  36 + (this.isUsePrefix() ? this.getCachePrefix().prefix(cacheName) : null),
  37 + this.getRedisOperations(),
  38 + expiration);
  39 + }
  40 +
  41 +
  42 + //notify other redis clent to update L1
  43 + public void publishMessage(Command command) {
  44 + this.getRedisOperations().convertAndSend(this.getLayeringCacheProperties().getCacheL1().getTopic(), command);
  45 + }
  46 +
  47 +
  48 +}
... ...
src/main/java/com/irrigation/icl/cache/core/LayeringCacheProperties.java 0 → 100644
  1 +package com.irrigation.icl.cache.core;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * @Author: boni
  10 + * @Date: 2018/8/24-下午2:59
  11 + */
  12 +
  13 +@Data
  14 +@ConfigurationProperties(prefix = "springext.cache")
  15 +public class LayeringCacheProperties {
  16 +
  17 + /**
  18 + * L1缓存配置
  19 + */
  20 + private L1 cacheL1;
  21 + /**
  22 + * 是否启用缓存
  23 + */
  24 + private boolean enable = true;
  25 + /**
  26 + * L2级缓存的过期时间,单位秒
  27 + */
  28 + private long expire;
  29 +
  30 +
  31 + /**
  32 + * L2级缓存的过期时间,name :time
  33 + */
  34 + private Map<String, Long> expires;
  35 +
  36 +
  37 + @Data
  38 + // ehcache设置
  39 + public static class L1 {
  40 +
  41 + /**
  42 + * 是否启用L1缓存
  43 + */
  44 + private boolean enable = false;
  45 + /**
  46 + * 启用L1缓存后同步的topic
  47 + */
  48 + private String topic = "default_L1_sync_topic";
  49 +
  50 + /**
  51 + * cache中使用的key前缀
  52 + */
  53 + private String key = "L1";
  54 +
  55 + /**
  56 + * key分隔符
  57 + */
  58 + private String separator = ":";
  59 +
  60 + /**
  61 + * L1缓存存储磁盘位置
  62 + */
  63 + private String localStoreLocation = "./cache/";
  64 + /**
  65 + * 本地缓存最大内存大小
  66 + */
  67 + private String localMaxBytesLocalHeap = "128M";
  68 + /**
  69 + * 本地缓存最大磁盘大小
  70 + */
  71 + private String localMaxBytesLocalDisk = "1024M";
  72 +
  73 + /**
  74 + * 本地缓存过期时间,单位秒,默认10分钟
  75 + */
  76 + private int localTimeToLiveSeconds = 1 * 60;
  77 + private int localTimeToIdleSeconds = 0;
  78 + /**
  79 + * 本地缓存清理周期,单位秒,默认3分钟
  80 + */
  81 + private int localDiskExpiryThreadIntervalSeconds = 90;
  82 + }
  83 +}
... ...
src/main/java/com/irrigation/icl/entity/PageList.java
... ... @@ -9,10 +9,14 @@ import lombok.NoArgsConstructor;
9 9  
10 10 import java.util.List;
11 11  
  12 +/**
  13 + * 分页返回类
  14 + * @param <E>
  15 + */
12 16 @Data
13 17 @NoArgsConstructor
14 18 @AllArgsConstructor
15   -@ApiModel(value = "分页返回类")
  19 +@ApiModel(value = "PageList")
16 20 public class PageList<E> {
17 21  
18 22 @ApiModelProperty(value = "总页数")
... ...
src/main/java/com/irrigation/icl/entity/PageParam.java
... ... @@ -6,10 +6,13 @@ import lombok.AllArgsConstructor;
6 6 import lombok.Data;
7 7 import lombok.NoArgsConstructor;
8 8  
  9 +/**
  10 + * 分页参数类
  11 + */
9 12 @Data
10 13 @NoArgsConstructor
11 14 @AllArgsConstructor
12   -@ApiModel(value = "分页参数类")
  15 +@ApiModel(value = "PageParam")
13 16 public class PageParam {
14 17  
15 18 @ApiModelProperty(value = "当前页")
... ...
src/main/java/com/irrigation/icl/entity/RestResult.java
... ... @@ -10,14 +10,18 @@ import lombok.AllArgsConstructor;
10 10 import lombok.Data;
11 11 import lombok.NoArgsConstructor;
12 12  
  13 +/**
  14 + * 公共返回类
  15 + * @param <T>
  16 + */
13 17 @Data
14 18 @AllArgsConstructor
15 19 @NoArgsConstructor
16   -@ApiModel(value = "公共返回类")
  20 +@ApiModel(value = "RestResult")
17 21 public class RestResult<T> {
18   - @ApiModelProperty(value = "返回编码类型")
  22 + @ApiModelProperty(value = "返回编码类型",example = "200",allowableValues = "200,400")
19 23 private int code;
20   - @ApiModelProperty(value = "返回提示消息")
  24 + @ApiModelProperty(value = "返回提示消息",example = "成功")
21 25 private String message;
22 26 @ApiModelProperty(value = "返回请求数据对象")
23 27 private T data;
... ...
src/main/java/com/irrigation/icl/enums/ResultEnum.java
... ... @@ -26,7 +26,7 @@ public enum ResultEnum {
26 26 private final int code;
27 27 private final String message;
28 28  
29   - private ResultEnum(int code, String message) {
  29 + ResultEnum(int code, String message) {
30 30 this.code = code;
31 31 this.message = message;
32 32 }
... ...
src/main/java/com/irrigation/icl/utils/RestResultGeneratorUtil.java
... ... @@ -11,23 +11,35 @@ public class RestResultGeneratorUtil {
11 11 return result;
12 12 }
13 13  
  14 + public static <T> RestResult<T> getSuccessResult() {
  15 + return getResult(ResultEnum.SUCCESS.getCode(), null, ResultEnum.SUCCESS.getMessage());
  16 + }
14 17 public static <T> RestResult<T> getSuccessResult(T data) {
15 18 return getResult(ResultEnum.SUCCESS.getCode(), data, ResultEnum.SUCCESS.getMessage());
16 19 }
17 20  
18   - public static RestResult<String> getSuccessResult() {
19   - return getResult(ResultEnum.SUCCESS.getCode(), null, ResultEnum.SUCCESS.getMessage());
  21 + public static <T> RestResult<T> getSuccessResult(T data,String message) {
  22 + return getResult(ResultEnum.SUCCESS.getCode(), data, message);
20 23 }
21 24  
22   - public static RestResult<String> getErrorResult(String message) {
  25 + public static <T> RestResult<T> getSuccessResultMsg(String message) {
  26 + return getResult(ResultEnum.SUCCESS.getCode(), null, message);
  27 + }
  28 +
  29 +
  30 +// public static RestResult<String> getErrorResult(String message) {
  31 +// return getResult(ResultEnum.ERROR.getCode(), null, message);
  32 +// }
  33 +
  34 + public static <T> RestResult<T> getErrorResult(String message) {
23 35 return getResult(ResultEnum.ERROR.getCode(), null, message);
24 36 }
25 37  
26   - public static RestResult<String> getErrorResult(int code, String message) {
  38 + public static <T> RestResult<T> getErrorResult(int code, String message) {
27 39 return getResult(code, null, message);
28 40 }
29 41  
30   - public static RestResult<String> getErrorResult(ResultEnum resultEnum) {
  42 + public static <T> RestResult<T> getErrorResult(ResultEnum resultEnum) {
31 43 return getResult(resultEnum.getCode(), null, resultEnum.getMessage());
32 44 }
33 45 }
... ...