spring的自动装配注解,spring boot注解详解

  spring的自动装配注解,spring boot注解详解

  

目录

1.自动化装配介绍2.Spring Boot自动化配置用户模式图解3.Spring Boot自动化配置核心注解分析3.1 @继承3.2 @ spring boot configuration 3.3 @ enable auto configuration 3.4 @ components can 3.5 @ configuration properties scan 3.6 @ auto configuration import selector 3.7 @ auto configuration packages 4 .总结

 

  

1. 自动化装配介绍

Spring Boot针对手动音量调节做了大量封装,简化开发者的使用,内部是如何管理资源配置,比恩配置,环境变量配置以及启动配置等?实质是跳羚做了大量的注解封装,比如@SpringBootApplication,同时采用春天4框架的新特性@有条件基于条件的豆创建管理机制来实现;

 

  实际的工作场景中是复杂多样的, 有些项目需要不同的组件, 比如REDIS、MONGODB作缓存;兔子q,卡夫卡作消息队列;有些项目运行环境不同, 比如JDK7、JDK8不同版本,面对众多复杂的需求, 又要做到最大化支持,Spring Boot是如何管理实现的, 这就依赖有条件的功能,基于条件的自动化配置。

  

2. Spring Boot 自动化配置UML图解

跳靴应用是我们所常用熟知的注解, 它是一个组合注解, 依赖多个注解,共同实现Spring Boot应用功能, 以下为所有依赖的用户模式图解,我们围绕这些注解深入研究,看下具体的实现。

 

  

3. Spring Boot 自动化配置核心注解分析

跳靴应用注解:

 

  @Target(ElementType .TYPE)@ Retention(保留策略.运行时)@ documentated @ Inherited @ spring boot configuration @ enable auto configuration @ components can(exclude filters={ @ Filter(type=Filter type .CUSTOM,classes=typeexcludefilter。class),@Filter(type=FilterType .CUSTOM,classes=autoconfigurationexcludefilter。class)})@ configurationpropertiescanpublic @ interface spring boot应用程序{/* * *需要排除的自动化配置, 根据类名进行排除, 比如蒙戈自动配置,jparepositoriesauto configuration等*/@ alias for(annotation=启用自动配置。类)类?[]排除()默认{ };/** * 需要排除的自动化配置, 根据名称进行排除*/@ alias for(annotation=启用自动配置。class)String[]排除名称()默认值{ };/** * 指定需要扫描的包路径,参数填写包名*/@ alias for(annotation=components can。class,attribute= base packages )String[]scanbase packages()default { };/** * 指定需要扫描的包路径*/@ alias for(annotation=components can。Class,attribute= base package classes )Class。[]scanbasecacapkageclasses()default { };/** * Bean方法的动态代理配置, 如果没有采用工厂方法, 可以标记为假的,采用字节码生成代理.class */@ alias for(annotation=configuration。class)布尔代理bean方法()默认为真实}

  

3.1 @Inherited

Java。郎。注释。@继承注解,从包名可以看出为爪哇岛开发工具包自带注解, 作用是让子类能够继承父类中引用在…里

 

  herited的注解, 但需注意的是, 该注解作用范围只在类声明中有效; 如果是接口与接口的继承, 类与接口的继承, 是不会生效。

  

 

  

3.2 @SpringBootConfiguration

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configuration(proxyBeanMethods = false)public @interface SpringBootConfiguration {/** * Bean方法的动态代理配置 */@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;}

这是配置型处理注解, 可以看到内部源码引用了@Configuration注解,

 

  自身没有太多的实现, 那为什么还需要再包装?官方给出的解释是对Spring的@Configuration的扩展,

  用于实现SpringBoot的自动化配置。proxyBeanMethods属性默认为true, 作用是对bean的方法是否开启代理方式调用, 默认为true, 如果没有采用工厂方法,可以设为false, 通过cglib作动态代理。

  

 

  

3.3 @EnableAutoConfiguration

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration { // 设置注解支持重载的标识String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";/** * 排除自动化配置的组件, 如MongoAutoConfiguration, JpaRepositoriesAutoConfiguration等 */Class<?>[] exclude() default {};/** * 排除自动化配置的组件, 根据名称设置 */String[] excludeName() default {};}

用于管理开启Spring Boot的各种自动化配置注解, 如datasource, mongodb, redis等,也是spring-boot-autoconfigure工程的核心注解。

 

  AutoConfigurationPackage

  它的主要作用是扫描主程序同级及下级的包路径所有Bean与组件注册到Spring Ioc容器中。

  Import

  它可以把没有声明配置的类注册到Spring Ioc容器中管理引用。 导入的AutoConfigurationImportSelector类实现BeanClassLoaderAware、ResourceLoaderAware、EnvironmentAware等接口, 管理类装载器, 资源装载器及环境配置等, 是一个负责处理自动化配置导入的选择管理器。在下面【@AutoConfigurationImportSelector剖析】进行详解。

  

 

  

3.4 @ComponentScan

这是我们在Spring下面常用的一个注解,它可以扫描Spring定义的注解, 如@Componment, @Service等, 常用的属性有basePackages扫描路径,includeFilters包含路径过滤器, excludeFilters排除路径过滤器,lazyInit是否懒加载等,能够非常灵活的扫描管理需要注册组件。

 

  

 

  

3.5 @ConfigurationPropertiesScan

作用是扫描指定包及子包路径下面的ConfigurationProperties注解,管理工程配置属性信息。主要属性为basePackages扫描路径, 支持多个路径,数组形式;basePackageClasses属性也可以具体到包下面的类,

 

  支持多个配置。

  

 

  

3.6 @AutoConfigurationImportSelector

AutoConfigurationImportSelector 实现 DeferredImportSelector、BeanClassLoaderAware、ResourceLoaderAware、BeanFactoryAware、EnvironmentAware、Ordered 接口, 为自动化配置的核心处理类, 主要负责自动化配置规则的一系列处理逻辑:

 

  

/** * {@link DeferredImportSelector} to handle {@link EnableAutoConfiguration * auto-configuration}. This class can also be subclassed if a custom variant of * {@link EnableAutoConfiguration @EnableAutoConfiguration} is needed. * * @author Phillip Webb * @author Andy Wilkinson * @author Stephane Nicoll * @author Madhura Bhave * @since 1.3.0 * @see EnableAutoConfiguration */public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { ... }}

讲解几个技术点:

 

  getCandidateConfigurations方法

  

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> 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;}

该方法是获取所有Spring Boot声明定义的自动化配置类。

 

  看下具体有哪些信息:

  

 

  这些实际是配置在Spring-boot-autoconfigure工程下的META-INF/spring.factories文件中:

  

 

  看到这里, 我们应该可以明白,为什么AOP,RABBIT,DATASOURCE, REIDS等组件SPRING BOOT都能帮我们快速配置实现,其实它内部遵循SPI机制, 已经把自动化配置做好了封装。

  AutoConfigurationGroup类

  它是AutoConfigurationImportSelector的内部类,实现了DeferredImportSelector.Group、BeanClassLoaderAware、BeanFactoryAware、ResourceLoaderAware接口,是一个重要的核心类。主要作用是负责自动化配置条目信息的记录, 排序,元数据处理等。它通过getImportGroup方法获取返回,该方法实现DeferredImportSelector的接口。

  

private static class AutoConfigurationGroupimplements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware { // 记录注解的元数据private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();// 记录自动化配置条目,放入集合private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>(); // 设置bean的类加载器private ClassLoader beanClassLoader; // 设置bean工厂信息private BeanFactory beanFactory; // 设置资源加载器信息private ResourceLoader resourceLoader; // 设置自动化配置的元数据记录private AutoConfigurationMetadata autoConfigurationMetadata;...}

属性主要定义了一些自动化配置类目信息、BEAN工厂、类和资源加载器信息。entries条目有22条, 具体内容如下:

 

  

 

  里面是主要的自动化配置类的元数据信息,autoConfigurationEntries属性就是具体的自动化配置条目。这些主要自动化类配置是Spring boot帮助我们实现mvc的核心功能,如请求分发,文件上传,参数验证,编码转换等功能。还有一部分是定制条件自动化配置类,

  autoConfigurationMetadata元数据内容较多, 包含各种组件, 根据环境配置和版本不同, 这里可以看到共有705个:

  

 

  由于Spring Boot支持众多插件,功能丰富, 数量较多; 这里存在些疑问, 这里面的元数据和上面的entries条目都是AutoConfiguration自动化配置类, 那有什么区别? 其实这里面的, 都是基于条件的自动化配置。

  我们就拿KafkaAutoConfiguration来看:

  

 

  可以看到注解ConditionalOnClass,意思是KafkaAutoConfiguration生效的前提是基于KafkaTemplate类的初始化成功,这就是定制条件,也就是基于条件的自动化配置类,虽然有七百多个,但其实是根据工程实际用到的组件,才会触发加载对应的配置。 有关Conditional基于条件的自动化配置实现原理, 在下面我们再作深入研究。

  继续看AutoConfigurationImportSelector内部类的selectImports方法:

  

@Overridepublic Iterable<Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) { return Collections.emptyList(); } // 将所有自动化条目根据配置的Exclusion条件作过滤, 并转换为SET集合 Set<String> allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet()); // SET集合, 记录所有需要处理的自动化配置 Set<String> processedConfigurations = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream) .collect(Collectors.toCollection(LinkedHashSet::new)); // 两个SET, 做交集过滤, 排除不需要的配置 processedConfigurations.removeAll(allExclusions); // 最后进行排序处理 return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList());}

该方法是针对autoConfigurationEntries自动化配置条目做过滤,根据指定的排除规则处理;再根据设置的启动的优先级做排序整理。从代码中可以看到,先获取所有的allExclusions排除配置信息,再获取所有需要处理的processedConfigurations配置信息,然后做过滤处理,最后再调用sortAutoConfigurations方法,根据order顺序做排序整理。

 

  AutoConfigurationImportSelector内部类的process方法:

  

@Overridepublic void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); // 获取自动化配置条目 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata); // 记录获取的条目 this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { // 放入成员变量entries中 this.entries.putIfAbsent(importClassName, annotationMetadata); }}

该方法是扫描获取autoConfigurationEntries自动化配置条目信息。

 

  annotationMetadata参数:

  为注解元数据,有也就是被@SpringBootApplication修饰的类信息,在这里就是我们的启动入口类信息。

  deferredImportSelector参数:

  通过@EnableAutoConfiguration注解定义的 @Import 的类,也就是AutoConfigurationImportSelector对象。根据配置,会加载指定的beanFactory、classLoader、resourceLoader和environment对象。

  AutoConfigurationImportSelector内部类的getAutoConfigurationEntry方法:

  

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) { // 1、判断是否开对应注解if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} // 2、获取注解定义的属性AnnotationAttributes attributes = getAttributes(annotationMetadata); // 3、获取符合规则的Spring Boot 内置的自动化配置类, 并做去重处理List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);configurations = removeDuplicates(configurations); // 4、做排除规则匹配, 过滤处理Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = filter(configurations, autoConfigurationMetadata); // 5、触发自动导入处理完成事件fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}

该方法主要作用是获取Spring Boot 内置的自动化条目, 例AopAutoConfiguration等,该方法会调用上面讲解的getCandidateConfigurations方法。 主要步骤逻辑如下:

 

  判断是否开启元注解扫描, 对应属性为spring.boot.enableautoconfiguration,默认情况下, 是开启自动配置。获取定义的注解属性, 跟踪内部源码, 里面会返回exclude和excludeName等属性。获取符合规则的Spring Boot 内置的自动化配置, 并做去重处理,也就是我们上面讲解的getCandidateConfigurations方法, 从中我们就可以理解其中的关联关系。做排除规则检查与过滤处理, 根据上面第2个步骤获取的exclude等属性以及配置属性spring.autoconfigure.exclude做过滤处理。触发自动导入完成事件, 该方法内部逻辑正常处理完成才会触发,会调用AutoConfigurationImportListener监听器做通知处理。

 

  

3.7 @AutoConfigurationPackages

AutoConfigurationPackages是EnableAutoConfiguration上的另一个核心注解类, 官方解释为:

 

  Indicates that the package containing the annotated class should be registered

  意思是包含该注解的类,所在包下面的class, 都会注册到Spring Ioc容器中。对应源码:

  

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage {...}

Import注解, 导入AutoConfigurationPackages抽象类下面的内部静态类Registrar,研究Registrar实现原理:

 

  Registrar实现 ImportBeanDefinitionRegistrar、DeterminableImports 接口,它负责存储从@AutoConfigurationPackage注解扫描到的信息。 源码如下:

  

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { // 注册BEAN的定义信息 @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImport(metadata).getPackageName()); } // 决定是否导入注解中的配置内容 @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImport(metadata)); } }

这里面主要涉及到PackageImport类, 它是AutoConfigurationPackages的内部私有静态类,主要是记录导入的 报名信息, 源码如下:

 

  

 /** * Wrapper for a package import. */private static final class PackageImport {private final String packageName;// 构造方法, 记录注解内容PackageImport(AnnotationMetadata metadata) {this.packageName = ClassUtils.getPackageName(metadata.getClassName());}// 获取指定包名称public String getPackageName() {return this.packageName;} // 重载父类比较逻辑, 根据包名判断@Overridepublic boolean equals(Object obj) {if (obj == null getClass() != obj.getClass()) {return false;}return this.packageName.equals(((PackageImport) obj).packageName);}// 重载hash标识, 以包名的HASH值为准@Overridepublic int hashCode() {return this.packageName.hashCode();} // 重载toString, 打印内容@Overridepublic String toString() {return "Package Import " + this.packageName;}}

内部断点跟踪的话, 可以看到它记录的是我们启动类所在的包名。这也就是为什么不需要指定扫描包路径, 也会加载启动类所在包下面的JavaConfig配置信息。

 

  回到上面Registrar的registerBeanDefinitions方法, 内部调用的是register方法:

  它是处理记录AutoConfigurationPackages扫描包信息,源码如下:

  

public static void register(BeanDefinitionRegistry registry, String... packageNames) { // 判断是否包含BEAN定义信息, 如果包含, 更新packageNames信息if (registry.containsBeanDefinition(BEAN)) {BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));} // 如果registry中不包含BEAN定义, 重新构造GenericBeanDefinition对象, 记录相关信息else { GenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(BasePackages.class);beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(BEAN, beanDefinition);}}

先判断AutoConfigurationPackages注解, 记录对应的扫描包信息;如果不存在,则自行创建基于BasePackages的BEAN定义信息, 并进行注册。再看下addBasePackages方法:

 

  

private static String[] addBasePackages(ConstructorArgumentValues constructorArguments, String[] packageNames) { // 获取已经存在的Bean定义信息String[] existing = (String[]) constructorArguments.getIndexedArgumentValue(0, String[].class).getValue(); // 创建合并集合, 过滤重复的Bean定义Set<String> merged = new LinkedHashSet<>(); // 根据Set特性, 自动合并去重merged.addAll(Arrays.asList(existing));merged.addAll(Arrays.asList(packageNames)); return StringUtils.toStringArray(merged);}

获取已经存在的定义信息,再和packageNames合并, 过滤重复的扫描包。

 

  自动化配置到此就不再对其他代码进行深入跟踪分析,Spring Boot整个框架代码还是较多, 大家可以按这种思路, 逐个层级去剖析,深入挖掘更多技术点。

  

 

  

4. 总结

我们研究了Spring Boot的自动化配置原理,逐层研究剖析,从@SpringBootApplication启动注解开始,到下面的@SpringBootConfiguration, @ConfigurationPropertiesScan, @ComponentScan以及核心@EnableAutoConfiguration。我们对@EnableAutoConfiguration下面的@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)两个重要注解作了深入研究,从中可以看到Spring Boot针对自动化配置, 是分为两部分, 一部分是核心注解,来支撑服务的正常运行; 另一部分是非核心的各种自动化组件注解,做了大量封装,便于我们集成使用。

 

  到此这篇关于Spring Boot示例分析讲解自动化装配机制核心注解的文章就介绍到这了,更多相关Spring Boot自动化装配机制内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • spring编程式事务处理,spring编程事务
  • spring编程式事务处理,spring编程事务,详解Spring学习之编程式事务管理
  • spring的核心功能模块有几个,列举一些重要的spring模块
  • spring的核心功能模块有几个,列举一些重要的spring模块,七个Spring核心模块详解
  • spring注解和springmvc的注解,SpringMVC常用注解
  • spring注解和springmvc的注解,SpringMVC常用注解,详解springmvc常用5种注解
  • spring实现ioc的四种方法,spring的ioc的三种实现方式
  • spring实现ioc的四种方法,spring的ioc的三种实现方式,简单实现Spring的IOC原理详解
  • spring事务失效问题分析及解决方案怎么做,spring 事务失效情况
  • spring事务失效问题分析及解决方案怎么做,spring 事务失效情况,Spring事务失效问题分析及解决方案
  • spring5.0新特性,spring4新特性
  • spring5.0新特性,spring4新特性,spring5新特性全面介绍
  • spring ioc以及aop原理,springmvc aop原理
  • spring ioc以及aop原理,springmvc aop原理,深入浅析Spring 的aop实现原理
  • Spring cloud网关,spring cloud zuul作用
  • 留言与评论(共有 条评论)
       
    验证码: