Spring Boot 自动装配初涉

前言

第一搭建Spring Boot项目的时候,我的内心是这样的,卧槽?!!这么简单!!完全不需要配置文件,只需要一个main方法就能跑起来。我陷入了沉思。。。经过一番学习,终于了解到了这要归功于Spring Boot的自动装配(Auto-configuration),也可以叫自动配置,但是叫装配好像高大上一点哈。

自动装配

Spring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added.

Spring Boot 官方文档上给了这么一个定义,初看并不容易理解。其实说白了,自动装配就是Spring Boot为我们自动创建了bean。

比如我们要在项目中使用redis

  • 我们能先添加redis的依赖

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
  • 在配置文件中添加redis 的配置

    spring.redis.host=localhost
    spring.redis.port=6379
    
  • 然后我们就能通过@Autowired引入RedisTemplate对redis 进行操做了

    @RestController
    public class RedisController {
    	@Autowired
    	private RedisTemplate<String, String> redisTemplate;
    
    	@GetMapping("/test")
    	public String test() {
    		redisTemplate.opsForValue().set("test", "test demo");
    		return "Test Demo";
    	}
    }
    

    这就是Spring Boot 的自动装配机制。我们并没有通过XML或者注解形式将RedisTemplate注入到IoC容器中,但是却可以直接使用。

    其实这是SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

    image-20210321175421076

@SpringBootApplication注解

在Spring Boot项目的启动类中都会有这个注解

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

从这个注解CTRL+鼠标左键进入后看到的主要部分就是下边这个

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM,
				classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ....
}

可以看到其实@SpringBootApplication就是由**@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan**三个注解组成的,完全可以把@SpringBootApplication 换成这三个,就像@RestController 可以换成@Controller 和@ResponseBody

@SpringBootConfiguration

@Configuration
public @interface SpringBootConfiguration {
}

可以看到**@SpringBootConfiguration 注解其实就是@Configuration注解**。@Configuration 用于修饰一个类,表示这个类的作用是配置Spring 容器,因为用@Bean 修饰这个类中的方法,方法的返回值作为一个bean装载到Spring 容器中。

@ComponentScan

这个注解就是指定了需要扫描package的根路径,默认扫描当前包及其字包下的注解。会将@Controller @Service @Component @Repository 等注解加载到IOC容器中。

@EnableAutoConfiguration

@EnableAutoConfiguration是这里最重要的注解,他用来自动载入Spring Boot应用的所有默认配置。自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中

private static final String[] NO_IMPORTS = new String[0];

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // <1>.判断自动装配开关是否打开
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
          //<2>.获取所有需要装配的bean
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

总结

Spring Boot自动装配的原理并不是非常复杂,其实背后的主要原理就是条件注解。 当我们使用@EnableAutoConfiguration注解激活自动装配时,实质对应着很多XXXAutoConfiguration类在执行装配工作,这些XXXAutoConfiguration类是在spring-boot-autoconfigure jar中的META-INF/spring.factories文件中配置好的,@EnableAutoConfiguration通过SpringFactoriesLoader机制创建XXXAutoConfiguration这些bean。XXXAutoConfiguration的bean会依次执行并判断是否需要创建对应的bean注入到Spring容器中。 在每个XXXAutoConfiguration类中,都会利用多种类型的条件注解@ConditionOnXXX对当前的应用环境做判断,如应用程序是否为Web应用、classpath路径上是否包含对应的类、Spring容器中是否已经包含了对应类型的bean。如果判断条件都成立,XXXAutoConfiguration就会认为需要向Spring容器中注入这个bean,否则就忽略。

参考