在学习使用springboot过程中,我们经常碰到以@Enable开头的注解,其实早在Spring3中就已经出现了类似注解,比如@EnableTransactionManagement、@ EnableWebMvc等,本文以@ EnableAutoConfiguration注解为例跟踪一下源码,分析实现过程。
@EnableAutoConfiguration注解@EnableAutoConfiguration注解主要功能是启用自动配,将classpath中所有包下的meta-INF/spring.factories配置文件中Key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的对应的符合自动配置条件的bean定义加载到Spring容器中。
查看源码可以看到@EnableAutoConfiguration是一个复合注解,自身也使用了其他注解,其中关键的是@import(AutoConfigurationimportSelector.class)
@EnableAutoConfiguration注解实现代码
@Retention(RetentionPolicy.RUNTIME) @documented @Inherited @AutoConfigurationPackage @import(AutoConfigurationimportSelector.class) public @interface EnableAutoConfiguration { //是否启用EnableAutoConfiguration注解,可在spring.factories中配置 spring.boot.enableautoconfiguration=true 或者false控制是否启用,默认为true String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; //通过class指定需要排除的自动配置类: Class>[] exclude() default {}; //通过类名指定需要排除的自动配置类: String[] excludeName() default {}; }查看AutoConfigurationimportSelector.class源码发现这个继承接口importSelector,所以截取其中最重要的一个方法
//实现接口importSelector的selectimports方法 ,该方法返回一个类名数组,数组中的类会被spring容器所托管起来
@Override public String[] selectimports(Annotationmetadata annotationmetadata) { //判断是否启用自动配置 if (!isEnabled(annotationmetadata)) { return NO_importS; } //加载spring内部自动配置的默认原属性 AutoConfigurationmetadata autoConfigurationmetadata = AutoConfigurationmetadataLoader .loadmetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationmetadata); //关键加载配置实现: // getCandidateConfigurations方法实现加载需要自动配置的类,内部通过使用Spring framework提供的SpringFactoriesLoader类,可以从classpath中搜索所有meta-INF/spring.factories配置文件,并读取配置 List configurations = getCandidateConfigurations(annotationmetadata, attributes); //去掉重复配置 configurations = removeDuplicates(configurations); Set exclusions = getExclusions(annotationmetadata, attributes); //检查需要排除的配置 checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); //spring.factories加载一个org.springframework.boot.autoconfigure.AutoConfigurationimportFilter过滤器OnClassCondition //通过该过//滤器判断现有系统是否引入了某个组件,如果有则进行相关配置. configurations = filter(configurations, autoConfigurationmetadata); //处理事件监听,具体监听器参见spring.factories中配置 fireAutoConfigurationimportEvents(configurations, exclusions); //返回最终需要托管的类 return StringUtils.toStringArray(configurations); } getCandidateConfigurations实现细节
//实现加载meta-INF/spring.factories配置文件,具体配置文件有什么类容,可以自行查看spring-boot-autoconfig-{version}.jar protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) { List configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in meta-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; } 上面分析了EnableAutoConfiguration的实现过程,下面通过一个示例演示如果从外部项目中读取自动配置
定义一个外部项目autoconfigbean
pom.xml
4.0.0 com.sl.autoconfig autoconfig-bean1.0-SNAPSHOT org.springframework spring-context5.0.7.RELEASE
定义需要自动注入的类
@Configuration public class TestConfig { @Bean public Configdemo configdemo(){ return new Configdemo(); } }
public class Configdemo { }添加resources/meta-INF/spring.factories配置文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration= configtest.Configdem
在springboot项目中引用autoconfigbean
com.sl.autoconfig autoconfig-bean1.0-SNAPSHOT
启动springboot项目可以通过System.out.println(context.getBeansOfType(Configdemo.class)) 查看是否已经注入到spring容器
@import注解上面的@EnableAutoConfiguration注解通过@import(AutoConfigurationimportSelector.class)实现了主要功能, 下面来看一下@import注解的作用
@import是spring framework提供的一个注解,是通过导入的方式把一个或多个bean或者bean的配置类注入到Spring容器中。
@import源码
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @documented public @interface import { Class>[] value(); }importSelector接口:selectimports方法返回一个class名称数组,该class会被spring容器所托管起来
public interface importSelector { String[] selectimports(Annotationmetadata importingClassmetadata); }importBeanDefinitionRegistrar接口:registerBeanDefinitions方法的参数有一个BeanDefinitionRegistry,该register可以用来向spring容器中注入bean
public interface importBeanDefinitionRegistrar { public void registerBeanDefinitions( Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry); }下面通过一个示例简单演示一下import注解通过{@link Configuration}, {@link importSelector}, {@link importBeanDefinitionRegistrar}三种方式注入
定义配置类
// importByConfiguration类定义的bean都将注入spring容器 public class importByConfiguration { @Bean public importTestClass createimportTestClass(){ return new importTestClass(); } }定义importSelector接口实现类,
//selectimports方法返回一个类数据,该数组中的类将会被spring容器所托管起来 public class importSelectorTest implements importSelector { @Override public String[] selectimports(Annotationmetadata importingClassmetadata) { return new String[]{ "com.sl.springbootdemo.EnableAnnotation.importTestClass" }; } }定义importBeanDefinitionRegistrar接口实现类
public class importBeanDefinitionRegistrarTest implements importBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) { // new一个RootBeanDefinition BeanDefinitionBuilder rootBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(importTestClass.class); //RootBeanDefinition rootBeanDefinition2 = new RootBeanDefinition(importTestClass.class); // 注册一个name为importTestClassInstance的bean registry.registerBeanDefinition("importTestClassInstance", rootBeanDefinition.getBeanDefinition()); //registry.registerBeanDefinition("importTestClassInstance",rootBeanDefinition2); } }输出到控制台:
@import({importByConfiguration.class, //导入bean配置类,则配置类中bean也将注入到spring容器 importSelectorTest.class, //importSelector接口方式 importBeanDefinitionRegistrarTest.class //importBeanDefinitionRegistrar接口方式 }) //@ComponentScan @SpringBootApplication public class SpringbootdemoApplication2 { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringbootdemoApplication2.class,args); System.out.println(context.getBeansOfType(importTestClass.class)); } }控制台打印信息如下:
{createimportTestClass=com.sl.springbootdemo.EnableAnnotation.importTestClass@2bc0cde, com.sl.springbootdemo.EnableAnnotation.importTestClass=com.sl.springbootdemo.EnableAnnotation.importTestClass@ac16e08, importTestClassInstance=com.sl.springbootdemo.EnableAnnotation.importTestClass@210a40d6}@import 注解并不是SpringBoot的功能,Spring 3.0开始就提供了@import这个注解,并在后续版本中逐渐完善,主要用来支持在Configuration类中引入其它的配置类,包括Configuration类, importSelector和importBeanDefinitionRegistrar的实现类。
原文出处:https://www.cnblogs.com/ashleyboy/p/9562052.html



