本文主要内容包括三个部分,第一部分主要介绍@Import注解的三种使用方法,第二部分主要介绍自定义starter的两种形式,第三部分主要介绍Springboot自动装配Bean的大致流程,第四部分主要介绍一些starter的一些基本知识。

1:三种使用方法

1.1:导入普通类

1.1.1:直接导入

新建一个测试类TestA.java

public class TestA {
   public String funA(){
       return "TestA";
  }
}

在创建一个配置类

@Import(TestA.class)
public class Config {
}

测试

public class Main {
   public static void main(String[] args) {
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
       TestA testA = context.getBean(TestA.class);
       System.out.println(testA.funA());
  }
}

1.1.2:导入带有@Configuration的配置类

再见一个测试类TestB.java

public class TestB {
  public String funB(){
      return "TestB";
  }
}

在创建一个配置类创建一个配置类ConfigOther.class

@Configuration
public class ConfigOther {
  @Bean
  public TestB testB(){
      return new TestB();
  }
}

修改Config.java

@Import({TestA.class, ConfigOther.class})
public class Config {
}

测试

public class Main {
   public static void main(String[] args) {
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
       TestA testA = context.getBean(TestA.class);
       System.out.println(testA.funA());
       TestB testB = context.getBean(TestB.class);
       System.out.println(testB.funB());
  }
}

1.2:通过ImportSelector导入

创建TestC.class

public class TestC {
   public String funC(){
       return "TestC";
  }
}

创建ClassConfig并实现org.springframework.context.annotation.ImportSelector接口

@Configuration
public class ClassConfig implements ImportSelector {
   @Override
   public String[] selectImports(AnnotationMetadata annotationMetadata) {
       return new String[]{TestC.class.getName()};
  }
}

修改Config.class

@Import({TestA.class, ConfigOther.class,ClassConfig.class})
public class Config {
}

测试

public class Main {
  public static void main(String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
      TestA testA = context.getBean(TestA.class);
      System.out.println(testA.funA());
      TestB testB = context.getBean(TestB.class);
      System.out.println(testB.funB());
      TestC testC = context.getBean(TestC.class);
      System.out.println(testC.funC());
  }
}

1.3通过 ImportBeanDefinitionRegistrar 方式导入的类

创建测试类TestD.class

public class TestD {
  public String funD(){
      return "TestD";
  }
}

创建CustomImportBeanDefinitionRegistrar.class并实现org.springframework.context.annotation.ImportBeanDefinitionRegistrar接口

public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
      RootBeanDefinition testD = new RootBeanDefinition(TestD.class);
      registry.registerBeanDefinition("testD", testD);
  }
}

修改Config.class

@Import({TestA.class, ConfigOther.class,ClassConfig.class,CustomImportBeanDefinitionRegistrar.class})
public class Config {
}

测试

public class Main {
  public static void main(String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
      TestA testA = context.getBean(TestA.class);
      System.out.println(testA.funA());
      TestB testB = context.getBean(TestB.class);
      System.out.println(testB.funB());
      TestC testC = context.getBean(TestC.class);
      System.out.println(testC.funC());
      TestD testD = context.getBean(TestD.class);
      System.out.println(testD.funD());
  }
}

至此@Import的使用已完毕,下面我们看一下starter是如何实现自动配置的。

自定义starter的时候有两种方式,

第一种是引入了依赖之后需要在启动类上加上@EnableXXX注解的方式,

第二种是在META-INF中加入spring.factories文件然后引入需要配置的类这种就什么也不需要配置了。

2:自定义starter的方式

第一种:采用@EnableXXX注解的形式自定义starter

新建一个注解@EnableAppConfig

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import(ClassConfig.class)
public @interface EnableAppConfig {
}

然后使用该starter的时候只需在pom.xml文件中加入依赖,在启动类上加上@EnableAppConfig,bean就会自动装配了

第二种:使用spring.factories文件形式自定义starter

在META-INF中加入spring.factories文件添加一下内容

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.liekkas.sql.testimport.Config

在Config.class类上加上@Configuration注解

@Import({TestA.class, ConfigOther.class,ClassConfig.class,CustomImportBeanDefinitionRegistrar.class})
@Configuration
public class Config {
}

然后使用该starter的时候只需要在pom.xml文件中加入依赖bean就会自动装配了。

两种形式自定义starter无本质区别,只是采用@EnableXXX注解的形式需要在启动类上加注解,而如果配置了spring.factories文件则只需要引入依赖就可以了。当然本文只是大致介绍了如何自定义starter的简单使用,如有复杂的逻辑配置等需求请参考https://www.cnblogs.com/wkynf/p/14256565.html

3:Springboot是如何自动配置Bean的

查看org.springframework.boot.autoconfigure.AutoConfigurationImportSelector的selectImports方法可知道

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
  if (!isEnabled(annotationMetadata)) {
    return NO_IMPORTS;
  }
  //获取所有需要自动装配的Bean的全限定名
  AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
  return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry获取所有的配置类的全限定类名

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
  if (!isEnabled(annotationMetadata)) {
    return EMPTY_ENTRY;
  }
  AnnotationAttributes attributes = getAttributes(annotationMetadata);
  //获取所有的Spring.factories里面的内容
  List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
  configurations = removeDuplicates(configurations);
  Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  checkExcludedClasses(configurations, exclusions);
  configurations.removeAll(exclusions);
  configurations = getConfigurationClassFilter().filter(configurations);
  fireAutoConfigurationImportEvents(configurations, exclusions);
  return new AutoConfigurationEntry(configurations, exclusions);
}

获取到所有需要加载的Bean的全限定类名之后就可以放到Spring的容器中了。

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;
}

SpringBoot使用了SPI机制可以读取所有classpath路径下的spring.factories文件的内容,然后根据我们@Import注解中的内容把Bean加入Spring的容器中。至于如何解析@Import注解的内容应该就是工作量的事情了,当我们把Springboot自动装配Bean的答题逻辑了解清楚了之后,其他的就是内容的实现了,如有需要了解具体逻辑的同学,请自行参考Springboot的代码。

4:starter的一些注意事项

starter主要分为两种,一种是官方定义的starter,另一种是非官方的starter比如我们自定义的starter。

一些命名的注意事项,一般官方的命名为spring-boot-starter-xxx,而非官方的starter命名为xxx-spring-boot-starter

官方定义starter可以参考redis的starter,非官方的可以参考mybatis的starter,仔细观察就会发现官方的starter中没有spring.factories文件,而非官方的starter中有spring.factories文件,就是因为官方的starter中的spring.factories文件内容已经被内置到Springboot项目中了,所以不需要spring.factories文件了,而非官方的就需要我们自定义配置了。

starter自动转配流程以及@Import注解使用的更多相关文章

  1. Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件

    本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...

  2. Spring 自动转配类 在类中使用@Bean 注解进行转配但是需要排除该类说明

    在spring中可以使用 @Component @Configuration @Bean(实例化后返回该bean)进行类实例的自动装配. 需求: 排除指定需要自动转配的类. 说明: 1.在以上注解中  ...

  3. SpringBoot自动配置(装配)流程

    源码分析 SpringBoot自动配置流程 ​ ​ 首先,我们要了解在@SpringBootApplication注解的内部,还具有@EnableAutoConfiguration,@SpringBo ...

  4. @enable跟@import注解

    参考文章: 讲@import的相关内容:https://blog.csdn.net/u012437781/article/details/78626134 讲为什么registrar没有注入:http ...

  5. Spring5源码深度分析(二)之理解@Conditional,@Import注解

    代码地址: 1.源码分析二主要分析的内容 1.使用@Condition多条件注册bean对象2.@Import注解快速注入第三方bean对象3.@EnableXXXX 开启原理4.基于ImportBe ...

  6. spring注解之@Import注解的三种使用方式

    目录 1.@Import注解须知 2.@Import的三种用法 3.@Import注解的三种使用方式总结 @ 1.@Import注解须知 1.@Import只能用在类上 ,@Import通过快速导入的 ...

  7. EnableAutoConfiguration注解 Spring中@Import注解的作用和使用

    EnableAutoConfiguration注解 http://www.51gjie.com/javaweb/1046.html springboot@EnableAutoConfiguration ...

  8. Spring中@Import注解的使用

    Spring中@Import注解的使用 @Import注解算是SpringBoot自动配置原理中一个很重要的注解 认识@Import注解 先看一下源码 @Target(ElementType.TYPE ...

  9. JAVA_eclipse 保留Java文件时自动格式化代码和优化Import

    Eclipse 保存Java文件时自动格式化代码和优化Import Eclipse中format代码的快捷方式是ctrl+shift+F,如果大家想保存 java文件的时候 自动就格式化代码+消除不必 ...

随机推荐

  1. MySQL密码复杂度与密码过期策略介绍

    前言: 年底了,你的数据库是不是该巡检了?一般巡检都会关心密码安全问题,比如密码复杂度设置,是否有定期修改等.特别是进行等保评测时,评测机构会要求具备密码安全策略.其实 MySQL 系统本身可以设置密 ...

  2. Vue.js源码解析-从scripts脚本看vue构建

    目录 1. scripts 脚本构建 1.1 dev 开发环境构建过程 1.1.1 配置文件代码 1.1.2 如何进行代码调试? 1.2 build 生产环境构建过程 1.2.1 scripts/bu ...

  3. dynamic_cast和typeid

    1. C++有三个支持RTTI的元素. 如果可能的话,dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针,否则,该运算符返回0--空指针. typeid运算符返回一个对t ...

  4. 克鲁斯卡尔(Kruskal)算法(代码)

    算法代码 C#代码 using System; using System.Linq; namespace Kruskal { class Program { static void Main(stri ...

  5. C++PRIMER第二章前半部分答案

    C++PRIMER第二章前半部分答案 哈哈哈,为什么是前半部分呢,后半部分还在学习中,重新系统性的学习c++,共同进步嘛,不多说,跟我一起来看看吧,第三章开始才是新手收割的时候,慢慢来~~ 2.1&a ...

  6. Swift系列七 - 汇编分析值类型

    通过汇编分下值类型的本质. 一.值类型 值类型赋值给var,let或者给参数传参,是直接将所有内容拷贝一份.类似于对文件进行复制粘贴操作,产生了全新的文件副本,属于深拷贝(deep copy). 示例 ...

  7. 【转载】CentOS 7自动以root身份登录gnome桌面 操作系统开机后自动登录到桌面 跳过GDM

    CentOS 7自动以root身份登录gnome桌面 ################### #cd /etc/gdm ]# cat custom.conf# GDM configuration st ...

  8. IT菜鸟之网站搭建(emlog)

    由多个网页组成的一种集合,叫做网站 网站分为:静态网站.动态网站  静态网站:不会因为时间.地点.用户角色等因素发生内容改变的网站 动态网站:会因为时间.地点.用户角色等因素发生内容改变的网站 注意: ...

  9. 搭建 Linux 集群环境

    什么是集群 集群是一组通过网络互联的计算机,集群里的每一台计算机称作一个节点. 搭建集群环境规划 集群主机节点数:4 台安装 CentOS7 的虚拟机 主机名(Hostname) IP 地址 node ...

  10. 3.socket编程示例

    #block_server.py 非阻塞IO示例#有个疑惑:下面的connfd的blockind要设置为True,不然会出错,待解决from socket import *from time impo ...