Spring IOC source code parsing based on annotations, version 5.1.x
Initializing bean s through the Spring context
Annotation class, annotationconfigpplicationcontext can be used to load Spring context based on java configuration class (various annotations), which is better than using application.xml More concise and convenient.
package com.jingjing.spring; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; /** * Which directory bean s need to be scanned * Created by yuanqingjing on 2020/3/7 */ @ComponentScan("com.jingjing") public class Test { public static void main(String[] args) { /** * Initialize bean init * 1.Scan the class * 2.Instantiate bean */ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test.class); BeanTest beanTest= context.getBean(BeanTest.class); System.out.println(beanTest); } }
package com.jingjing.spring; import org.springframework.stereotype.Component; /** * Created by yuanqingjing on 2020/3/7 */ @Component public class BeanTest{ public BeanTest() { System.out.println("init"); } }
Annotationconfidapplicationcontext constructor
/** * Register the bean s in the corresponding configuration class into the container * Create a new annotation configuration context, get bean definitions from the annotatedClasses configuration class, and then * bean definition Update to context * Create a new AnnotationConfigApplicationContext, deriving bean definitions * from the given annotated classes and automatically refreshing the context. * @param annotatedClasses one or more annotated classes, * e.g. {@link Configuration @Configuration} classes */ public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { //Because it has a parent class, it will first call the parent class constructor, and then call its own constructor //Initializing a reader and a scanner in your own constructor //The parent class constructor creates a beanfactory defaultlistablebeanfactory this(); //Turn annotation class into a BeanDefinition register(annotatedClasses); //Scan the Class, change the Class under these paths into a BeanDefinition, and then change some beandefinitions into bean objects refresh(); }
this() method parsing
Annotationconfiguapplicationcontext inherits from GenericApplicationContext
/** * The parent class GenericApplication default constructor creates a BeanFactory * DefaultListableBeanFactory,A very important BeanFactory * Create a new GenericApplicationContext. * @see #registerBeanDefinition * @see #refresh */ public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
/** * Default constructor * Create an annotation based BeanDefinition reader * Create a BeanDefinition scanner that scans the path * Create a new AnnotationConfigApplicationContext that needs to be populated * through {@link #register} calls and then manually {@linkplain #refresh refreshed}. */ public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
Analysis of register (annotated classes) method
/** *It's actually calling the register method of the AnnotatedBeanDefinitionReader class */ public void register(Class<?>... annotatedClasses) { Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); this.reader.register(annotatedClasses); }
The core logic is the doRegisterBean() method of AnnotatedBeanDefinition
public void register(Class<?>... annotatedClasses) { Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified"); this.reader.register(annotatedClasses); } public void registerBean(Class<?> annotatedClass) { doRegisterBean(annotatedClass, null, null, null); } /** * Register a bean from the given bean class, deriving its metadata from * class-declared annotations. * @param annotatedClass the class of the bean * @param instanceSupplier a callback for creating an instance of the bean * (may be {@code null}) * @param name an explicit name for the bean * @param qualifiers specific qualifier annotations to consider, if any, * in addition to qualifiers at the bean class level * @param definitionCustomizers one or more callbacks for customizing the * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @since 5.0 */ <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { //Change the configuration class to AnnotatedGenericBeanDefinition, which inherits BeanDefinition, //The function is to define the data structure of a bean. getmetadata() can get the annotation information on the bean AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); //@Conditional assembly condition judge whether to skip registration if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } //Set callback abd.setInstanceSupplier(instanceSupplier); //Resolve the bean Scope (singleton or prototype). If @ Scope annotation is available, the bean Scope will be resolved. Otherwise, singleton will be the default ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); //Scope written back to beandefinition abd.setScope(scopeMetadata.getScopeName()); //Generate bean configuration class beanName String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); //The general annotation is parsed into the BeanDefinition structure, mainly dealing with the five annotations of lazy Primary DependsOn Role Description AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); //@Qualifier special qualifier handling if (qualifiers != null) { for (Class<? extends Annotation> qualifier : qualifiers) { //If the Primary annotation is configured, set the current bean as the preferred bean when autowire is automatically assembled if (Primary.class == qualifier) { abd.setPrimary(true); } //Set lazy load to delay load else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { //Add additional annotations to the abd structure abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } //The user-defined bean registration is usually used after the applicationContext is created to manually register the bean in the way of - lambda expression in the container // applicationContext.registerBean(Test.class,()->new Test()); for (BeanDefinitionCustomizer customizer : definitionCustomizers) { //Custom bean added to BeanDefinition customizer.customize(abd); } //Encapsulate a bean definition holder according to bean name bean definition information BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); //Create proxy object definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); //Go deep into the code to find out whether the registerBeanDefinition() of DefaultListableBeanFactory is the last call //The logic is to put beanname and beandefinition into BeanDefinitionMap of BeanFactory BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); }
In fact, the register method mainly completes the parsing and registration of configuration classes, mainly including the following steps
1. The class annotatedClass will be configured, and the Bean definition will be used to resolve the definition information of the Bean, mainly some annotation information
2.bean Scope processing. If there is @ Scope scope, it will return to the Scope. If there is no Scope, it will be Singleton by default
3. Parsing common annotations with annotations configutils
4. Register bean name (bean definition) to the Ioc container
Analysis of refresh method
The refresh() method is implemented in the AbstractApplicationContext class. The main function of this class is to load or refresh the current configuration information. If a Spring container already exists, first destroy the Spring container, recreate the Spring container, load the bean definition, and complete the initialization of the container. It can be seen that the annotationconfigpplicationcontext container starts the whole Ioc container by calling the refresh method of its parent class AbstractApplicationContext to load and initialize the bean definition
1. Refresh preprocessing
AbstractApplicationContext.prepareRefresh()
protected void prepareRefresh() { // Switch to active. //Set container start time this.startupDate = System.currentTimeMillis(); //Start identification this.closed.set(false); this.active.set(true); if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) { logger.trace("Refreshing " + this); } else { logger.debug("Refreshing " + getDisplayName()); } } // Initialize any placeholder property sources in the context environment. //Empty method, used for the property setting method of custom personalization of child containers initPropertySources(); // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties //Check the validity of attributes, etc getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners... // Early listeners to hold pre refreshed containers if (this.earlyApplicationListeners == null) { this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { // Reset local application listeners to pre-refresh state. this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... //Save early events in container this.earlyApplicationEvents = new LinkedHashSet<>(); }
2. The subclass refreshes the internal BeanFactory and obtains the refreshed BeanFactory
AbstractApplicationContext.obtainBeanFactory()
/** * Tell the subclass to refresh the internal BeanFactory * Tell the subclass to refresh the internal bean factory. * @return the fresh BeanFactory instance * @see #refreshBeanFactory() * @see #getBeanFactory() */ protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
Gener icApplicationContext.refreshBeanFactory And getBeanFactory
protected final void refreshBeanFactory() throws IllegalStateException { //The atomic operation of AtomicBoolean is used to assign a value to the refreshed variable. During initialization, the refreshed value is false. If the assignment fails, an exception is thrown to avoid multiple refreshes if (!this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } //Set the id unique id of the serialization id as annotationconfigpplicationcontext for BeanFactory this.beanFactory.setSerializationId(getId()); } public final ConfigurableListableBeanFactory getBeanFactory() { //Return to DefaultListableBeanFactory return this.beanFactory; }
The steps to refresh BeanFactory are as follows:
1. Set the updated value of annotationconfiguapplicationcontext to true
2. Set the serializationId of DefaultBeanFactory to the id of annotationconfidapplicationcontext
3. Preprocessing of beanfactory
Mainly complete the property setting of BeanFactory
/** * Complete the property setting of BeanFactory */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. //Set bean classloader to container classloader for BeanFactory beanFactory.setBeanClassLoader(getClassLoader()); //bean expression resolver beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //Property Edit registrar beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. //Configure beanFactory with context callback //Add a bean post processor to implement ApplicationContextAwareProcess beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //Set the ignored auto assembly interfaces, indicating that the implementation classes of these interfaces cannot be automatically injected through the interfaces beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. //Register components that can be automatically assembled, and components that allow automatic injection in any component beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. // Registering early PostProcessor with application listener to detect internal bean s beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. //Add AspectJ at compile time if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. //Register the Singleton component, configurableenvironment, SystemProperties, systemenvironment in the container and add them to singletonObjects (ConcurrentHashMap type) if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
5. Execute the BeanFactoryPostProcess method, the postprocessor of beanfactory, after the beanfactory standard is initialized
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<>(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! // Separate between BeanDefinitionRegistryPostProcessors that implement // PriorityOrdered, Ordered, and the rest. List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. boolean reiterate = true; while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } // Now, invoke the postProcessBeanFactory callback of all processors handled so far. invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the bean factory post-processors apply to them! String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, // Ordered, and the rest. List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have // modified the original metadata, e.g. replacing placeholders in values... beanFactory.clearMetadataCache(); }