likes
comments
collection
share

动手学习|如何创建自己的starter?

作者站长头像
站长
· 阅读数 19

相信现在的Java Boy在创建Web项目的时候,首选的必然是Spring Boot,Spring Boot是一个依靠大量注解实现自动化配置的全新框架。在构建Spring应用时,我们只需要添加相应的场景依赖,Spring Boot就会根据添加的场景依赖自动进行配置。

那么这个自动配置是怎么实现的?

原理

在使用spring boot来搭建一个项目时,只需要在pom文件中引入官方提供的starter依赖,就可以直接使用,免去了各种配置。 starter简单来说就是引入了一些相关依赖​​和一些初始化的配置​​

在平常的使用过程中,我们会发现starter依赖有两种命名形式:

  1. 官方的starter: spring-boot-starter-xxx​​ 例如:spring-boot-starter-web​
  2. 第三方的starter:xxx-spring-boot-starter​​ ​例如:mybatis-spring-boot-starter​​

我们以常见的mybatis-spring-boot-starter​​为例进行分析,先在项目中引入该依赖。

<dependency>
 	<groupId>org.mybatis.spring.boot</groupId>
 	<artifactId>mybatis-spring-boot-starter</artifactId>
 	<version>2.2.0</version>
 </dependency>

@SpringBootApplication

​@SpringBootApplication​​作为SpringBoot的入口注解,当然是最先需要注意到的。进入@SpringBootApplication​​内部,可以看到它是一个复合注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
...
}

英语好点的同学,可能一下子就注意到了其中的一个注解,没错,那就是@EnableAutoConfiguration​​,启动自动配置!多么见名知意的命名啊!好的,我们再点进去看一下!

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
...
}

嗯?有个注解不太对劲@Import(AutoConfigurationImportSelector.class)​​

引入了一个类?简单翻译下,自动配置引入选择器?点进去看看!

AutoConfigurationImportSelector.class

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

进去之后发现了这个方法!翻译一下方法名==》获取候选配置

欸,这个方法应该就是拿到配置类了!看注释应该是从META-INF/spring.factories这个文件中去读取的。

打个断点!调式一下!

调试

断点!启动!

动手学习|如何创建自己的starter?

哇,好多配置类,我们刚刚是不是引入了mybatis-spring-boot-starter​​?找一下看看

动手学习|如何创建自己的starter?

找到了!

也能在mybatis的包里面找到对应的spring.factories文件!

动手学习|如何创建自己的starter?

MybatisAutoConfiguration

点进这个配置类,可以看到它配置了两个@Bean。可以,自动配置原理明白了!

动手学习|如何创建自己的starter?

创建自己的starter

了解了上面自动配置的部分原理,我们可以来创建自己的starter了!

创建starter之前有个前置知识,那就是一个配置类如何读取配置文件中的信息!涉及到两个注解分别是

​@ConfigurationProperties​​和@EnableConfigurationProperties​​

服务类

首先创建一个简单的服务类

public class SimpleService {
    private String name;
    private String address;

    public SimpleService(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public String sayHello(){
        return "你好!我的名字叫" + this.name + ", 我来自" + this.address;
    }
}

配置属性类

创建个配置属性,读取配置文件中以simple为前缀的name,address值。

@Component
@ConfigurationProperties(prefix = "simple")
public class SimpleProperties {

    private String name;
    private String address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

自动配置类

创建自动配置类,把服务类注入容器

@Configuration
@EnableConfigurationProperties(SimpleProperties.class)
public class SimpleServiceAutoConfiguration {

    private SimpleProperties simpleProperties;

    /**
     * 以构造函数的方式注入配置
     * @param simpleProperties
     */
    public SimpleServiceAutoConfiguration(SimpleProperties simpleProperties) {
        this.simpleProperties = simpleProperties;
    }

    @Bean
    @ConditionalOnMissingBean
    public SimpleService simpleService(){
        return new SimpleService(simpleProperties.getName(), simpleProperties.getAddress());
    }
}

​@ConditionalOnMissingBean​​是一个条件装配注解,类似的还有

注解用途
@ConditionalOnBean仅当当前上下文中存在某个bean时,才会实例化这个bean
@ConditionalOnClass某个class位于类路径上,才会实例化这个bean
@ConditionalOnExpression当表达式为true的时候,才会实例化这个bean
@ConditionalOnMissingBean仅在当前上下文中不存在某个bean时,才会实例化这个bean
@ConditionalOnMissingClass某个class在类路径上不存在时,才会实例化这个bean
@ConditionalOnNotWebApplication不是web应用时,才会实例化这个Bean
@AutoConfigureAfter在某个bean完成自动配置后,才会实例化这个Bean
@AutoConfigureBefore某个bean完成自动配置前,才会实例化这个Bean

spring.factories

最后,别忘了在META-INF目录下创建一个spring.factories文件,并写类路径

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.qsw.SimpleServiceAutoConfiguration

OK!构建打包发布!

使用自己的starter

引入依赖

首先在springboot项目引入刚创建的starter依赖

<dependency>
	<groupId>com.qsw</groupId>
	<artifactId>mySpringStarter</artifactId>
	<version>1.0.0</version>
</dependency>

使用

随便找个controller注入一下!

@Autowired
SimpleService simpleService;

随便写个接口使用一下!

@GetMapping("/simpleService")
    public String simpleService(){
        return simpleService.sayHello();
    }

添加配置

在配置文件中添加如下配置

访问

动手学习|如何创建自己的starter?

总结

不错不错,自动配置简单原理明白了,也能写个starter了,说不定以后能写些东西让别人依赖一下(哈哈哈,开始做梦)。