Spring Boot中的自动装配
添加Starter依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
|
配置Redis数据源
1 2
| spring.redis.host=localhost spring.redis.port=6379
|
创建一个Controller
1 2 3 4 5 6 7 8 9 10 11 12
| @RestController public class TestController {
@Autowired RedisTemplate<String,String> redisTemplate;
@GetMapping("/test") public String test(){ redisTemplate.opsForValue().set("hello","Spring Boot"); return "success"; } }
|
这就是一个Spring Boot的装配机制,我们没有通过XML形式或者注解的形式把RedisTemplate注入到IOC容器,但是在Controller中可以直接通过@Autowired来直接注入使用。
自动装配是如何实现的?
1 2 3 4 5 6
| @SpringBootApplication public class TestDemoApplication { public static void main(String[] args) { SpringApplication.run(TestDemoApplication.class, args); } }
|
点进 @SpringBootApplication 这个注解去看下,@SpringBootApplication 注解主要由三个注解组成:@ComponentScan、@SpringBootConfiguration、**@EnableAutoConfiguration**。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @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 注解:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {}; }
|
在@EnableAutoConfiguration中最重要的是 **@Import({AutoConfigurationImportSelector.class}) **注解。@Import 将 AutoConfigurationImportSelector 这个类导入,点进这个类一看:
1 2 3
| public class AutoConfigurationImportSelector implements DeferredImportSelector,***{}
public interface DeferredImportSelector extends ImportSelector {}
|
实现了 DeferredImportSelector 接口,而 DeferredImportSelector 是继承 ImportSelector 类的。在 ImportSelector 中有个非常重要的方法:
1 2
| String[] selectImports(AnnotationMetadata var1);
|
如何利用 ImportSelector 装配类到IOC容器中去
首先创建一个类TestClass
1 2
| public class TestClass { }
|
创建一个ImportSelector的实现类,在实现类中把定义的Bean加入String数据中(因为ImportSelector可以实现批量装配,这里用一个来举例,多个逗号分隔就好),该Bean将会装配到IOC容器中
1 2 3 4 5 6 7
| public class TestImportSelector implements ImportSelector {
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{TestClass.class.getName()}; } }
|
为了模拟 EnableAutoConfiguration,我们自定义一个注解,通过@Import导入
1 2 3 4 5 6 7 8
| @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(TestImportSelector.class) public @interface EnableAutoImport { }
|
然后创建一个启动类,在启动类上使用@EnableAutoImport注解,即可通过getBean从IOC容器中得到TestClass实例
1 2 3 4 5 6 7 8 9
| @SpringBootApplication @EnableAutoImport public class ImportSelectorMain {
public static void main(String[] args) { ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(ImportSelectorMain.class,args); TestClass testClass = configurableApplicationContext.getBean(TestClass.class); } }
|
总结
自动装配的原理是通过主要组成@SpringBootApplication注解的@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解中的@EnableAutoConfiguration 中通过 @Import({AutoConfigurationImportSelector.class}) 导入的AutoConfigurationImportSelector实现的 selectImports 方法来实现批量装配的。
上面这个问题回答上了之后,有些面试官会深入问下面这个问题:
装配 application.properties/yml
在autoconfigure包下有个类 ServletWebServerFactoryAutoConfiguration,这个是SpringBoot 自动装配 Servlet 配置的类。
1 2 3 4 5 6 7 8 9 10 11 12
| package org.springframework.boot.autoconfigure.web.servlet; @Configuration( proxyBeanMethods = false ) @AutoConfigureOrder(-2147483648) @ConditionalOnClass({ServletRequest.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @EnableConfigurationProperties({ServerProperties.class}) @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class}) public class ServletWebServerFactoryAutoConfiguration {}
|
在SpringMVC中 @EnableConfigurationProperties 是一个非常熟悉的类,上面会将ServerProperties 类中的一些配置加载到当前类中,点进 ServletProperties:
1 2 3 4 5
| @ConfigurationProperties( prefix = "server", ignoreUnknownFields = true ) public class ServerProperties {}
|
@ConfigurationProperties 将配置文件的属性对应的值读入到 ServerProperties 这个类中,prefix=“server” 会读取 application.properties 中前缀为 server 的属性和值。