Bean的装配升级
基于XML配置完成对象声明周期的描述和管理,随着项目管理规模不断扩大,XML的配置逐渐增多,难以管理。而将Spring升级到3.x后,提供了java config的能力,他可取代xml,通过java config完成对bean的注入。所以当前的spring framework以及spring boot已经基本不会看到xml配置的存在。
使用java config形式过后,只需要使用@Configure注解即可,其等同于XML的配置形式,而Configure一般会跟着@Bean组合,以此来将对象引入IOC容器,默认采用方法名 作为改Bean的id,跟在XML声明类似。
比如
@Configure
public class SpringConfig{
@Bean
public BeanDefine beanDefine(){
return new BeanDefine();
}
}
而某些配置,是根据框架“约定开发”原则的那些注解,如@ComponentScan对应的XML形式的<context:component-scan base-package=""/>,它会扫描指定包路径下带有@Service @Repository、@Controller、@Component等注解的类,将这些装载到IOC容器。
@Import对应XML形式的<import resource=""/>,导入其他的皮遏制文件。
问题:
但是一直全部使用java config来定义所有的bean装载,就会导致开发者需要过多关注开发这部分功能,比如通过java config整合mybatis,需要配置驱动、数据源、mybatis、事务管理器等等来集合一个技术组件需要的基础配置,而且每个开发者都要重复去做这些工作,并且运行和部署麻烦。因此spring boot诞生,拥有“约定优于配置”的软件设计范式,即根据springboot的某种约定开发。
Springboot的核心:
·自动装配,自动根据上下文完成bean的装配
·Starter组件,提供开箱即用的组件,其核心也是自动装配来实现
..................
springboot自动装配
自动装配是Starter的基础,是spring boot的核心,即将bean自动装载到IOC容器中。
样例
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
比如spring,在pom引入依赖,接着在application.properties进行配置redis信息即可开箱使用,在需要操作redis的类@Autowired RedisTesmplate,就可以使用,说明IOC容器已经存在RedisTemplate,这就是自动装配机制。
自动装配实现
通过@EnableAutoConfiguration注解来开启,该注解的声明在启动类注解@SpringBootApplication中,而@Enable在Spring3.1就已经支持该注解,主要作用是把相关组件装配到IOC容器中,是对java config的进一步完善,使得开发者使用spring framework减少了配置代码量,降低了使用的难度。比如@EnableScheduling。
基于java config的形式完成Bean的装载,则必须使用@Configuration注解以及@Bean注解,而@Enable注解实际是对@Configuration注解以及@Bean的封装,该@Enable注解中都会携带一个@Import注解,该Import对应的是bean封装配置,比如
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
配置类会根据@Import导入的配置类进行bean装载。
因此,使用@Enable注解后,Spring会解析到@Import导入的配置类,从而根据这个配置类的描述来实现Bean的装配,进而使得开发者减少代码配置,降低使用的难度。
@EnableAutoConfiguration开启自动装配
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage,该注解作用是使用了该注解的类所在的包以及子包下的所有组件自动扫描到IOC容器中。
再看@Import,一般@Import写的是Configuration以及bean的绑定,但此处是Seletor,实际上对多个Configuration的绑定,只要实现了ImportSelector接口的selectImports就可以实现将bean装配到IOC容器中。
改selelctImport中涉及到SpringFactoriesLoader去扫描factories,读取需要自动装配的配置类
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
AutoConfigurationImportSelector
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//配置文件 spring-autoconfigure-metadata.properties 获得自动装配类过滤相关的配置
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 源码点进去 spring.factories 这个文件存储了spring-boot所有默认支持的待自动装配候选类
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
总结SpringBoot自动装配原理:
· 通过@Import(AutoConfigurationImportSeletor)实现配置类的接入,不是传统意义的单个配置类装配
· AutoConfigurationImportSeletor实现了ImportSeletor接口,重写了方法selectImports,其用于实现选择性批量配置类的装配
· 该接口selectImports 中通过spring提供的SpringFactoriesLoader机制,扫描classpath路径下的META-INF/spring.factories,读取需要实现自动装配的配置类。
· 通过条件筛选的方式,把不符合条件配置移除,最终完成自动装配
spring.factories解读链接、spring-configuration-metadata.json的文件作用