Spring extension and initialization process analysis

Spring related

The following analysis is based on Spring-4.3.10 version

namespace extension

The namespace extension (Schema extension) in Spring uses the JAVA SPI mechanism , and the specific implementation is as follows:

  1. Add the spring.handlers file in the META-INF directory of your jar package

  2. The contents of the file are as follows:

    http://lj.test.spring.org/schema/test=org.lj.test.spring.schema.TestNamespaceHandler
  3. Write the namespace resolution class org.lj.test.spring.schema.TestNamespaceHandler, which is recommended to inherit from the NamespaceHandlerSupport class. Used to register tag names and corresponding resolvers.

    public class TestNamespaceHandler extends NamespaceHandlerSupport {
       public void init() {
           registerBeanDefinitionParser("test", new TestBeanDefinitionParser(TestConfig.class, true));
       }
    }
  4. Write the TestBeanDefinitionParser class, which is used to parse the xml into a BeanDefinition. This class is the Bean definition class in Spring and is used to return the actual Bean during coding.

  5. Declare the namespace in the spring configuration file and use the annotation:

    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:test="http://lj.test.spring.org/schema/test"
          xmlns="http://www.springframework.org/schema/beans"
          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
          http://lj.test.spring.org/schema/test http://lj.test.spring.org/schema/test/test.xsd">
    <test:test name="demo-test"/>
    </beans>

Context initialization

The following takes ClassPathXmlApplicationContext as an example to outline the instantiation and initialization process of ApplicationContext. Other Contexts are similar.

  1. set parent container
  2. Set the configuration file path. (AbstractApplicationContext.refresh())
  3. Record the startup time and set the Context state to active, set the initialization properties and verify the required environment variables set through ConfigurablePropertyResolver#setRequiredProperties, and instantiate the broadcaster initial event list collection. (AbstractApplicationContext.prepareRefresh())
  4. Get and refresh the BeanFactory inside the Context. (AbstractApplicationContext.obtainFreshBeanFactory())
    • Destroy the original BeanFactory that may exist
    • Create a new BeanFactory, the default is the DefaultListableBeanFactory class instance, and set its parent BeanFactory, serialization ID
    • Configure custom properties of BeanFactory, such as whether to allow beans with the same name, Bean circular dependencies, whether to ignore lazy-init loading (allowEagerClassLoading), whether to inject in circular dependencies (allowRawInjectionDespiteWrapping), etc.
    • Load BeanDefinition from the configuration file. Different Contexts have different implementations. When the namespace extension is called here, the registered BeanDefinitionParser interface implements the class to load BeanDefinition .
  5. Set the public properties of the BeanFactory. AbstractApplicationContext.prepareBeanFactory(ConfigurableListableBeanFactory)
    • Set the class loader, expression parser, and bean property editor when creating a bean
    • Add Bean creation post-processor ApplicationContextAwareProcessor (BeanPostProcessor, AOP is implemented through the implementation class AspectJAwareAdvisorAutoProxyCreator of this interface )
    • Add interfaces that are ignored during auto-injection
    • Register the automatic injection type and the corresponding value with a fixed value, that is to say, the corresponding type injected during the automatic injection process is fixed and unchanged.
    • According to the BeanDefinition in the BeanFactory, register a special Bean (loadTimeWeaver, environment, systemProperties, systemEnvironment)
  6. Execute BeanFactory post-processing logic for subclasses to add unique logic. AbstractApplicationContext.postProcessBeanFactory(ConfigurableListableBeanFactory)
  7. Call the post-processor of the BeanFactory in the Context (the BeanFactoryPostProcessor interface implementation class). The post-processor can be derived from the BeanDefinition in the BeanFactory. AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)
  8. Register the Bean PostProcessor (BeanPostProcessor) contained in the BeanDefinition in the BeanFactory, where the AOP Bean PostProcessor is registered. AbstractApplicationContext.registerBeanPostProcessors(ConfigurableListableBeanFactory)
  9. Initialize the resource string data source, which is used to obtain the internationalized resource string in the Context. By default, the Bean whose ID is messageSource is obtained from the BeanDefinition. If it cannot be obtained, the default DelegatingMessageSource class instance is used. AbstractApplicationContext.initMessageSource()
  10. Initializes the application event broadcaster (ApplicationEventMulticaster) in the context to broadcast context events. The Bean whose ID is applicationEventMulticaster in the BeanDefinition is preferentially used, and the SimpleApplicationEventMulticaster is used if it cannot be obtained. AbstractApplicationContext.initApplicationEventMulticaster()
  11. Call the onrefresh template method of Context. AbstractApplicationContext.onRefresh()
  12. Registers an application listener (from a direct registration or a bean of type ApplicationListener) with the application event broadcaster, and fires the events in the broadcaster's initial event list collection. AbstractApplicationContext.registerListeners()
  13. Complete BeanFactory initialization and initialize singleton, non-lazy loaded beans. finishBeanFactoryInitialization(ConfigurableListableBeanFactory)
    • If the bean is a factory bean (the implementation class of the FactoryBean interface), add & before beanName to identify it for subsequent instantiation.
    • If the singleton class implements the SmartInitializingSingleton interface, its afterSingletonsInstantiated method is called.
  14. Finally complete the initialization of Context. AbstractApplicationContext.finishRefresh()
    • To initialize the lifecycle processor, the Bean whose ID is lifecycleProcessor in the BeanDefinition is preferentially used, and the DefaultLifecycleProcessor is used if it cannot be obtained.
    • Trigger the onRefresh event of the life cycle processor (ContextRefreshedEvent, dubbo listens for this event)
    • Trigger the ContextRefreshedEvent event via the event broadcaster
    • Register this Context with JMX

Summarize

  • Context instantiation obviously uses the template (method) pattern to achieve initialization.
  • Context is essentially a wrapper for BeanFactory, adding support for features such as event mechanism and internationalized resource strings.
  • Context will automatically register some special types of BeanDefinition to BeanFactory, such as BeanPostProcessor type or other special name Bean.
  • Context will customize the BeanFactory according to its own usage scenarios, including ignoring the injection interface, setting fixed injection objects, etc.
  • The framework and application itself can support JMX through simple code to improve maintainability.
  • Context life cycle events inherit from the ApplicationEvent class.

Bean initialization

The following only records the approximate and key processes and related method names. The initial method entry is AbstractBeanFactory.doGetBean.

  1. Obtain the actual beanName according to the beanName, mainly dealing with the alias and FactoryBean name.
  2. Attempt to get the bean instance from the cache.
  3. If the bean is a FactoryBean, call its getObject to return the object, otherwise return the cached instance directly. Skip the next steps.
  4. Check for circular dependencies.
  5. If this level does not contain the BeanDefinition corresponding to the bean, try to obtain the corresponding BeanDefinition from the parent BeanFactory.
  6. The marker bean has been created.
  7. Get its corresponding RootBeanDefinition according to the bean.
  8. Check bean dependencies and register and instantiate dependent beans.
  9. If the bean is a singleton, create the bean logic (createBean) by calling the singleton method, and add and delete the current bean to the concurrenthashmap before and after creation to avoid repeated creation.
  10. If the bean is prototype, directly call the create bean logic (createBean), and register and delete the beanName with ThreadLocal before and after creation.
  11. If it is another Scope, the bean logic is created by calling the scope's get method , and the beanName is registered with ThreadLocal before and after creation, and the beanName is deleted.
  12. Convert the instanced bean to the data type specified by the parameter through the type converter.

Create bean logic

The method entry is AbstractBeanFactory.createBean(name, RootBeanDefinition, args).

  1. Get the actual RootBeanDefinition of the bean.
  2. Check for overloaded methods inside the bean.
  3. Try to call the InstantiationAwareBeanPostProcessor method of the BeanPostProcessor sub-interface. If it returns null, continue to create the bean, otherwise directly return to process the generated bean ( AOP works here, and the injection of Aware is also implemented here ). AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation()
  4. Directly call the default constructor or the constructor with parameters for instantiation to generate a BeanWrapper instance.
  5. Call the BeanPostProcessor sub-interface MergedBeanDefinitionPostProcessor to process the instantiated bean. AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors()

Summarize

  • The overall structure of Context loading Bean in Spring is similar to Tomcat's class loader mechanism (different from parental delegation), that is, it is first loaded by this BeanFactory, and the Bean is loaded from the parent BeanFactory if it is not found .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324662954&siteId=291194637