上一篇: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当中再上连接