相信现在的Java Boy在创建Web项目的时候,首选的必然是Spring Boot,Spring Boot是一个依靠大量注解实现自动化配置的全新框架。在构建Spring应用时,我们只需要添加相应的场景依赖,Spring Boot就会根据添加的场景依赖自动进行配置。
那么这个自动配置是怎么实现的?
原理
在使用spring boot来搭建一个项目时,只需要在pom文件中引入官方提供的starter依赖,就可以直接使用,免去了各种配置。
starter简单来说就是引入了一些相关依赖和一些初始化的配置
在平常的使用过程中,我们会发现starter依赖有两种命名形式:
- 官方的starter: spring-boot-starter-xxx 例如:spring-boot-starter-web
- 第三方的starter:xxx-spring-boot-starter 例如:mybatis-spring-boot-starter
我们以常见的mybatis-spring-boot-starter为例进行分析,先在项目中引入该依赖。
xml
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
@SpringBootApplication
@SpringBootApplication作为SpringBoot的入口注解,当然是最先需要注意到的。进入@SpringBootApplication内部,可以看到它是一个复合注解
less
@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
less
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
...
}
嗯?有个注解不太对劲@Import(AutoConfigurationImportSelector.class)
引入了一个类?简单翻译下,自动配置引入选择器?点进去看看!
AutoConfigurationImportSelector.class
typescript
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这个文件中去读取的。
打个断点!调式一下!
调试
断点!启动!
哇,好多配置类,我们刚刚是不是引入了mybatis-spring-boot-starter?找一下看看
找到了!
也能在mybatis的包里面找到对应的spring.factories文件!
MybatisAutoConfiguration
点进这个配置类,可以看到它配置了两个@Bean。可以,自动配置原理明白了!
创建自己的starter
了解了上面自动配置的部分原理,我们可以来创建自己的starter了!
创建starter之前有个前置知识,那就是一个配置类如何读取配置文件中的信息!涉及到两个注解分别是
@ConfigurationProperties和@EnableConfigurationProperties
服务类
首先创建一个简单的服务类
java
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值。
java
@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;
}
}
自动配置类
创建自动配置类,把服务类注入容器
java
@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文件,并写类路径
ini
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.qsw.SimpleServiceAutoConfiguration
OK!构建打包发布!
使用自己的starter
引入依赖
首先在springboot项目引入刚创建的starter依赖
xml
<dependency>
<groupId>com.qsw</groupId>
<artifactId>mySpringStarter</artifactId>
<version>1.0.0</version>
</dependency>
使用
随便找个controller注入一下!
java
@Autowired
SimpleService simpleService;
随便写个接口使用一下!
java
@GetMapping("/simpleService")
public String simpleService(){
return simpleService.sayHello();
}
添加配置
在配置文件中添加如下配置
yml
simple:
name: 掘金
address: 极客时间
访问
总结
不错不错,自动配置简单原理明白了,也能写个starter了,说不定以后能写些东西让别人依赖一下(哈哈哈,开始做梦)。