手写一个Redis和Spring整合的插件

扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,阅读更多Spring源码分析文章。
微信公众号

1. 前言

在笔者的上一篇文章中(点击此处跳转查看)介绍了@Import注解的使用场景和原理,以及@EnableXXX注解的实现原理,这一篇文章将通过一个自定义的@Enable注解来实现一个Redis和Spring整合的插件。

  • 以前我们在Spring中整合Redis时(非SpringBoot和redis整合,看完本文,spring-boot-starter-data-redis这个包的原理也基本明白了),通常第一步是先引入redis客户端的jar包,第二步通过XML方式或者@Bean方式配置一个Jedis或者JedisCluster对象,第三步就是在代码中注入Jedis或者JedisCluter。这三步中,最为麻烦的是第二步。那么有没有一种方法能像@EnableXXX那样满足我们的需求呢?

2. 思路

要想完成Spring和redis的整合,我们就需要向Spring容器中添加一个Jedis或者JedisCluster这样的bean,然后还需要为redis的客户端设置属性,如连接地址,端口号等。那么我们可以自定义一个@EnableJedisClient或者@EnableJedisClusterClient注解,让这两个注解来达到我们的目的。

  • 自定义@EnableJedisClient和@EnableJedisClusterClient注解,让这两个注解来向容器中注册Jedis和JedisCluster。
  • 由于@Enable注解通常是结合@Import注解使用的,而@Import注解能帮助我们向容器中注册Bean,但是没办法为Bean的属性赋值,因为Import注解的处理只能干预BeanFactory的建造过程,不能参与Bean的创建过程,例如不能参与为Bean的属性赋值等操作。
  • 既然想要参与Bean的创建过程,为Bean的属性赋值,那么我们可以通过BeanPostProcessor来参与Bean的创建过程,创建JedisClientBeanPostProcessor和JedisClusterClientBeanPostProcessor类分别为Jedis和JedisCluster来设置属性,这两个类均实现了BeanPostProcessor接口。

3. 代码实现

先实现Jedis的整合,再实现JedisCluster的整合。前者是针对单机版的redis,后者是针对集群版的redis。

  • pom依赖
 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.8.RELEASE</version>
    <!-- 如果该项目是准备作为一个第三方插件的话,这里对spring的依赖范围最好指定为provided-->
    <!--<scope>provided</scope>-->
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.1.0</version>
</dependency>

3.1 @EnableJedisClient

  • 首先定义一个EnableJedisClient注解,在注解中通过Import注解导入了JedisClientImportRegistrar类。并且为EnableJedisClient添加了一个属性:namespace,添加该属性的目的是为了让项目中能同时引入多个redis。例如:在项目中需要同时连接两个不同的redis机器,那么这个时候就可以通过namespace来区分。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(JedisClientImportRegistrar.class)
public @interface EnableJedisClient {
   

    String namespace() default "default";
}
  • JedisClientImportRegistrar类实现了ImportBeanDefinitionRegistrar接口,重写了registerBeanDefinitions()方法,在方法中向Spring容器中注册了两个Bean,一个是Jedis,一个是JedisClientBeanPostProcessor后置处理器,注册该后置处理器是为了在后面Jedis初始化的过程中,为jedis设置连接地址,端口号等属性。
  • Jedis在容器中的beanName是 namespace + “Jedis”,namespace的值是从EnableJedisClient注解中获取到的。例如如下示例使用:那么此时的namespce的值为demo,如果不指定,则为default。
@EnableJedisClient(namespace = "demo")
public class AppConfig {
   
}
  • 源码如下
public class JedisClientImportRegistrar implements ImportBeanDefinitionRegistrar {
   

    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
   
        Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(EnableJedisClient.class.getName());
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(annotationAttributes);
        String namespace = attributes.getString("namespace");
        // 创建jedis的BeanDefinition,然后注册进容器中,beanName为namespace + "Jedis"
        BeanDefinitionBuilder jedisBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Jedis.class);
        AbstractBeanDefinition jedisBeanDefinition = jedisBeanDefinitionBuilder.getBeanDefinition();
        beanDefinitionRegistry.registerBeanDefinition(namespace+Jedis.class.getSimpleName(),jedisBeanDefinition);

        // 向容器注册一个Jedis的后置处理器,这是为了让后置处理器为Jedis的属性赋值
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(JedisClientBeanPostProcessor.class);
        beanDefinitionRegistry.registerBeanDefinition(JedisClientBeanPostProcessor.class.getSimpleName(),beanDefinitionBuilder.getBeanDefinition());
    }
}
  • JedisClientBeanPostProcessor实现了BeanPostProcessor和EnvironmentAware接口,实现EnvironmentAware接口是为了获取到配置文件中相关配置。重写了postProcessBeforeInitialization(),在该方法中,先读取了配置文件中的redis配置,然后为Jedis对象赋值。源码如下:
public class JedisClientBeanPostProcessor implements BeanPostProcessor,EnvironmentAware {
   

    private static String JEDIS_ADDRESS_PREFIX = "jedis.url"
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值