重庆大渡口网站建设解决方案,株洲最新通知今天,站台建筑,互联网保险发展现状【前言】
我们在使用Spring注入Bean对象时#xff0c;会使用不同注解#xff0c;比如Component Service Controller Import Bean等。由于Service Controller 等都可以归为Component#xff0c;那么Component 和Import 、Bean是何时被加载的#xff0c;以及他们之间的顺序呢…【前言】
我们在使用Spring注入Bean对象时会使用不同注解比如Component Service Controller Import Bean等。由于Service Controller 等都可以归为Component那么Component 和Import 、Bean是何时被加载的以及他们之间的顺序呢下面就来分析一下。
【源码解析】
首先Spring的启动肯定是由AbstractApplicationContext.refresh()方法开始的。之后直接进入invokeBeanFactoryPostProcessors(beanFactory)方法该方法用来处理要载入的Bean对象。会进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())方法。
之后会进入ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException(postProcessBeanDefinitionRegistry already called on this post-processor against registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException(postProcessBeanFactory already called on this post-processor against registry);}this.registriesPostProcessed.add(registryId);processConfigBeanDefinitions(registry);}
进入processConfigBeanDefinitions(registry);该方法主要加载就是如下这段
........................
ConfigurationClassParser parser new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);SetBeanDefinitionHolder candidates new LinkedHashSet(configCandidates);SetConfigurationClass alreadyParsed new HashSet(configCandidates.size());do {parser.parse(candidates);parser.validate();SetConfigurationClass configClasses new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader null) {this.reader new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);}
........................ 这段parser.parse(candidates);中candidates就是最初启动的bean对象名字比如springboot应用中的主类带Springboot标识的如下
SpringBootApplication
public class DemoApplication {public static void main(String[] args) {new SpringApplication(DemoApplication.class).run(args);}
}
那么candidates 就会包含这个DemoApplication 。进入parser.parse(candidates)方法
public void parse(SetBeanDefinitionHolder configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd holder.getBeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}else if (bd instanceof AbstractBeanDefinition ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else {parse(bd.getBeanClassName(), holder.getBeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException(Failed to parse configuration class [ bd.getBeanClassName() ], ex);}}this.deferredImportSelectorHandler.process();}
会继续进行解析根据不同类型但一般都是AnnotatedBeanDefinition。之后继续进入 protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {processConfigurationClass(new ConfigurationClass(metadata, beanName));}protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}ConfigurationClass existingClass this.configurationClasses.get(configClass);if (existingClass ! null) {if (configClass.isImported()) {if (existingClass.isImported()) {existingClass.mergeImportedBy(configClass);}// Otherwise ignore new imported config class; existing non-imported class overrides it.return;}else {// Explicit bean definition found, probably replacing an import.// Lets remove the old one and go with the new one.this.configurationClasses.remove(configClass);this.knownSuperclasses.values().removeIf(configClass::equals);}}// Recursively process the configuration class and its superclass hierarchy.SourceClass sourceClass asSourceClass(configClass);do {sourceClass doProcessConfigurationClass(configClass, sourceClass);}while (sourceClass ! null);this.configurationClasses.put(configClass, configClass);}
主要就是将 DemoApplication 封装成ConfigurationClass类。然后通过asSourceClass(configClass)解析出原始类DemoApplication.class。之后调用doProcessConfigurationClass方法
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)throws IOException {// **1**if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass);}// Process any PropertySource annotationsfor (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);}}// **2**SetAnnotationAttributes 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// ** 2.1 **SetBeanDefinitionHolder scannedBeanDefinitions this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand null) {bdCand holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// Process any Import annotations// **3**processImports(configClass, sourceClass, getImports(sourceClass), true);// Process any ImportResource annotationsAnnotationAttributes 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// **4**SetMethodMetadata beanMethods retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// Process superclass, if anyif (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 recursereturn sourceClass.getSuperClass();}}// No superclass - processing is completereturn null;} // **1** 处理内部类。比如我有一个Component的类里面有内部类A且内部类中也有包含Bean、Component、Import的注解那么会继续处理内部类A。
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {CollectionSourceClass memberClasses sourceClass.getMemberClasses();if (!memberClasses.isEmpty()) {ListSourceClass candidates new ArrayList(memberClasses.size());for (SourceClass memberClass : memberClasses) {if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {candidates.add(memberClass);}}OrderComparator.sort(candidates);for (SourceClass candidate : candidates) {if (this.importStack.contains(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));}else {this.importStack.push(configClass);try {processConfigurationClass(candidate.asConfigClass(configClass));}finally {this.importStack.pop();}}}}}
在处理内部类中会继续调用processConfigurationClass方法。此时的入参会将内部类A封装成ConfigurationClass类。 // **2** 处理Component中包含ComponentScans注解的去扫描其他Component对象并直接注册成Bean。在 // ** 2.1 ** 方法中实现。
// **3** 处理Import注解。该方法会将Import分为三类。一类是ImportSelector例如EnableAutoConfiguration中的AutoConfigurationImportSelector。第二类是ImportBeanDefinitionRegistrar。第三类就当作Component继续处理。代码如下
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,CollectionSourceClass importCandidates, boolean checkForCircularImports) {if (importCandidates.isEmpty()) {return;}if (checkForCircularImports isChainedImportOnStack(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));}else {this.importStack.push(configClass);try {for (SourceClass candidate : importCandidates) {if (candidate.isAssignable(ImportSelector.class)) {// Candidate class is an ImportSelector - delegate to it to determine importsClass? candidateClass candidate.loadClass();ImportSelector selector BeanUtils.instantiateClass(candidateClass, ImportSelector.class);ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);if (selector instanceof DeferredImportSelector) {this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);}else {String[] importClassNames selector.selectImports(currentSourceClass.getMetadata());CollectionSourceClass importSourceClasses asSourceClasses(importClassNames);processImports(configClass, currentSourceClass, importSourceClasses, false);}}else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar -// delegate to it to register additional bean definitionsClass? candidateClass candidate.loadClass();ImportBeanDefinitionRegistrar registrar BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());}else {// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -// process it as an Configuration classthis.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());processConfigurationClass(candidate.asConfigClass(configClass));}}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException(Failed to process import candidates for configuration class [ configClass.getMetadata().getClassName() ], ex);}finally {this.importStack.pop();}}}
// **4** 处理类中带Bean的方法。SetMethodMetadata beanMethods retrieveBeanMethodMetadata(sourceClass);方法获取每个方法中带有Bean注解的方法。 private SetMethodMetadata retrieveBeanMethodMetadata(SourceClass sourceClass) {AnnotationMetadata original sourceClass.getMetadata();SetMethodMetadata beanMethods original.getAnnotatedMethods(Bean.class.getName());..............}
并且加入到之前封装的configClass的beanMethod方法中 SetMethodMetadata beanMethods retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}
至此刚才的processConfigBeanDefinitions(registry);方法的parse方法就完事了。把上面的代码站下来。 SetBeanDefinitionHolder candidates new LinkedHashSet(configCandidates);SetConfigurationClass alreadyParsed new HashSet(configCandidates.size());do {parser.parse(candidates);parser.validate();SetConfigurationClass configClasses new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader null) {this.reader new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);
执行完 parser.parse(candidates) 此时Spring容器中装载的Bean有 DemoApplication 扫描下的所有Component注解的类以及该类中包含ComponentScan路径下带有Component注解的类。至于内部类和Import中的第二类ImportBeanDefinitionRegistrar以及BeanMethod还没有装载。
继续执行this.reader.loadBeanDefinitions(configClasses); public void loadBeanDefinitions(SetConfigurationClass configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator new TrackedConditionEvaluator();for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}}private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {// 1if (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;}// 2if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);}// 3for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());// 4loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}
//1判断之前生成的configclass 是否符合注入条件就是判断包含的Conditional注解。如果不符合直接return
//2判断是否为内部类如果是且带Component就注入。比如 A 类中有内部类B且类B也有Component注解那么此时Spring容器才会将B注入。
//3将之前类中包含Bean的method方法注入Spring容器中当作Bean对象。
//4注入实现ImportBeanDefinitionRegistrar接口的类比如aop的AspectJAutoProxyRegistrar。
【总结】
1、执行完 parser.parse(candidates) 此时Spring容器中装载的Bean有 DemoApplication 扫描下的所有Component注解的类以及该类中包含ComponentScan路径下带有Component注解的类。
2、注入内部类
3、注入Bean方法
4、注入实现ImportBeanDefinitionRegistrar接口的类