栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

Spring Boot(四)@EnableXXX注解分析

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Boot(四)@EnableXXX注解分析

在学习使用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-bean     1.0-SNAPSHOT                           org.springframework             spring-context             5.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-bean    1.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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/235443.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号