Spring Boot 核心特性之组件自动装配

时间:2022-06-08
本文章向大家介绍Spring Boot 核心特性之组件自动装配,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

摘要: Spring Boot 核心特性之组件自动装配

正文:

Spring Boot 核心特性之组件自动装配

Spring Framework 手动装配

模式注解装配

  • ex:@Component@Service@Configuration
  • 装配方式:<context:componet-scan>@ComponentScan

@Component是一种由Spring 容器托管的通用模式组件

Spring Framework 注解

场景

version

@Repository

数据仓储模式注解

2.0

@Component

通用组件模式注解

2.5

@Service

服务模式注解

2.5

@Controller

Web 控制器模式注解

2.5

@Configuration

配置类模式注解

3.0

  • 自定义模式注解

“派生性”(“基注解”<”派生注解”),可以参考以上注解实现自定义注解: @Component<@Repository<CustomRepository

@Enable 模块装配

Spring Framework从3.1开始支持@Enable 模块驱动 ,模块是指具备相同领域的功能组件集合组合成为一个独立的单元

举例:

@Enable 注解模块

模块说明

@EnableWebMvc

Web MVC模块

@EnableAsync

异步处理模块

@EnableAutoConfiguration

自动配置模块

@EnableEurekaClient

Eureka Client模块

注解驱动方式 version:3.0 举例: org.springframework.web.servlet.config.annotation.EnableWebMvc


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {}

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}

接口编程方式 version:3.1 举例: org.springframework.boot.autoconfigure.EnableAutoConfiguration

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

org.springframework.boot.autoconfigure.EnableAutoConfigurationImportSelector

public class EnableAutoConfigurationImportSelector
  extends AutoConfigurationImportSelector {}
public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
  @Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {}
}

条件装配

Spring Framework从3.1开始支持在Bean 装配时增加前置条件判断

  • @Profile 配置化方式条件装配 version:3.1 举例:
    • class
@Configuration
@Profile("development")
public class StandaloneDataConfig {
    @Bean
    public DataSource dataSource() {}
}
@Configuration
@Profile("production")
public class JndiDataConfig {
    @Bean
    public DataSource dataSource() throws Exception {}
}
@Configuration
public class SomeConfig {
    @Bean("dataSource")
    @Profile("development")
    public DataSource standaloneDataSource() {}
    @Bean("dataSource")
    @Profile("production")
    public DataSource jndiDataSource() throws Exception {}
}
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();

@Conditional 编程方式条件装配 version:4.0 举例:


@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {}
  • Spring-Boot的@Conditional:
    • ConditionalOnBean
    • ConditionalOnMissingBean
    • ConditionalOnClass
    • ConditionalOnMissingClass
    • ConditionalOnProperty
    • ConditionalOnJava
    • ConditionalOnWebApplication

Spring Boot 自动装配

激活:@EnableAutoConfiguration
Spring Boot 默认没有激活自动装配,存在@SpringBootApplication注解中

参考:org.springframework.boot.autoconfigure.AutoConfigurationImport

Selector#getCandidateConfigurations
 
 
配置:/META-INF/spring.factories

 规约文件,META-INFO指的是元信息目录,如spring.handlers、spring.schemas等

参考:org.springframework.core.io.support.SpringFactoriesLoader
 
实现:XxxAutoConfiguration
ex: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
 

Demo-Spring-Boot-Starter

Demo-Spring-Boot-Starter

源码分析

ImportSelector部分

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		try {
          	//加载spring-boot-autoconfigure-1.5.6.RELEASE.jar!META-INFspring-autoconfigure-metadata.properties
			AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
					.loadMetadata(this.beanClassLoader);
          	 //获取EnableAutoConfiguration里的exclude和excludeName-->LinkedHashMap-->AnnotationAttributes
			AnnotationAttributes attributes = getAttributes(annotationMetadata);
             //获取依赖里所有的xx.jar!META-INFspring.factories的value
			List<String> configurations = getCandidateConfigurations(annotationMetadata,
					attributes);
             //利用Set去重
			configurations = removeDuplicates(configurations);
             //排序->先按照字母排序->再按照Order排序(ex:MessageSourceAutoConfiguration#@AutoConfigureOrder)->然后根据@AutoConfigureBefore @AutoConfigureAfter(ex:WebSocketAutoConfiguration#@AutoConfigureBefore)排序
			configurations = sort(configurations, autoConfigurationMetadata);
             //对attributes封装与去重得到exclusions
			Set<String> exclusions = getExclusions(annotationMetadata, attributes);
			checkExcludedClasses(configurations, exclusions);
             //去掉exclusions里的XxAutoConf...
			configurations.removeAll(exclusions);
             //加载过滤器,对不满足ex:默认有一个OnClassCondition(org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationImportFilters(),见下图)的会排除掉()
			configurations = filter(configurations, autoConfigurationMetadata);
			fireAutoConfigurationImportEvents(configurations, exclusions);
			return configurations.toArray(new String[configurations.size()]);
		}
		catch (IOException ex) {
			throw new IllegalStateException(ex);
		}
	}

调用ImportSelector部分

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)
org.springframework.context.annotation.ConfigurationClassParser#processDeferredImportSelectors
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);