SpringBoot micro electric service providers to develop practical projects --- module version number and Redis integration to achieve unified management

Based on an article summarizes SpringBoot unified configuration of distributed micro-services, sub-environment deployment configuration. And a separate server modules (each provider is an independent micro-services), micro-service floor, Dubbo and integration providers, consumer configuration to achieve. This article will access the database and cache implementation. Project is structured as follows:

As can be seen from the figure, we want to build a buffer between service providers and consumers, an example to explain this to Redis. After the service access system cache, query interface to access a large quantity, we can cache the first time after the interfaces to get data from the server (provider) up and get behind the request comes first from the cache, if the cache exists returned directly, or call the provider (query the database) to obtain data, and added to the cache. This is the case of high concurrency, it will greatly enhance the efficiency effect service providers and reduce the pressure on the database.

Based on previous projects, we explore in depth a little bit today, starting with version management's start.

Version unified management

First, the sub-module version control

Take a look at the parent project pom configuration file, set the version number of each sub-module dependencies.

Let's look at the version settings for each module.

common module pom configuration

Service provider to the system module (lyn-sys) as an example, the same set of other modules.

The interface module pom lyn-sys

The interface module pom lyn-sys

Look at consumer lyn-web of dependence.

 

Why unified management? I wanted to have many years of experience in the development Coder must understand the importance of it, not much talk here.

Second, third-party Jar dependent control

Jar for third-party management, just to put these dependencies <dependencyManagement> to go inside, where only the external application of Jar, SpringBoot basically rely not on here.

SpringBoot basis dependent

 

Other third-party relies

其他模块如果需要用到这些第三方Jar,就在自己的模块对应去添加,这样可以较少其他模块对不必要的jar依赖,减小最终jar/war包的的大小。如Dubbo依赖,各个提供者的接口层(***-api)就不需要依赖这个服务,它仅提供给服务实现及消费者依赖。所以我们只需在各个服务模块的Service现实(***-service)及消费者模块(lyn-web)pom里依赖。

数据库连接实现

先在pom里引入数据库的相关依赖(属于第三方被管理的jar)

然后在各个提供者实现(***-service)模块的pom里依赖

这里Mybatis逆向生成和数据库连接池的依赖在lyn-common模块的pom里。提供者实现模块的properties配置

然后使用逆向工程执行生成实体、mapper及xml映射文件。这里以lyn-goods服务层的结构为例。

在对应提供者的***-api里写Service接口及在***-service里写对应的Service接口的实现代码,上面是goods-service的代码实现为例。其他模块类似,到此为止,数据库及基础代码已生成,接着编写对应的Controller服务,此处代码不讲。

Redis接入即实现

目前java操作redis的客户端有jedisLettuce。在springboot1.x系列中,其中使用的是jedis,但是到了springboot2.x使用的是Lettuce。 因为我们的版本是springboot2.1,所以今天使用的是Lettuce。,父级pom里依赖如下:

这里我使用的版本分别如下:

Redis的版本号:2.1.2.RELEASE

commons-pools的版本:2.5.0

jackson-databind版本号:2.9.6

接下来配置Redis,目录结构如下:

代码:

import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.CachingConfigurerSupport;import org.springframework.cache.annotation.EnableCaching;import org.springframework.cache.interceptor.KeyGenerator;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheConfiguration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.cache.RedisCacheWriter;import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;import java.lang.reflect.Method;
/** * <p>Redis缓存配置</p> * * @author lft * @version 1.0 * @date 2019/6/13 0013 * @since jdk1.8 */@Configuration@EnableCaching //启用缓存public class CacheConfig extends CachingConfigurerSupport {
@Bean @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } /** * 缓存配置管理器 */ @Bean public CacheManager cacheManager(LettuceConnectionFactory factory) { //以锁写入的方式创建RedisCacheWriter对象 RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory); //创建默认缓存配置对象 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); RedisCacheManager cacheManager = new RedisCacheManager(writer, config); return cacheManager; }
@Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer); //使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; }}

封装Redis缓存类:

public interface CacheService {    Object getCache(String key);    void setCache(String key, Object value);    void setCache(String key, Object value, long time);    <T> void setList(String key, List<T> os);    <T> void setList(String key, List<T> os, long time);    <T> List<T> getList(String key);    boolean isExistKey(String key);    void removeKey(String key);    Set<String> getMatchPrefixKey(String prefix);    Long getExpire(String key);}

实现代码:

@Service("cacheService")public class CacheServiceImpl implements CacheService {    private static Logger logger = LoggerFactory.getLogger(CacheServiceImpl.class);    @Autowired    private RedisTemplate<String, Object> redisTemplate;    @Autowired    private StringRedisTemplate stringRedisTemplate;    @Override    public Object getCache(String key) {        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();        return valueOperations.get(key);    }    @Override    public void setCache(String key, Object value) {        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();        valueOperations.set(key, value);    }    @Override    public void setCacheToRedis(String key, Object value, long time) {        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();        if(time > 0){            valueOperations.set(key, value, time, TimeUnit.SECONDS);        }else{            valueOperations.set(key, value);        }    }    @Override    public <T> void setList(String key, List<T> os) {        ListOperations<String,Object> listOperations = redisTemplate.opsForList();        for (Object o : os) {            listOperations.rightPush(key, o);        }    }    @Override    public <T> void setList(String key, List<T> os, long time) {        if(time > 0){            ListOperations<String,Object> listOperations = redisTemplate.opsForList();            for (Object o : os) {                listOperations.rightPush(key, o);                redisTemplate.expire(key, time, TimeUnit.SECONDS);            }        }    }    @Override    public <T> List<T> getList(String key) {        ListOperations<String, Object> listOperations = redisTemplate.opsForList();        List<T> o = null;        if (listOperations.size(key) > 0) {            o = (List<T>) listOperations.range(key, 0, -1);        }        return o;    }    @Override    public boolean isExistKey(String key) {        if(!StringUtils.isEmpty(key)) {            return redisTemplate.hasKey(key);        }        return false;    }    @Override    public void removeKey(String key) {        redisTemplate.delete(key);    }    @Override    public Set<String> getMatchPrefixKey(String prefix) {        if(!StringUtils.isEmpty(prefix)) {            Set<String> keys = stringRedisTemplate.keys(prefix + "*");            if(keys==null || keys.size() == 0){                return null;            }            return keys;        }        return null;    }    @Override    public Long getExpire(String key) {        return redisTemplate.getExpire(key);    }}

现在,在我们的消费者properties里配置redis。

接着我们在Controller里写一个测试接口

消费者(lyn-web)启动类添加包扫描,如下:

数据添加一条数据

然后启动四个提供者和一个消费者服务测试。

再通过Redis客户端看看缓存的数据。

本次讲了SpringBoot分布式微服务开发下的子模块及第三方jar的版本统一管理、数据库接入、Redis的配置及简单的缓存实现。到目前为止,一个简单的项目分布式电商项目已经基本成型,但如果要以正式项目开发使用,那还有很多需要处理和优化。比如Reids缓存,如何防止缓存被击穿和缓存雪崩的发生? 下期我们继续深入去讨论实现。

精彩文章推荐:

Spring Boot实现分布式微服务开发实战系列(一)

Spring Boot实现分布式微服务开发实战系列(二)

 

获取项目源代码,请扫码关注公众号,并发送Springboot获取。

Guess you like

Origin www.cnblogs.com/lyn20141231/p/11210065.html