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

    1
    2
    3
    4
    5
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(DelegatingWebMvcConfiguration.class)
    public @interface EnableWebMvc {}

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

    1
    2
    @Configuration
    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}
  • 接口编程方式

    version:3.1

    举例:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration

    1
    2
    3
    4
    5
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(EnableAutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {}

    org.springframework.boot.autoconfigure.EnableAutoConfigurationImportSelector

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Configuration
    @Profile("development")
    public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource() {}
    }

    @Configuration
    @Profile("production")
    public class JndiDataConfig {

    @Bean
    public DataSource dataSource() throws Exception {}
    }
    • method
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Configuration
    public class SomeConfig {

    @Bean("dataSource")
    @Profile("development")
    public DataSource standaloneDataSource() {}

    @Bean("dataSource")
    @Profile("production")
    public DataSource jndiDataSource() throws Exception {}
    }
    • 激活
    1
    2
    3
    4
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.getEnvironment().setActiveProfiles("development");
    ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
    ctx.refresh();
  • @Conditional 编程方式条件装配

    version:4.0

    举例:

    1
    2
    3
    4
    5
    @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.handlersspring.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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
//加载spring-boot-autoconfigure-1.5.6.RELEASE.jar!\META-INF\spring-autoconfigure-metadata.properties
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
//获取EnableAutoConfiguration里的exclude和excludeName-->LinkedHashMap-->AnnotationAttributes
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取依赖里所有的xx.jar!\META-INF\spring.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);
}
}

importFilter

调用ImportSelector部分

1
2
3
4
5
6
7
8
9
10
11
12
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);