一般在项目的使用过程中,有时候为了减轻数据库的压力,从而将一部分数据缓存至Redis,但是随着业务量的增多。我们所需要的Redis服务器也会越来越多,就算不需要多个Redis数据源,那么在一个redis里面,切换不同的DB也是很麻烦的一件事情。
非AOP的一般的多数据源操作
在Redis的多数据源使用中,一般的方法是从配置文件中读取多个RedisProperties
,读取到配置文件之后,将RedisProperties
配置到RedisTemplate
,然后每次使用的时候就通过不同的Template
来调用Redis服务器。示例如下:
代码示例
Redis的配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @Configuration@Order(1) @Slf4j public class RedisConfig {
@Bean(name = "redis1") @Primary JedisConnectionFactory jedisConnectionFactory1(){ JedisConnectionFactory jedisConnectionFactory =new JedisConnectionFactory(); jedisConnectionFactory.setHostName("127.0.0.1"); jedisConnectionFactory.setPort(6379); jedisConnectionFactory.setPassword("123456"); jedisConnectionFactory.setDatabase(0); return jedisConnectionFactory; } @Bean(name = "redis2") @ConfigurationProperties("spring.redis.db1") JedisConnectionFactory jedisConnectionFactory2(){ JedisConnectionFactory jedisConnectionFactory =new JedisConnectionFactory(); jedisConnectionFactory.setHostName("127.0.0.1"); jedisConnectionFactory.setPort(6379); jedisConnectionFactory.setPassword("123456"); jedisConnectionFactory.setDatabase(2); return jedisConnectionFactory; }
@Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(jedisConnectionFactory1()); return template; } @Bean public RedisTemplate<String, Object> redisTemplate2() { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(jedisConnectionFactory2()); return template; } }
|
在上面的配置类里面,分别生成了两个JedisConnectionFactory
和两个RedisTemplate
,那么在使用的时候直接通过注解@Autowired
装配两个RedisTemplate
即可。
使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Service public class RedisCommonService { @Autowired RedisTemplate<String,Object> redisTemplate ;
@Autowired RedisTemplate<String,Object> redisTemplate2 ;
public void redis1Save(String key,String value){ redisTemplate.opsForValue().set(key,value); }
public void redis1Save2(String key,String value) { redisTemplate2.opsForValue().set(key, value); } }
|
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| RestController @RequestMapping("/") public class RedisCommonController {
@Autowired RedisCommonService redisCommonService;
@RequestMapping(value = "/redis1",method = RequestMethod.GET) public void redis1(){ redisCommonService.redis1Save("1","2"); }
@RequestMapping(value = "/redis2",method = RequestMethod.GET) public void redis2(){ redisCommonService.redis1Save2("2","3"); } }
|
然后在Redis的服务器上可以看到
可以看到两个数据分别写入到了不同的Db中
通过AOP的调用
通过AOP方法调用的基础是需要获取RedisTemplate
里面的JedisConnectionFactory
切面代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Around("execution(* com.somersames.service.redis.RedisService.*(..))") public void as(ProceedingJoinPoint joinPoint) throws Throwable { Field methodInvocationField = joinPoint.getClass().getDeclaredField("methodInvocation"); System.out.println(AopUtils.isAopProxy(joinPoint.getTarget())); methodInvocationField.setAccessible(true); ReflectiveMethodInvocation o = (ReflectiveMethodInvocation) methodInvocationField.get(joinPoint); Field h = o.getProxy().getClass().getDeclaredField("CGLIB$CALLBACK_0"); h.setAccessible(true); Object dynamicAdvisedInterceptor = h.get(o.getProxy()); Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); advised.setAccessible(true);
Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); Field re = target.getClass().getDeclaredField("redisTemplate"); re.setAccessible(true); Object re2= re.get(target);
Field d = re2.getClass().getSuperclass().getDeclaredField("connectionFactory"); d.setAccessible(true); Object[] objs = joinPoint.getArgs(); if(objs != null && objs.length !=0){ re.set(target,applicationContext.getBean((String) objs[0])); }
joinPoint.proceed(); }
|
RedisServer
1 2 3 4 5 6 7 8 9 10 11 12
| @Service public class RedisService {
@Autowired RedisTemplate<String,Object> redisTemplate;
public void aopRedis(String reditTemplate){ redisTemplate.opsForValue().set("a","a"); }
}
|
上述的代码也很简单,就是获取RedisServer
的aopRedis
方法的第一个参数,然后通过AOP将其替换为指定的Redis连接。测试如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @RestController @RequestMapping("/") public class AopController {
@Autowired RedisService redisService; @RequestMapping(value = "/redis",method = RequestMethod.GET) public void testCurd1(){ redisService.aopRedis("redisTemplate2"); } }
|
在AopController
里面,我想通过redisTemplate2
来执行aopRedis
方法。
但是在RedisService
里面,我们又是配置的是Redis连接数据源1,那么如何
RedisTemplate<String,Object> redisTemplate;
这个时候,我们可以通过切面,直接替换RedisTemplate的连接,从而获取指定的Redis连接,测试如下:
启动服务。
访问http://localhost:8080/redis
。
在不开启切面的情况下,可以看到直接访问的是0
号库,而开启切面之后,在调用RedisService
的时候,由于切面将RedisTemplate的connectionFactory
替换为2号库,所以访问结果如下:
本篇文章只是简单的介绍了下AOP的使用,下面几篇可能会基于这篇文章做一些AOP补充和增加一些其他功能。例如:添加Redis的AOP的自动切换,同时添加多个Redis数据源的自动注入,不再手动写Bean。
然后会可能基于Mongo的多数据源来讲解AOP的不同代理获取方式,和一般通用的获取方式