利用SpringBoot自动装配原理自定义starter

在使用SpringBoot时候我们经常会碰到引入很多的starter的自动化配置,有了这些starter以后我们就可以很轻松的完成一个企业级的开发项目,很多小朋友就会对于starter很神奇,其实starter也都是基于Spring与SpringMVC开发出来的。其实在企业当中我们经常会自己开发starter,例如:我们在日常开发当中,可能会需要开发一个通用的模块,以供其他的工程进行复用,我们很直观的解决思路就是将该通用模块的代码拷贝到另一个工程当中,重新集成一遍,就会很麻烦,我们可以将业务之外的公共模块封装成一个个的starter,然后使用Maven的install将该模块导入远程自定义仓库当中,当不同的项目需要该模块的时候在pom中引用依赖就可以了,SpringBoot为我们完全自动装配,很舒服!!!!

核心原理:

核心原理其实就涉及到了SpringBoot的自动装配原理,其实starter的核心条件就是注解@Conditional,此注解在整个SpringBoot中占据了重要的地位。

定义自己的starter:

所谓的starter,其实就是一个普通的maven项目,因此我们首先引入需要的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>2.1.8.RELEASE</version>
</dependency>

配置完成以后,我们首先创建一个Properties类来接收application.properyies中注入的值,这里采用的是SpringBoot中的yaml格式对于属性进行赋值,yaml格式可以使得
属性的赋值更加的灵活:

@ConfigurationProperties(prefix = "Hello")
public class PersonProperties {
    private static final String DEFAULT_NAME = "LYC";
    private static final String DEFAULT_DESC = "学习代码小白";
    private String name = DEFAULT_NAME;
    private String desc = DEFAULT_DESC;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
}

application.properties:

Hello.name=LiuYC
Hello.desc=学习Java

紧接着PersonService定义如下:

public class PersonService {
    private String desc;
    private String name;
    public String sayHello() {
        return name + " say " + desc + " !";
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

接下来就是重中之重东西,自动配置类的定义,先撸一段代码:

@Configuration
@EnableConfigurationProperties(PersonProperties.class)
@ConditionalOnClass(PersonService.class)
public class PersonServiceAutoConfiguration {
    @Autowired
    PersonProperties personProperties;

    @Bean
    PersonService personService() {
        PersonService personService = new PersonService();
        personService.setName(personProperties.getName());
        personService.setDesc(personProperties.getDesc());
        return personService;
    }
}

我们来解释其中的代码的一些东西:

(1)@Configuration表明这是一个配置类
(2)@EnableConfigurationProperties注解是使我们之前配置的properties生效,让属性成功配置进入bean当中
(3)@ConditionOnClass表示当前项目的classPath下有PersonServce事才会生效

接下来我们需要回顾一下SpringBoot自动配置的原理:
我们先来看一看SpringBoot自动配置步骤:
步骤一:会使用到@SpringBootApplication:
我们会经常使用到SpringBoot来开发项目,其中最重要的就是主启动类,springBoot核心就在主启动类上的@SpringBootApplication注解:

步骤二:其中最重要的注解就是@EnableAutoConfiguration注解:

步骤三:对于该注解利用@Import向Spring容器注入了一个bean就是AutoConfigurationImportSelector:

步骤四:我们进入到该类去寻找一个重要的方法:
先找到getAutoConfigurationEntry方法然后是getCandidateConfigurations方法:

步骤五:我们进入getCandidateConfigurations中的loadFactoryNames方法:

步骤六:我们通过loadFactoryNames进入到loadFactories方法我们就会看到一个及其重要的参数:

classLoader.getResources会读META-INF/spring.factories文件中的EnableAutoConfiguration下的所有的配置,为什么是EnableAutoConfiguration下的所有的配置不是别的,那么就是跟loadFactoryNames参数有关了,其中传递的是EnableAutoConfiguration.class类:

步骤七:其实就涉及到了@Conditional注解,对于EnableAutoConfiguration配置中有众多的配置,但是我们不可能所有的配置都导入,我们会根据@Conditional注解选择
已经存在的配置进行导入,就会涉及getAutoConfigurationEntry接下来的代码:

这以上就是SpringBoot的自动配置流程,基于以上的原理,我们需要在我们项目下resources目录下创建一个名为META-INF的文件夹,也创建一个spring.factories的文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.lyc.mystarter.PersonServiceAutoConfiguration

在这里指定我们的自动化配置类的路径即可

本地安装:

如果是在公司当中时候我们通常会将刚写好的东西打包上传到Maven远程仓库当中以供其他的同事使用,我们在这里就将自动化配置类导入到本地仓库当中,我们点击IDEA右边的
Maven Project 中选择Lifecycle中的install:

然后我们就可以使用了,引入starter依赖:

<dependency>
    <groupId>org.lyc</groupId>
    <artifactId>mystarter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

我们可以自定义数据,在项目中创建application.properties:

Hello.name=LiuYC
Hello.desc=学习Java
@RunWith(SpringRunner.class)
@SpringBootTest
public class MystarterApplicationTests {

    @Autowired
    PersonService personService;
    @Test
    public void contextLoads() {
        System.out.println(personService.sayHello());
    }
}

我们便可以输出:

LiuYC  say  学习Java !
posted @ 2023-02-22 20:18  LycCj  阅读(193)  评论(0编辑  收藏  举报