Java SpringBoot
开发中常常看到一些@EnableXXX开头的注解,如:@EnableScheduling@EnableAsync@EnableFeignClients@EnableDiscoveryClient等等。那么也可以自定义一个这样的注解。

@EnableXXX分析

点开@EnableScheduling注解查看:

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Import({SchedulingConfiguration.class})
  4. @Documented
  5. public @interface EnableScheduling {
  6. }

@EnableScheduling注解只是导入了一个配置类,点击查看SchedulingConfiguration

  1. @Configuration(
  2. proxyBeanMethods = false
  3. )
  4. @Role(2)
  5. public class SchedulingConfiguration {
  6. public SchedulingConfiguration() {
  7. }
  8. @Bean(
  9. name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
  10. )
  11. @Role(2)
  12. public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
  13. return new ScheduledAnnotationBeanPostProcessor();
  14. }
  15. }

声明了一个ScheduledAnnotationBeanPostProcessor后置处理器,点进去看看:

  1. public class ScheduledAnnotationBeanPostProcessor implements ScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware, SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {
  2. public static final String DEFAULT_TASK_SCHEDULER_BEAN_NAME = "taskScheduler";
  3. protected final Log logger = LogFactory.getLog(this.getClass());
  4. private final ScheduledTaskRegistrar registrar;
  5. @Nullable
  6. private Object scheduler;
  7. @Nullable
  8. private StringValueResolver embeddedValueResolver;
  9. @Nullable
  10. private String beanName;
  11. @Nullable
  12. private BeanFactory beanFactory;
  13. @Nullable
  14. private ApplicationContext applicationContext;
  15. private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap(64));
  16. private final Map<Object, Set<ScheduledTask>> scheduledTasks = new IdentityHashMap(16);
  17. public ScheduledAnnotationBeanPostProcessor() {
  18. this.registrar = new ScheduledTaskRegistrar();
  19. }

这个后置处理器逻辑还是挺复杂的,看看继承的类和实现接口大概知道,利用bean生命周期相关回调方法,读取方法上的@scheduler信息做一些逻辑处理,这里不深究源码。

  1. graph LR
  2. 注解EnableXXX -->|开启| Import配置类
  3. Import配置类 --> |声明bean|相关逻辑bean
  4. 相关逻辑bean --> 利用bean生命周期完成业务相关逻辑

加载配置

@Configuration

java config方式是是使用注解@Configuration声明一个配置文件,用@Bean声明一个bean,bean的id默认方法名;SpringBoot开发常用的加载配置方式,该方式可以不用写xml,适合开发者的开发习惯。推荐

  1. @Configuration
  2. public class BConfiguration {
  3. @Bean
  4. @ConditionalOnMissingBean
  5. public B b() {
  6. System.out.println("开始注入b");
  7. return new B();
  8. }
  9. }

@PropertySource

该注解能加载.properties文件到Spingboot环境中,如:

  1. @PropertySource(value = "classpath:user.properties", encoding ="UTF-8" )

user.properties

  1. user.userName= root
  2. user.isAdmin= true
  3. user.regTime= 2022/01/01
  4. user.isOnline= 1
  5. user.maps.k1=v1
  6. user.maps.k2=v2
  7. user.lists=list1,list2
  8. user.address.tel= 16800
  9. user.address.name= 哈哈
  1. @Component
  2. @ConfigurationProperties(prefix = "user")
  3. public class User {
  4. private String userName;
  5. private boolean isAdmin;
  6. private Date regTime;
  7. private Long isOnline;
  8. private Map<String, Object> maps;
  9. private List<Object> lists;
  10. private Address address;
  11. @Override
  12. public String toString() {
  13. return "User{" +
  14. "userName='" + userName + ''' +
  15. ", isAdmin=" + isAdmin +
  16. ", regTime=" + regTime +
  17. ", isOnline=" + isOnline +
  18. ", maps=" + maps +
  19. ", lists=" + lists +
  20. ", address=" + address +
  21. '}';
  22. }
  23. //省略setter getter
  24. }
  25. public class Address {
  26. private String tel;
  27. private String name;
  28. @Override
  29. public String toString() {
  30. return "Address{" +
  31. "tel='" + tel + ''' +
  32. ", name='" + name + ''' +
  33. '}';
  34. }
  35. //省略setter getter
  36. }

加入到环境就可以使用@ConfigurationProperties@Value等注解获取到属性性。和在application.xml中配置的属性一样的道理,只是把属性放到一个.properties文件中

@ImportResource

@ImportResource注解用于导入Spring的bean配置文件,让配置文件里面的内容生效;如:以前写的springmvc.xml和applicationContext.xml等文件。使用spingboot框架的话,可以使用java config方式配置,如果有xml配置文件,可以使用@ImportResource这个注解导入到springboot环境。

  1. @ImportResource(locations = "classpath:beans.xml")
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="importSourceService" class="com.ljw.service.ImportSourceService">
  6. <!-- 给这个初始化值-->
  7. <property name="name" value="ljw"/>
  8. <property name="age" value="18"/>
  9. </bean>
  10. </beans>
  1. public class ImportSourceService {
  2. private String name;
  3. private int age;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. }
  10. public int getAge() {
  11. return age;
  12. }
  13. public void setAge(int age) {
  14. this.age = age;
  15. }
  16. @Override
  17. public String toString() {
  18. return "ImportSourceService{" +
  19. "name='" + name + ''' +
  20. ", age=" + age +
  21. '}';
  22. }
  23. }

@Import

注解@Import可以导入配置到SpringBoot环境中,它支持多种方式把bean导入到ioc容器中:

  • 普通类
  • @Configuration的配置类
  • ImportSelector的实现类
  • ImportBeanDefinitionRegistrar的实现类

4.2 版本之前只可以导入配置类,4.2版本之后也可以导入普通类,所以这四种方式其实就变成一种,就是所有类都用该注解导入到环境中。只是每种方式bean生命周期逻辑不一样而已。
下面就这四种方式进行验证

1.普通类

  1. /**
  2. * @Description: 普通服务类-直接import注入:@Import(A.class)
  3. */
  4. public class A {
  5. public A() {
  6. System.out.println("======A实例化======");
  7. }
  8. }

2.@Configuration的配置类

使用注解@Configuration声明该类为配置类

  1. @Configuration
  2. public class BConfiguration {
  3. @Bean
  4. @ConditionalOnMissingBean
  5. public B b() {
  6. System.out.println("开始注入b");
  7. return new B();
  8. }
  9. }
  10. /**
  11. * @Description: @Configuration注入
  12. * @Author: jianweil
  13. * @date: 2021/12/31 11:50
  14. */
  15. public class B implements InitializingBean {
  16. public B() {
  17. System.out.println("======B实例化======");
  18. }
  19. @Override
  20. public void afterPropertiesSet() throws Exception {
  21. System.out.println("执行B的业务方法");
  22. }
  23. }

3.ImportSelector的实现

实现ImportSelector接口,并重写selectImports方法,把com.ljw.service.C注入到ioc容器

  1. public class ImportSelectorImpl implements ImportSelector {
  2. @Override
  3. public String[] selectImports(AnnotationMetadata importingClassMetadata) {
  4. return new String[]{C.class.getName()};
  5. //return new String[]{"com.ljw.service.C"};
  6. }
  7. @Override
  8. public Predicate<String> getExclusionFilter() {
  9. return ImportSelector.super.getExclusionFilter();
  10. }
  11. }

4.ImportBeanDefinitionRegistrar的实现

「实现ImportBeanDefinitionRegistrar接口,并获取自定义的注解EnableDefinedBean的参数isBeanNon动态判断是否注入Non.class类」

  1. public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {
  2. @Override
  3. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  4. //在这里可以拿到所有注解的信息,可以根据不同注解的和注解的属性来返回不同的class,从而达到开启不同功能的目的
  5. AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(
  6. importingClassMetadata.getAnnotationAttributes(
  7. EnableDefinedBean.class.getName()));
  8. //根据注解配置参数值是否注入Non.class
  9. boolean isBeanNon = annotationAttributes.getBoolean("isBeanNon");
  10. if (isBeanNon) {
  11. Class nonbeanClass = Non.class;
  12. RootBeanDefinition nonbeanDefinition = new RootBeanDefinition(nonbeanClass);
  13. String beanName = StringUtils.uncapitalize(nonbeanClass.getSimpleName());
  14. registry.registerBeanDefinition(beanName, nonbeanDefinition);
  15. }
  16. //默认注入D.class
  17. Class beanClass = D.class;
  18. RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
  19. String beanName = StringUtils.uncapitalize(beanClass.getSimpleName());
  20. //在这里可以拿到所有注解的信息,可以根据不同注解来返回不同的class,从而达到开启不同功能的目的
  21. //通过这种方式可以自定义beanName
  22. registry.registerBeanDefinition(beanName, beanDefinition);
  23. }
  24. }

自定义注解@EnableDefinedBean

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. //导入属性配置文件
  4. @PropertySource(value = "classpath:user.properties", encoding ="UTF-8" )
  5. //导入一个bean定义资源
  6. @ImportResource(locations = "classpath:beans.xml")
  7. //导入一些bean类
  8. @Import({A.class, ImportSelectorImpl.class, ImportBeanDefinitionRegistrarImpl.class})
  9. public @interface EnableDefinedBean {
  10. boolean isBeanNon() default false;
  11. }
  • 使用@PropertySource导入属性文件user.properties
  • 使用@ImportResource导入beans配置文件beans.xml
  • 使用@Import导入普通类A.class
  • 使用@Import导入实现ImportSelector接口类ImportSelectorImpl.class
  • 使用@Import导入实现ImportBeanDefinitionRegistrar接口类ImportBeanDefinitionRegistrarImpl.class

    测试类

    下面测试可以看出上面的注解都发挥了他的作用,并且可以通过自定义注解的参数动态控制bean是否注入的逻辑。

    1. @SpringBootApplication
    2. //开启注入Non.class
    3. @EnableDefinedBean(isBeanNon = true)
    4. //@EnableDefinedBean
    5. public class App {
    6. public static void main(String[] args) {
    7. ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
    8. System.out.println("-->" + context.getBean(A.class));
    9. System.out.println("-->" + context.getBean(B.class));
    10. System.out.println("-->" + context.getBean(C.class));
    11. System.out.println("-->" + context.getBean(D.class));
    12. System.out.println("-->" + context.getBean(ImportSourceService.class));
    13. System.out.println("-->" + context.getBean(User.class));
    14. try {
    15. Non bean = context.getBean(Non.class);
    16. System.out.println("-->" + bean);
    17. } catch (BeansException e) {
    18. System.err.println("-->没有注入Non");
    19. }
    20. }
    21. }

    自定义注解配置true参数运行结果:@EnableDefinedBean(isBeanNon = true) ```java 开始注入b ======B实例化====== 执行B的业务方法 ======A实例化====== ======C实例化====== ======D实例化====== 2021-12-31 16:36:43.350 INFO 13152 —- [ main] com.ljw.App : Started App in 0.758 seconds (JVM running for 1.383) —>com.ljw.service.A@52066604 —>com.ljw.service.B@340b9973 —>com.ljw.service.C@56113384 —>com.ljw.service.D@5669c5fb —>ImportSourceService{name=’ljw’, age=18} —>User{userName=’root’, isAdmin=false, regTime=Sat Jan 01 00:00:00 CST 2022, isOnline=1, maps={k2=v2, k1=v1}, lists=[list1, list2], address=Address{tel=’16800’, name=’哈哈’}} —>com.ljw.service.Non@373ebf74

Process finished with exit code 0

  1. 自定义注解默认参数运行结果:`@EnableDefinedBean`
  2. ```java
  3. 开始注入b
  4. ======B实例化======
  5. 执行B的业务方法
  6. ======A实例化======
  7. ======C实例化======
  8. ======D实例化======
  9. 2021-12-31 16:37:34.041 INFO 83928 --- [ main] com.ljw.App : Started App in 0.71 seconds (JVM running for 1.309)
  10. -->com.ljw.service.A@5f9678e1
  11. -->com.ljw.service.B@c4ed84
  12. -->com.ljw.service.C@189aa67a
  13. -->com.ljw.service.D@5a9d6f02
  14. -->ImportSourceService{name='ljw', age=18}
  15. -->User{userName='root', isAdmin=false, regTime=Sat Jan 01 00:00:00 CST 2022, isOnline=1, maps={k2=v2, k1=v1}, lists=[list1, list2], address=Address{tel='16800', name='哈哈'}}
  16. -->没有注入Non

源码查看

下面查看源码springboot版本为2.6.1;由于spring流程比较复杂,直接查看关键信息:

processConfigBeanDefinitions方法

ConfigurationClassPostProcessor#processConfigBeanDefinitions

  1. public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  2. List<BeanDefinitionHolder> configCandidates = new ArrayList();
  3. String[] candidateNames = registry.getBeanDefinitionNames();
  4. String[] var4 = candidateNames;
  5. int var5 = candidateNames.length;
  6. for(int var6 = 0; var6 < var5; ++var6) {
  7. String beanName = var4[var6];
  8. BeanDefinition beanDef = registry.getBeanDefinition(beanName);
  9. if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
  10. if (this.logger.isDebugEnabled()) {
  11. this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
  12. }
  13. }
  14. //查看是否是配置类
  15. else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
  16. configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
  17. }
  18. }
  19. //对这些配置类根据Order排序
  20. if (!configCandidates.isEmpty()) {
  21. configCandidates.sort((bd1, bd2) -> {
  22. int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
  23. int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
  24. return Integer.compare(i1, i2);
  25. });
  26. SingletonBeanRegistry sbr = null;
  27. if (registry instanceof SingletonBeanRegistry) {
  28. sbr = (SingletonBeanRegistry)registry;
  29. if (!this.localBeanNameGeneratorSet) {
  30. BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");
  31. if (generator != null) {
  32. this.componentScanBeanNameGenerator = generator;
  33. this.importBeanNameGenerator = generator;
  34. }
  35. }
  36. }
  37. if (this.environment == null) {
  38. this.environment = new StandardEnvironment();
  39. }
  40. //创建配置类的解析类
  41. ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
  42. Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
  43. HashSet alreadyParsed = new HashSet(configCandidates.size());
  44. do {
  45. StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
  46. //ConfigurationClassParser#parse方法进行解析,重点,点进去查看
  47. parser.parse(candidates);
  48. parser.validate();
  49. Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
  50. configClasses.removeAll(alreadyParsed);
  51. if (this.reader == null) {
  52. this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());
  53. }
  54. this.reader.loadBeanDefinitions(configClasses);
  55. alreadyParsed.addAll(configClasses);
  56. processConfig.tag("classCount", () -> {
  57. return String.valueOf(configClasses.size());
  58. }).end();
  59. candidates.clear();
  60. if (registry.getBeanDefinitionCount() > candidateNames.length) {
  61. String[] newCandidateNames = registry.getBeanDefinitionNames();
  62. Set<String> oldCandidateNames = new HashSet(Arrays.asList(candidateNames));
  63. Set<String> alreadyParsedClasses = new HashSet();
  64. Iterator var13 = alreadyParsed.iterator();
  65. while(var13.hasNext()) {
  66. ConfigurationClass configurationClass = (ConfigurationClass)var13.next();
  67. alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
  68. }
  69. String[] var24 = newCandidateNames;
  70. int var25 = newCandidateNames.length;
  71. for(int var15 = 0; var15 < var25; ++var15) {
  72. String candidateName = var24[var15];
  73. if (!oldCandidateNames.contains(candidateName)) {
  74. BeanDefinition bd = registry.getBeanDefinition(candidateName);
  75. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {
  76. candidates.add(new BeanDefinitionHolder(bd, candidateName));
  77. }
  78. }
  79. }
  80. candidateNames = newCandidateNames;
  81. }
  82. } while(!candidates.isEmpty());
  83. if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
  84. sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
  85. }
  86. if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
  87. ((CachingMetadataReaderFactory)this.metadataReaderFactory).clearCache();
  88. }
  89. }
  90. }

ConfigurationClassParser

ConfigurationClassParser#parse

  1. public void parse(Set<BeanDefinitionHolder> configCandidates) {
  2. Iterator var2 = configCandidates.iterator();
  3. while(var2.hasNext()) {
  4. BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
  5. BeanDefinition bd = holder.getBeanDefinition();
  6. try {
  7. if (bd instanceof AnnotatedBeanDefinition) {
  8. //属于AnnotatedBeanDefinition 方法1
  9. this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
  10. } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
  11. //属于AbstractBeanDefinition方法2
  12. this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
  13. } else {
  14. //其他方法3
  15. this.parse(bd.getBeanClassName(), holder.getBeanName());
  16. }
  17. } catch (BeanDefinitionStoreException var6) {
  18. throw var6;
  19. } catch (Throwable var7) {
  20. throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
  21. }
  22. }
  23. this.deferredImportSelectorHandler.process();
  24. }
  25. //方法3
  26. protected final void parse(@Nullable String className, String beanName) throws IOException {
  27. Assert.notNull(className, "No bean class name for configuration class bean definition");
  28. MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
  29. this.processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
  30. }
  31. //方法2
  32. protected final void parse(Class<?> clazz, String beanName) throws IOException {
  33. this.processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
  34. }
  35. //方法1
  36. protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
  37. this.processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
  38. }

三种不同的类信息都是通过processConfigurationClass解析。

processConfigurationClass

ConfigurationClassParser#processConfigurationClass

  1. protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
  2. if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
  3. ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
  4. //在这里处理Configuration重复import;如果同一个配置类被处理两次,两次都属于被import的则合并导入类,返回。如果配置类不是被导入的,则移除旧使用新的配置类
  5. if (existingClass != null) {
  6. if (configClass.isImported()) {
  7. if (existingClass.isImported()) {
  8. existingClass.mergeImportedBy(configClass);
  9. }
  10. return;
  11. }
  12. this.configurationClasses.remove(configClass);
  13. this.knownSuperclasses.values().removeIf(configClass::equals);
  14. }
  15. ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass, filter);
  16. do {
  17. //进入看看
  18. sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter);
  19. } while(sourceClass != null);
  20. this.configurationClasses.put(configClass, configClass);
  21. }
  22. }

doProcessConfigurationClass方法

ConfigurationClassParser#doProcessConfigurationClass
@Bean@ImportResource@Import@ComponentScan@PropertySource都是这个方法处理

  1. @Nullable
  2. protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass, Predicate<String> filter) throws IOException {
  3. // 处理递归类
  4. if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
  5. this.processMemberClasses(configClass, sourceClass, filter);
  6. }
  7. // 处理@PropertySource注解
  8. Iterator var4 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator();
  9. AnnotationAttributes importResource;
  10. while(var4.hasNext()) {
  11. importResource = (AnnotationAttributes)var4.next();
  12. if (this.environment instanceof ConfigurableEnvironment) {
  13. this.processPropertySource(importResource);
  14. } else {
  15. this.logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
  16. }
  17. }
  18. // 处理 @ComponentScan 注解
  19. Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
  20. if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
  21. Iterator var14 = componentScans.iterator();
  22. while(var14.hasNext()) {
  23. AnnotationAttributes componentScan = (AnnotationAttributes)var14.next();
  24. Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
  25. Iterator var8 = scannedBeanDefinitions.iterator();
  26. while(var8.hasNext()) {
  27. BeanDefinitionHolder holder = (BeanDefinitionHolder)var8.next();
  28. BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
  29. if (bdCand == null) {
  30. bdCand = holder.getBeanDefinition();
  31. }
  32. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
  33. this.parse(bdCand.getBeanClassName(), holder.getBeanName());
  34. }
  35. }
  36. }
  37. }
  38. //处理Import注解
  39. this.processImports(configClass, sourceClass, this.getImports(sourceClass), filter, true);
  40. // 处理@ImportResource 注解
  41. importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
  42. if (importResource != null) {
  43. String[] resources = importResource.getStringArray("locations");
  44. Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
  45. String[] var20 = resources;
  46. int var22 = resources.length;
  47. for(int var23 = 0; var23 < var22; ++var23) {
  48. String resource = var20[var23];
  49. String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
  50. configClass.addImportedResource(resolvedResource, readerClass);
  51. }
  52. }
  53. //处理包含@Bean注解的方法
  54. Set<MethodMetadata> beanMethods = this.retrieveBeanMethodMetadata(sourceClass);
  55. Iterator var18 = beanMethods.iterator();
  56. while(var18.hasNext()) {
  57. MethodMetadata methodMetadata = (MethodMetadata)var18.next();
  58. configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
  59. }
  60. // 处理普通方法
  61. this.processInterfaces(configClass, sourceClass);
  62. if (sourceClass.getMetadata().hasSuperClass()) {
  63. String superclass = sourceClass.getMetadata().getSuperClassName();
  64. if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
  65. this.knownSuperclasses.put(superclass, configClass);
  66. return sourceClass.getSuperClass();
  67. }
  68. }
  69. return null;
  70. }

ConfigurationClassParser

ConfigurationClassParser#processImports
这里点进去查看@Import解析方法

  1. private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) {
  2. if (!importCandidates.isEmpty()) {
  3. if (checkForCircularImports && this.isChainedImportOnStack(configClass)) {
  4. this.problemReporter.error(new ConfigurationClassParser.CircularImportProblem(configClass, this.importStack));
  5. } else {
  6. this.importStack.push(configClass);
  7. try {
  8. Iterator var6 = importCandidates.iterator();
  9. while(var6.hasNext()) {
  10. ConfigurationClassParser.SourceClass candidate = (ConfigurationClassParser.SourceClass)var6.next();
  11. Class candidateClass;
  12. //如果实现了ImportSelector接口
  13. if (candidate.isAssignable(ImportSelector.class)) {
  14. candidateClass = candidate.loadClass();
  15. ImportSelector selector = (ImportSelector)ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry);
  16. Predicate<String> selectorFilter = selector.getExclusionFilter();
  17. if (selectorFilter != null) {
  18. exclusionFilter = exclusionFilter.or(selectorFilter);
  19. }
  20. if (selector instanceof DeferredImportSelector) {
  21. this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector)selector);
  22. } else {
  23. String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
  24. Collection<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames, exclusionFilter);
  25. this.processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
  26. }
  27. }
  28. //如果实现了ImportBeanDefinitionRegistrar接口
  29. else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
  30. candidateClass = candidate.loadClass();
  31. ImportBeanDefinitionRegistrar registrar = (ImportBeanDefinitionRegistrar)ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry);
  32. configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
  33. } else {
  34. //将import当成Configuration来使用,就是我们的普通类方式导入
  35. this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
  36. this.processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
  37. }
  38. }
  39. } catch (BeanDefinitionStoreException var17) {
  40. throw var17;
  41. } catch (Throwable var18) {
  42. throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", var18);
  43. } finally {
  44. this.importStack.pop();
  45. }
  46. }
  47. }
  48. }

该方法解析了上面三种情况导入:

  1. 实现了ImportSelector接口的类导入
  2. 实现了ImportBeanDefinitionRegistrar接口的类导入
  3. 普通类的类导入