前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何实现一个自定义的starter

如何实现一个自定义的starter

作者头像
路行的亚洲
发布2021-04-28 14:26:35
9300
发布2021-04-28 14:26:35
举报
文章被收录于专栏:后端技术学习

如果要实现一个自定义的starter,首先需要引入两个依赖spring-boot的jar包:spring-boot-autoconfigure和spring-boot-configuration-processor:

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

在resource中新建META-INF文件夹,创建spring.factories,比如:

代码语言:javascript
复制
#定义自动装配的类=>RedissonCofiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.study.configuration.RedissonConfiguration

同时你的starter的名称:

代码语言:javascript
复制
<groupId>com.study</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>1.0.0</version>

同时需要基于存在某种条件才进行装配时,可以使用@ContionOnClass.

代码语言:javascript
复制
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {

    Class<?>[] value() default {};

    String[] name() default {};

}

从源码上看,只有在classpath下能找到你需要的conditionOnClass类才会构建这个bean。比如你想写一个redisson的自动装配:

代码语言:javascript
复制
/**
 * redisson配置:配置、自动配置、配置条件
 */
@Configuration
@EnableConfigurationProperties(value = RedissonProperties.class)
@ConditionalOnClass(RedissonProperties.class)
public class RedissonConfiguration {

}

使用@ConditionOnMissingBean:

代码语言:javascript
复制
@ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常,以此来告诉开发人员。

通常的相关注解:

代码语言:javascript
复制
@ConditionalOnBean // 当给定的bean存在时,则实例化当前Bean
@ConditionalOnMissingBean // 当给定的bean不存在时,则实例化当前Bean
@ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean
@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean

创建RessionClient的方式:基于对应的方式创建客户端,因为Ression有很多模式,哨兵、主从、单例、集群、云托管模式,拿到对应的模式的配置后,创建对应的客户端bean:

代码语言:javascript
复制
@Bean
@ConditionalOnMissingBean(RedissonClient.class)
public RedissonClient redissonClient() {
   // 创建Redisson客户端对象对象
   return Redisson.create(config);
}

同时还需要一些特定的信息:

代码语言:javascript
复制
相关bean:lockAop分布式锁、MQAop 发送AOP、RedissonBinary 操作对象二进制、RedissonObject操作对象、RedissonCollection操作集合、RedissonClient重要,此时就可以基于@ConditionOnMissBean的方式进行创建,从而实现自定装配。此时可以基于分布式锁Aop切面来做拦截,对分布式锁进行增强操作,也即对当前拿到的锁信息进行判断。对锁的模式进行判断,如果当前的锁模式为自动的,则此时根据你所的key进行判断,如果keys的长度>1,则使用红锁,否者使用可重入式锁。
如果锁模式不是 联锁 && 红锁 &&长度大于1,此时会抛异常

如果是公平锁,则直接处理,如果是红锁,则需要变量keys,对锁进行添加到RLock中,对锁进行遍历,添加到数组中,然后将其重新赋值给红锁,否者放入到可重入式锁,或者读锁或者写锁中。执行aop.

那可自动装配又是怎样实现的呢?其关键在于@SpringBootApplication这个注解上,这个组件是一个组合注解:

代码语言:javascript
复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //springboot配置注解
@EnableAutoConfiguration  //可以自动注入配置
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) //进行组件扫描,同时排掉过滤信息
public @interface SpringBootApplication {
  // 省略代码,主要包含的方法:排掉特定自动注入的配置,通过名称或者类方式,进行基包扫描、或者classes、代理bean方法等
}

同时我们可以看到SpringBootApplication里面的所有方法,都使用了一个注解@AliasFor。那这个组件有什么用呢?这个注解用于桥接到其它注解,该注解的属性中指定的所桥接的注解类,减少用户使用多注解带来的麻烦。

其关键就在@EnableAutoConfiguration这个注解中,这个注解里面有一个@Import注解,里面这个类自动配置导入选择器类:

代码语言:javascript
复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

   Class<?>[] exclude() default {};
 
   String[] excludeName() default {};

}

如果我们想使用xml进行配置的话,此时在springboot启动的时候可以使用@Import将配置进行导入,实现配置注入的目的。而AutoConfigurationImportSelector实现了DeferredImportSelector延迟导入选择器,也即ImportSelector的子类。那ImportSelector里面有什么方法呢?里面有两个方法一个是选择导入的方法、一个是排掉过滤的方法,下面可以看到选择导入方法的入参是导入类元数据。

代码语言:javascript
复制
public interface ImportSelector {
   
    String[] selectImports(AnnotationMetadata importingClassMetadata);
}

那这个选择导入的过程又是怎样的呢?

SpringFactoriesLoader加载器加载指定ClassLoader下面的所有的META-INF/spring.factories文件,并将文件解析内容存在Map<string,list>中。然后通过loadFactoryNames传递过来的class的名称从map中获取该类的配置列表。通过Set集合进行去重操作。执行过滤组件操作,而这些操作都是在AutoConfigurationImportFilter接口下的组件实现的,也即FilterSpringBootCondition实现抽象类的。下面有OnBeanCondition、OnClassCondition、OnWebApplicationCondition的getOutcomes方法。</string,list

执行fire操作,fireAutoConfigurationImportEvents,此时会执行事件注册。

而其重要的方法就是getAutoConfigurationEntry就是自动装配的重点。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端技术学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云托管 CloudBase Run
云托管 CloudBase Run(Tencent CloudBase Run,TCBR)是由云开发提供的新一代云原生应用引擎(App Engine 2.0),支持托管任意语言和框架编写的容器化应用。和云开发其他产品(云函数、云数据库、云存储、扩展应用、HTTP 访问服务、静态网站托管等)一起为用户提供云原生一体化开发环境和工具平台,为开发者提供高可用、自动弹性扩缩的后端云服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档