210630:springBoot自动配置-自定义start

一. 自动配置原理

Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中:

当然,自动配置原理的相关描述,官方文档貌似是没有提及。不过我们不难猜出,Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。那么自动配置原理一定和这个注解有着千丝万缕的联系!

1. @EnableAutoConfiguration

@SpringBootApplication是一个复合注解或派生注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration,翻译成人话就是开启自动配置,其定义如下:

而这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:

这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

二. 自动配置生效

每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

  • @ConditionalOnBean:当容器里有指定的bean的条件下。
  • @ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
  • @ConditionalOnClass:当类路径下有指定类的条件下。
  • @ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
  • @ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。

在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。

在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。

可能到目前为止还是有所疑惑,但面试的时候,其实远远不需要回答的这么具体,你只需要这样回答:

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

三. 什么是starter

Starter可以理解为一个可拔插式的插件,提供一系列便利的依赖描述符,您可以获得所需的所有Spring和相关技术的一站式服务。应用程序只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。用一句话描述,就是springboot的场景启动器。

1. 自定义starter

官方定义的starter命名都是spring-boot-starter-xxx,我们自己定义的一般都 xxx-spring-boot-starter,新建一个ruangh-id-gengerate-spring-boot-starter项目

导入springboot 包spring-boot-starter

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <!--主要是为了生成spring-configration-metadata.json文件,方便idea跳转-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

2. 创建映射配置类

定义一个映射配置新的的类IdProperties和LockieProperties,添加注解ConfigurationProperties("machine.id"),我们的配置文件以machine.id开头,比如mathine.id.name=boot-order,另外一个配置是已spring.lockie开头的

package com.ruangh.start.config;
@Data
@ConfigurationProperties("machine.id")
public class IdProperties {
    private String name;
}


package com.ruangh.start.config;
@Data
@ConfigurationProperties("spring.lockie")
public class LockieProperties {
    private String prefix;
    private String suffix;
}

3. 创建接口对应业务

IdService里面有个getId方法用来生成自定义的ID

package com.ruangh.start.service;

@Data
public class IdService {
    private IdProperties idProperties;

    /**
     * 获取id
     * @return
     */
    public String getId(){
        return idProperties.getName() + "-" + System.currentTimeMillis();
    }
}

package com.ruangh.start.service;

@Data
public class LockieService {
    LockieProperties lockieProperties;
    public String hello(String name){
        return lockieProperties.getPrefix() + "-" + name + "-" +lockieProperties.getSuffix();
    }
}

4. 创建配置类

  • @Configuration:配置类
  • @EnableConfigurationProperties():开启某属性类,里面封装的是属性信息,相当于@ConfigurationProperties加载application.properties里面的信息,并用@Component将类交由spring管理
  • @ConditionalOnClass():当这个类存在时,再进行下面的步骤,否则就不进行下面的步骤了
  • @AutoConfigureAfter():当自动配置完成后,再执行里面的类
  • @ConfigurationOnMissBean():当这个bean不存在时,再添加bean类
  • @Bean:添加bean类
package com.ruangh.start.configuation;

@Configuration
@EnableConfigurationProperties(IdProperties.class)
public class IdAutoConfiguation {
    @Autowired
    private IdProperties idProperties;
    @Bean
    public IdService idService(){
        IdService idService = new IdService();
        idService.setIdProperties(idProperties);
        return idService;
    }
}


package com.ruangh.start.configuation;

@Configuration
@EnableConfigurationProperties({LockieProperties.class})
public class LockieAutoConfiguration {
    @Autowired
    LockieProperties lockieProperties;
    @Bean
    public LockieService lockieService(){
        LockieService lockieService = new LockieService();
        lockieService.setLockieProperties(lockieProperties);
        return lockieService;
    }
}

5. 添加文件spring.factories

在resources目录下创建META-INF目录,并添加文件spring.factories。在这个文件中配置EnableAutoConfiguration,具体如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.ruangh.start.configuation.IdAutoConfiguation,\
  com.ruangh.start.configuation.LockieAutoConfiguration

6. 测测自定义的start

创建一个模块,在pom文件中增加依赖

<dependency>
    <groupId>com.ruangh.study</groupId>
    <artifactId>ruangh-id-gengerate-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

启动类上添加注解

@SpringBootApplication(scanBasePackages = "com.ruangh")

配置文件增加配置参数

添加测试类


@SpringBootTest
@ContextConfiguration(classes = DemoApplication.class)
public class DemoTest {
    @Autowired
    private IdService idService;
    @Autowired
    private LockieService lockieService;
    @Test
    public void testId(){
        String id = idService.getId();
        System.out.println("生成id--》"+id);
    }
    @Test
    public void testLockie(){
        System.out.println(lockieService.hello("小明"));

    }
}

运行一下查看结果,看到结果是我们想要的,至此我们自定义一个starter就成功了,总结一下就是要创建3个类1个配置文件,xxProperties,xxService,xxAutoConfiguation和spring.factories

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容