文章目录

  • Pre
  • 四种处理方式
  • 从@SpringBootApplication注解说起
    • @SpringBootApplication组合注解说明
      • @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited
      • @SpringBootConfiguration
      • @EnableAutoConfiguration
      • @ComponentScan
    • @EnableAutoConfiguration
      • @AutoConfigurationPackage
      • @Import(AutoConfigurationImportSelector.class)
  • @Import源码
    • @Import 普通组件
    • @Import 实现了ImportSelector接口的组件 (类的全限定类名)
    • @Import 实现了ImportBeanDefinitionRegistrar接口的组件
  • 最佳实践 @EnableXXX
    • 【自定义注解 @EnableArtisan】
    • 将AppConfig.java添加@EnableArtisan
  • 源码

Pre

Spring Boot - 自动配置实现原理


四种处理方式

在使用 Spring Boot 时,@Import 也是一个非常常见的注解,可以用来动态创建 Bean。

在 @Import 注解的属性中可以设置需要引入的类名,例如 @AutoConfigurationPackage 注解上的 @Import(AutoConfigurationPackages.Registrar.class)。根据该类的不同类型,Spring 容器针对 @Import 注解有以下四种处理方式:

  • 如果该类实现了 ImportSelector 接口,Spring 容器就会实例化该类,并且调用其 selectImports 方法;
  • 如果该类实现了 DeferredImportSelector 接口,则 Spring 容器也会实例化该类并调用其 selectImports方法。DeferredImportSelector 继承了 ImportSelector,区别在于 DeferredImportSelector 实例的 selectImports 方法调用时机晚于 ImportSelector 的实例,要等到 @Configuration 注解中相关的业务全部都处理完了才会调用;
  • 如果该类实现了 ImportBeanDefinitionRegistrar 接口,Spring 容器就会实例化该类,并且调用其 registerBeanDefinitions 方法;
  • 如果该类没有实现上述三种接口中的任何一个,Spring 容器就会直接实例化该类。

我们来搞一搞@Import吧


从@SpringBootApplication注解说起

我们都知道 启动一个SpringBoot应用 无须各种的配置文件,无须各种繁杂的pom依赖,一个main方法,就能run起来了。

与其他框架整合也相当方便,使用EnableXXXXX注解就可以完成整合

那SpringBoot是如何实现自动配置的????


@SpringBootApplication组合注解说明

@SpringBootApplication: Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot需要运行这个类的main方法来启动SpringBoot应用

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited

注解说明:

  • @Target(ElementType.TYPE) 设置当前注解可以标记在哪
  • @Retention(RetentionPolicy.RUNTIME) 当注解标注的类编译以什么方式保留。 RetentionPolicy.RUNTIME 会被jvm加载
  • @Documented java doc 会生成注解信息
  • @Inherited 是否会被继承

更详细的请参考我以前写的一篇博文: Java-Java5.0注解解读


@SpringBootConfiguration

Spring Boot的配置类 , 标注在某个类上,表示这是一个Spring Boot的配置类


@EnableAutoConfiguration

开启自动配置功能 , @EnableAutoConfiguration告诉SpringBoot开启自动配置,会自动去加载自动配置类


@ComponentScan

相当于在spring.xml 配置中<context:comonent-scan> 但是并没有指定basepackage,如果没有指定spring底层会自动扫描当前配置类所有在的包


@EnableAutoConfiguration

SpringBootApplication注解中最重要的一个注解就是 @EnableAutoConfiguration.

@AutoConfigurationPackage

将当前配置类所在包保存在BasePackages的Bean中。供Spring内部使用

使用了@Import注解 保存扫描路径, 注册

那看下 org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar


@Import(AutoConfigurationImportSelector.class)

关键点!

可以看到,在@EnableAutoConfiguration注解内也使用到了@Import注解来完成导入配置的功能


那都用它,我们来搞搞@Import吧


@Import源码


@Import表示要导入的一个或多个@Configuration类

我们来看下value方法源码中的注释: Configuration,ImportSelector,ImportBeanDefinitionRegistrar 或者是一个普通的组件

那分别来看下如何使用吧

POM 核心 有个context就够了

  <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.18</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.6.RELEASE</version></dependency></dependencies>

@Import 普通组件

@Import({ 要导入的组件 } )

【模拟第三方框架提供的】

package com.artisan.configuration;import com.artisan.beans.Artisan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author 小工匠* @version 1.0* @description:  自定义的配置类  类比第三方的配置类* @date 2021/5/22 8:50* @mark: show me the code , change the world*/@Configuration
public class ArtisanConfig {@Beanpublic Artisan artisan() {Artisan artisan = new Artisan();artisan.setName("小工匠");artisan.setAge(18);return artisan;}
}

【模拟Spring自己的】

/*** 系统当前加载的配置类*/@Configuration
@Import({ArtisanConfig.class})
// @Import(ArtisanImportSelector.class)
//@Import(ArtisanRegistrar.class)
//@EnableArtisan
public class AppConfig {}

将AppConfig.java添加注解 @Import({ArtisanConfig.class}) , 将第三方的配置类导入到Bean容器中 , 本质上就是导入 一个Configuration配置类组件

【测试类】

public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);Artisan artisan =  ctx.getBean(Artisan.class);System.out.println(artisan);}
}

【测试结果】


@Import 实现了ImportSelector接口的组件 (类的全限定类名)

【ImportSelector接口 返回全限定名】

package com.artisan.impt;import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;/*** @author 小工匠* @version 1.0* @description: TODO* @date 2021/5/22 9:25* @mark: show me the code , change the world*/
public class ArtisanImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {return new String[]{"com.artisan.beans.Artisan"};}
}

【AppConfig - @Import(ArtisanImportSelector.class)】

/*** 系统当前加载的配置类*/@Configuration
//@Import({ArtisanConfig.class})@Import(ArtisanImportSelector.class)
//@Import(ArtisanRegistrar.class)
//@EnableArtisan
public class AppConfig {}

测试

ArtisanSelector返回的类的全限定类名,即为导入到容器中的组件全类名


@Import 实现了ImportBeanDefinitionRegistrar接口的组件

【ImportBeanDefinitionRegistrar 接口】

package com.artisan.impt;import com.artisan.beans.Artisan;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;/*** @author 小工匠* @version 1.0* @description: TODO* @date 2021/5/22 9:28* @mark: show me the code , change the world*/
public class ArtisanRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Artisan.class);builder.setScope(BeanDefinition.SCOPE_SINGLETON);builder.addPropertyValue("name", "小工匠Registrar");builder.addPropertyValue("age", "18");registry.registerBeanDefinition("artisan", builder.getBeanDefinition());}
}

【AppConfig - @Import(ArtisanRegistrar.class) 】

/*** 系统当前加载的配置类*/@Configuration
//@Import({ArtisanConfig.class})
// @Import(ArtisanImportSelector.class)
@Import(ArtisanRegistrar.class)
//@EnableArtisan
public class AppConfig {}

【测试】

ImportBeanDefinitionRegistrar类似于ImportSelector用法,只不过这种用法能自定义化注册,往容器内注入一个BeanDefinition,然后BeanDeiniton在容器内转为一个实例bean。


最佳实践 @EnableXXX

【自定义注解 @EnableArtisan】

package com.artisan.annotation;import com.artisan.configuration.ArtisanConfig;
import com.artisan.impt.ArtisanImportSelector;
import com.artisan.impt.ArtisanRegistrar;
import org.springframework.context.annotation.Import;import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented// @Import({ArtisanConfig.class})   @Import({ArtisanImportSelector.class})  都可以
@Import({ArtisanRegistrar.class})
public @interface EnableArtisan {}

将AppConfig.java添加@EnableArtisan

【测试结果】


源码

https://github.com/yangshangwei/boot2/tree/master/spring_maven

Spring Boot - 自动装配中的不可忽视的@Import相关推荐

  1. Spring Boot自动装配过程解析及简单Demo演示

    文章目录 1.约定大于配置 2.自动装配原理 2.1.`@SpringBootApplication` 2.2.`@EnableAutoConfiguration` 2.3.`@Import` 2.4 ...

  2. Spring Boot自动装配原理详解

    目录 1.环境和依赖 1.1.spring boot版本 1.2.依赖管理 2.自动装配 2.1.流程概述 2.2.三大步前的准备工作 2.2.1.注解入口 2.2.2.获取所有配置类 2.3.获取过 ...

  3. Spring Boot 自动装配的原理

    在Spring Boot中,不得不说的一个点是自动装配,它是Starter的基础,也是Spring Boot的核心,那么什么叫自动装配呢?或者说什么叫装配呢? 简单来说,就是自动将Bean装配到IoC ...

  4. Spring Boot 自动装配原理

    本文已经收录到Github仓库,该仓库包含计算机基础.Java核心知识点.多线程.JVM.常见框架.分布式.微服务.设计模式.架构等核心知识点,欢迎star~ Github地址:https://git ...

  5. Spring/Spring MVC/Spring Boot自动装配机制介绍

  6. springboot 自动装配_Spring Boot 自动装配流程

    Spring Boot 自动装配流程 本文以 mybatis-spring-boot-starter 为例简单分析 Spring Boot 的自动装配流程. Spring Boot 发现自动配置类 这 ...

  7. Spring Boot - 自动配置实例解读

    文章目录 Pre 启用 debug=true输出自动配置 HttpEncodingAutoConfiguration 什么情况下,Spring Boot 会自动装配 HttpEncodingAutoC ...

  8. Spring Boot - 自动配置实现原理

    文章目录 Pre @SpringBootApplication 注解 @ComponentScan 注解 @SpringBootConfiguration 注解 @EnableAutoConfigur ...

  9. 学习第三篇:【SpringBoot-Labs】芋道 Spring Boot 自动配置原理

    本周(8.21-8.27)将学习芋道 Spring Boot的以下文章: 8.21: 快速入门 8.22:Spring Boot 自动配置原理 .Jar 启动原理 8.23:调试环境. 热部署入门.消 ...

最新文章

  1. find ip from hostname or find hostname from ip
  2. 2018年中美独角兽研究报告
  3. JavaScript设计模式 Item 3 --封装
  4. JSON简介,语法,在html中应用
  5. 《OD大数据实战》MapReduce实战
  6. 阿里巴巴开发公约节选(日常编程较常用的一些)
  7. 鸿蒙hms在哪儿更新,原创 华为鸿蒙系统已开始实施!华为EMUI10.1再更新:HMS将决定战略方向...
  8. 本科、硕士、博士的区别
  9. 锁屏界面提示某些设置已隐藏_OPPO手机忘记锁屏密码怎么办?教你一招轻松解开!...
  10. 360html5播放加速,总结:没有讨论加速问题,“视频快速观看”完全支持360种浏览器...
  11. 将钉钉应用内浮窗_手机钉钉怎么设置悬浮窗 几步轻松开启
  12. DH参数(Denavit-Hartenberg parameters)
  13. 电商 秒杀系统 设计思路和实现方法
  14. 华为计算机复制怎么删,华为电脑复制粘贴快捷键
  15. java qlv转mp4 代码_如何将QLV视频格式转换成MP4视频
  16. HTC Vive榜单:盘点一周最受欢迎的VR应用
  17. 神经网络计算棒有什么用,神经网络计算棒怎么用
  18. 【计算机网络】网络安全 : 数字签名 ( 数字签名简介 | 数字签名实现 | 数字签名功能 | 保密数字签名 )
  19. 微客侠:解决微信内直接打开淘宝链接
  20. 如何通过关键字和搜索结果分析用户需求

热门文章

  1. ubuntu16.04 搭建Jenkins自动编译环境问题汇总
  2. 简单图库软件的实现(联网下载图片保存到sdcard在Listview中展示,并作为ContentProvider为其他软件提供图库数据)
  3. python实用小技巧
  4. OpenMP入门教程(二)reduce sum
  5. linux 统计日志最多的ip,统计nginx日志里访问次数最多的前十个IP
  6. 未排序正整数组中累加和为指定值的最长子数组长度
  7. 强化学习(四)---基于模型动态规划问题
  8. NTU 课程: MAS714(3) DFS BFS(搜索算法)
  9. R语言问题剖析20篇(一)-R语言泛函式编程purrr实现优雅循环迭代
  10. 数据中台建设是噱头还是黑科技?