SpringBoot 自定义starter组件

水深无声 2023-05-28 06:43 37阅读 0赞

自定义一个starter一般需要经过以下几个过程

步骤

完整项目会以免积分附件形式发布,有兴趣的可以down下来跟着试一下
或使用码云地址:https://gitee.com/master336/demo-spring-boot-starter

前提

SpringBoot项目开启自动配置 @EnableAutoConfiguration(默认开启了,参见@SpringBootApplication)

1. 创建项目

这一步就一个关注点,项目名建议**-spring-boot-starter,据说是springboot官方建议的命名方式,有只要此建议地址的朋友可以留言以方便补充。这里给两个常用starter命名示例
在这里插入图片描述
在这里插入图片描述

2. maven依赖倒入

首先再次提一下命名问题,再看一眼上一步。
引入依赖,核心依赖就一个,目的是为了使用其注解

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-autoconfigure</artifactId>
  5. <version>2.2.5.RELEASE</version>
  6. </dependency>
  7. </dependencies>

3. 定义自动装配属性对应的配置类(非必须)

如果有允许用户自定义配置的地方,可以借助Configurationproperties注解轻松将配置转换为Java对象,方便注入使用。

  1. import org.springframework.boot.context.properties.ConfigurationProperties;
  2. @ConfigurationProperties(prefix = "demo")
  3. public class DemoProperties {
  4. private String name = "default name";
  5. private Integer age = 18;
  6. public String getName() {
  7. return name;
  8. }
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. public Integer getAge() {
  13. return age;
  14. }
  15. public void setAge(Integer age) {
  16. this.age = age;
  17. }
  18. }

简单说一下ConfigurationProperties这个注解,这个用于声明该类为配置类,prefix声明配置项的开头,如上代码中,配置装载的是以demo开头的配置,yml(或peopreties)文件配置如下:

  1. demo:
  2. name: 张三
  3. age: 22

注意: Springboot本着”约定大于配置”原则,请合理设置默认值。

4. 定义需要交由Spring管理的Bean类及其具体实现方法

通过定义已上一步配置类为入参的构造方法获取配置类信息,用以获取可由用户自定义的一些属性值。

  1. import cn.com.demo.autoconfigure.properties.DemoProperties;
  2. public class DemoService {
  3. private DemoProperties demoProperties;
  4. public DemoService(DemoProperties demoProperties) {
  5. this.demoProperties = demoProperties;
  6. }
  7. public void printProperties(){
  8. if ( demoProperties == null){
  9. System.out.println("null propertoes");
  10. }else {
  11. System.out.println("name: "+demoProperties.getName() +"\t age:"+demoProperties.getAge());
  12. }
  13. }
  14. }

看到这个类可能存在疑问:

  1. 这个类不是要注册成Bean交由Spring管理吗?为什么没有定义声明@Component@Bean等之类的标签标注一下?
    其实这个问题是这样的,Springboot中声明Bean除了要使用Spring中符合要求的注解外,还需要定义@Configuration(不然会因为没在扫描路径(ComponentScan)下导致无法被Spring管理,为什么不会一会儿再第6步里说明),用于告诉SpringBoot你这是个Bean配置管理类,这样一来就成了下一步要干的事了,这里把Bean的声明和实现分开,更清晰的管理自己的Bean。

另外:值得注意的是@Configuration 标注的也是一个Bean~,只是有特殊含义,其在某种情况下也是可以被其他方案代替的(参见@Configuration)。

5. 定义Configuration类完成Bean声明

  1. 起始就是完成Beannew过程,即告诉Spring这个Bean是怎么来的。
  2. import cn.com.demo.autoconfigure.properties.DemoProperties;
  3. import cn.com.demo.autoconfigure.service.DemoService;
  4. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  5. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. @Configuration
  9. @EnableConfigurationProperties(DemoProperties.class)
  10. public class DemoAutoConfigure {
  11. /**属性自动从Springboot配置文件装配,DemoProperties里声明前缀*/
  12. private DemoProperties demoProperties;
  13. /* 如果无需(或不允许)用户修改配置,这里可以使用默认构造(简单来说就是别写任何构造方法了) public DemoAutoConfigure(){ System.out.println("init no patam "); }*/
  14. public DemoAutoConfigure(DemoProperties demoProperties) {
  15. this.demoProperties = demoProperties;
  16. }
  17. /** * 自定义Bean以供外部使用 * @return */
  18. @Bean
  19. @ConditionalOnMissingBean
  20. public DemoService demoService(){
  21. return new DemoService(demoProperties);
  22. }
  23. }

@Bean用户告诉容器这是一个Bean,方法名为BeanName(可以通过name指定)
@ConditionalOnMissingBean 如果容器中没有这个Bean,会通过此定义创建改Bean,即如果不需要再次封装,可以使用这个Bean进行操作(相当于默认处理Bean,类似druid里定义datasource这个Bean一样,可参见:com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure)

6. 编写META-INF/spring.factories文件定义自动配置类

即告诉Spring自动装配的类路径,内容如下:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. cn.com.demo.autoconfigure.DemoAutoConfigure

这里有个疑问:为什么已经配置了@Configuration还要整个spring.factories文件呢?
这个问题在于@Configuration会不会生效的问题,如果@Configuration所在类在你的项目扫描路径下,就不需要配置,如果不在,那就需要配置(@Configuration)。如果你作为一个组件发布,你无法保证ComponentScan能扫描到你的组件,所以就有了配置这个的方法。

spring.factories文件的加载在:
new SpringApplication()
–> setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
–>private Collection getSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, Object… args)
–>Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
–>private static Map loadSpringFactories(@Nullable ClassLoader classLoader)
–>private static Map loadSpringFactories(@Nullable ClassLoader classLoader)
spring.factories中配置生效(Bean被创建)是在:
SpringApplication.refreshContext(context),过程比较复杂,感兴趣可以深入跟踪一下。

以上为执行过程,对照代码可能更容易懂~

7. 打包发布

如果本地测试的话:

  1. mvn clean compile install

即可被本地其他项目以来,如果需要发布仓库被别人共用的话请使用deploy

8. 需要的项目上引入依赖即使用

  1. <dependency>
  2. <groupId>cn.com.demo</groupId>
  3. <artifactId>demo-spring-boot-starter</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. </dependency>

作为一个Bean正常注入即可使用

  1. // 需要用哪个注入那个即可
  2. @Resource
  3. DemoService demoService;
  4. // 一般咱们不用这个
  5. @Resource
  6. DemoAutoConfigure demoAutoConfigure;

发表评论

表情:
评论列表 (有 0 条评论,37人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SpringBoot定义starter

    SpringBoot自定义starter 按照一般的模式, 我们创建一个启动器, 但是该启动器只用来做依赖导入 然后创建另外一个自动配置模块, 用来定义自动配置 启动