上一篇:Spring5 源碼分析-容器刷新-@Import(類 implments DeferImportSelector)java
原本是要將@Import(ImportBeanDefinitionRegistrar) @Bean @Bean接口方法他們解析與執行所在源碼位置幾乎是在一塊兒的,因此一塊兒寫在一篇博客中git
該方法最後結束的地方是獲取父類的class返回繼續調用doProcessConfigurationClass方法,嘗試父類class是否是也是配置類,若是是則繼續處理,一直循環直到沒有父類才結束。spring
@Import(ImportBeanDefinitionRegistrar) :將自定義的ImportBeanDefinitionRegistrar經過@Import導入,能夠實現自定義註冊BeanDefinition,甚至能夠根據一些配置手動干預生成的BeanDefinition。好比自定義一個註解(該註解能夠定義BeanDefinition的相關屬性),將@Import做爲元註解,那麼在registryBeanDefinition的時候就能夠根據自定義註解上的屬性設置想要註冊的BeanDefinition源碼分析
@Bean:將類或者接口中被@Bean修飾的方法返回類的BeanDefinition註冊到容器中測試
配置類父類:doProcessConfigurationClass方法結束的地方是獲取父類的SourceClass,將其返回並繼續調用doProcessConfigurationClass方法ui
這個例子中將涉及4中導入的方法:this
1.經過自定義的註解導入自定義的ImportBeanDefinitionRegistrarlua
2.類的@Bean methodspa
3.接口的@Bean method.net
4.父類也是配置類
接口(有@Bean)
public interface MyConfig { @Bean default City getCity(){ return new City(); } }
配置類父類(添加@ComponentScan註解)
@ComponentScan(value = "com.jv.spring.other.scan") public class MyParentConfig { }
自定義導入功能註解
@Retention(RetentionPolicy.RUNTIME) @Import(MyImportBeanDefinitionRegistrar.class) public @interface MyAnnotation { boolean lazyInit(); }
自定義ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{ private AnnotationMetadata importMetadata; public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { BeanDefinitionBuilder bdb = BeanDefinitionBuilder.genericBeanDefinition(Dept.class); Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(MyAnnotation.class.getName()); boolean lazyInit = (boolean)annotationAttributes.get("lazyInit"); bdb.getBeanDefinition().setLazyInit(lazyInit); registry.registerBeanDefinition("dept",bdb.getBeanDefinition()); } }
配置類
@Configuration @PropertySource(value = "classpath:au.properties",name="my-au",encoding = "utf-8") @MyAnnotation(lazyInit = true) public class OtherConfig extends MyParentConfig implements MyConfig{ @Bean public User getUser(){ return new User(); } }
實體類
@Setter @Getter public class City { private String cityName = "重慶"; }
@Setter @Getter public class Dept { private String deptName = "研發部"; }
@Getter @Setter public class User { private String userName = "梅西"; }
@Component @Getter @Setter public class Employee { private String empName = "Havi"; }
測試類
public class OtherMain { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(OtherConfig.class); User user = ac.getBean(User.class); System.out.println(user.getUserName()); City city = ac.getBean(City.class); System.out.println(city.getCityName()); Dept dept = ac.getBean(Dept.class); System.out.println(dept.getDeptName()); Employee employee = ac.getBean(Employee.class); System.out.println(employee.getEmpName()); } }
測試結果
幾個對象都被Spring容器初始化成功,若是要看lazyInit效果,將斷點設置到getBean(Dept.class)這一行,看BeanFactory.singletonObjects中是否包含Dept對象。結論是不包含。如圖:
以上的操做主要集中在兩端代碼區域
掃描配置類,解析對應的註解(ConfigurationclassParser.doProcessConfigurationClass())
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { /** * 首先處理@configuration配置類的嵌套類(嵌套類被@Component @Import @ImportResource @ComponentScan 或者這個類是否有被@Bean修飾的Method), * 若是有則會進行遞歸調用processConfigurationClass()->doProcessConfigurationClass() */ if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass); } // Process any @PropertySource annotations 處理@PropertySource註解的類 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations 處理@ComponentScan註解,完成符合Spring規則類定義註冊 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately 當即執行掃描 //不會掃描到本身(@Configuration修飾了的類) Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed // 檢查掃描到全部類中是否還有被@Configuration修飾的類,若是還有,則須要再按照配置類的流程處理一遍 for (BeanDefinitionHolder holder : scannedBeanDefinitions) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { //若是掃描的包路徑下還有被@Configuration修飾的類,則遞歸進行處理 parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @Import annotations 處理@Import註解 processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations 處理@ImportResource註解 AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual @Bean methods 處理@Bean註解 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces 處理接口默認方法上的@Bean註解 // 根據接口的繼承接口遞歸調用retrieveBeanMethodMetadata(),將Interface中默認方法上的@Bean對應的beanMethod添加到configClass.beanMethods當中 processInterfaces(configClass, sourceClass); // Process superclass, if any // 循環處理父類上的配置信息 if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete // 若是沒有父類了,則處理結束 return null; }
將掃描解析的結果(添加到對應的待處理列表)進行處理(上面的方法處理返回到)
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { 。。。。省略若干行。。。。 do {/*這裏會將符合規則的BD放入到BeanDefinitionMap中,還有配置類上的屬性文件放入到enviremont中,在使用AutowireAnnotationBeanPostProcessor的時候進行屬性注入*/ parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } // 處理@Bean所註冊的beanMethod,解析成對應的BeanDefinition並註冊 // 處理由@Import導入的ImportBeanDefinitionRegistrar // 處理@ImportResource導入的配置文件 this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); 。。。。省略若干行。。。。 }
其中圈出來部分就是處理ImportBeanDefinitionRegistrar列表和BeanMethod,以及@ImportResource。再往loadBeanDefinitions()裏面翻,直到以下方法loadBeanDefinitionsForConfigurationClass()
private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return; } if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } //遍歷經過@Bean(普通方法+接口默認方法)添加的beanMethod for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //導入外部配置文件xml或者groovy loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //導入@Import註解指定的相關配置類(由ImportBeanDefinitionRegistrar) loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
再往深層次的方法註釋,等我把源碼上傳到gitee當中再上連接