相信现在的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了,说不定以后能写些东西让别人依赖一下(哈哈哈,开始做梦)。