spring loaded bean flow analysis

spring framework as a basis for the development of our current daily basic development work and his inseparable, as most classic bean management, excellent framework, its complexity is often prohibitive. But as a framework for daily life, we have to understand a problem that spring is how to load the bean, notes that we often use in development such as @ Component, @ AutoWired, @ Socpe such as annotation, how Spring is resolved, understand these principles will help us to a deeper understanding of the spring. It should be noted that the source is spring very sophisticated, complex, limited to limited space, this blog will not be detailed analysis of the source code, will take a careful look at the way, avoid the light weight, seize the key to the entire process analysis (analysis does not specific details), this will be based on the version spring5.0

This blog directories:

A: spring configuration or reading process annotations

Two: bean life cycle of spring

Three: spring of BeanPostProcessor processor

Four: Some key issues

Five: Testing

Six: summary 

A: spring configuration or reading process annotations 

1: first specify the annotation by scanning the spring package path, such as spring identification @ Component, @ Service, @ Lazy @Sope attribute xml or other annotations configured (by reading the stream into a parse Document, Document) will then spring resolve these properties, these properties BeanDefintaion encapsulates the implementation of the interface class.

In springboot, we can also be used to configure the way notes:

 This configuration example Bean, spring will also className, scope, lazy, etc. These properties are fitted into the corresponding BeanDefintaion PersonAction in particular uses BeanDefinitionParser interface parse (Element element, ParserContext parserContext) method, this interface there are many different implementations class. Notes to parse through the implementation class or xml and then put BeanDefination, the role BeanDefintaion that integrates a variety of attributes our configuration objects, it is important to have this bean is ClassName, if there is Singleton, attributes and values ​​such as object (if single embodiment, it will be behind the singleton object into a single cell embodiment of the spring). If you need late spring directly from these properties will be in it. Then, re-registration to a ConcurrentHashMap, the spring in particular is to registerBeanDefinition (), the Map stored key is the name of the object, such as Person object, its name is the person, the value is BeanDefination, which is located DefaultListableBeanFactory class below the beanDefinitionMap class attribute while all put into beanDefinitionNames bean name in the list, the purpose is easy to take the beanName;

Two: bean life cycle of spring

In fact, the life cycle of bean spring core is divided into four steps, as long as the three key steps to sort out, others just add different details to achieve in these three details, that is spring of bean Shengming cycle:

The difference between instantiation and initialization : instantiation in jvm heap created the object instance, this time it's just an empty object, all the property is null. And after the initialization process is to talk about some of the properties of the object-dependent assignment, call some method to open some default load. A database configured such spring properties Bean, at initialization time will fill these properties, such as driver, jdbcurl the like, and then initiates the connection

2.1: instantiation Instantiation

     AbstractAutowireCapableBeanFactory.doCreateBean will call createBeanInstance () method, which is the main phase from beanDefinitionMap bean read cycle, acquiring its properties, and the use of reflection (ReflectionUtil there will first force the constructor setAccessible (true the core package)) object to be read constructor (spring will automatically determine if there is no parameter or parameters, and the constructor parameter is available), and then to create an instance (the newInstance)

2.2: Initialization

   Initialization consists of two steps, a property is filled, the other is a specific initialization process

2.2.1: property assignment PopulateBean () will depend on the properties of the bean filling, @ AutoWired annotation injected properties occurs at this stage, if we have a lot of bean depend on, then spring will in turn call these dependent objects instantiated of note here may have a circular dependency problem. Later we will talk about how to solve the spring is a circular dependency problem

2.2: Initialization Initialization

       The initialization process includes the initialization good bean to spring into the cache, filling our pre attributes do further post-processing, etc.
3: use and destruction of Destruction

      After all Spring bean initialization are good, our business systems can be called up. The destruction of the main operation is the destruction of bean, the main spring is accompanied by closed container, this time will be removed in spring of bean container. After this spring's life cycle to the end of this step is complete, no longer accept the management and restraint spring.

Three: spring of BeanPostProcessor processor

Another power of spring is to allow developers to extend the definition of self-initialization process the bean, the main idea is realized by BeanPostProcessor achieved, spring a variety of pre- and post-processors that permeate created in bean the Ins and Outs, interspersed at various stages of the life cycle of spring, every step will affect the spring of bean loading process. Next we have to analyze specific process:

 

 3.1: Examples stage

Examples of, after performing the instantiation, the calls InstantiationAwareBeanPostProcessor postProcessBeforeInstantiation method calls the empty stage of object's constructor object

The BeanPostProcessor (the specific implementation is InstantiationAwareBeanPostProcessor) postProcessBeforeInstantiation ().;

This stage allows the previous instantiated in Bena, allowing developers to custom logic, such as returning a proxy object. But note that if returned at this stage is not a null instance of, spring break will be the follow-up process.
BeanPostProcessor.postProcessAfterInstantiation ();

This stage is performed after the post-processing operation is completed Bean instantiated, executed before all initialization logic, the logic assembly

3.2:初始化阶段

3.2.1:BeanPostProcessor.postProcessBeforeInitialization

该方法在bean初始化方法前被调用,Spring AOP的底层处理也是通过实现BeanPostProcessor来执行代理逻辑的

3.2.2:InitializingBean.afterPropertiesSet

自定义属性值 该方法允许我们进行对对象中的属性进行设置,假如在某些业务中,一个对象的某些属性为null,但是不能显示为null,比如显示0或者其他的固定数值,我们就可以在这个方法实现中将null值转换为特定的值

3.2.3:BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)。可以在这个方法中进行bean的实例化之后的处理,比如我们的自定义注解,对依赖对象的版本控制自动路由切换。比如有一个服务依赖了两种版本的实现,我们如何实现自动切换呢?这时候可以自定义一个路由注解,假如叫@RouteAnnotaion,然后实现BeanPostProcessor接口,在其中通过反射拿到自定义的注解@RouteAnnotaion再进行路由规则的设定。


3.2.4:SmartInitializingSingleton.afterSingletonsInstantiated

4.1:容器启动运行阶段

4.1.1:SmartLifecycle.start

容器正式渲染完毕,开始启动阶段,bean已经在spring容器的管理下,程序可以随时调用

5.1:容器停止销毁
5.1.1:SmartLifecycle.stop(Runnable callback) 

spring容器停止运行
5.1.2:DisposableBean.destroy()

spring会将所有的bean销毁,实现的bean实例被销毁的时候释放资源被调用

四:一些关键性的问题

4.1:FactoryBean和BeanFactory的区别?

BeanFactory是个bean 工厂类接口,是负责生产和管理bean的工厂,是IOC容器最底层和基础的接口,spring用它来管理和装配普通bean的IOC容器,它有多种实现,比如AnnotationConfigApplicationContext、XmlWebApplicationContext等。

FactoryBean是FactoryBean属于spring的一个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理,生产的对象是由getObject()方法决定的。注意:它是泛型的,只能固定生产某一类对象,而不像BeanFactory那样可以生产多种类型的Bean。在对于某些特殊的Bean的处理中,比如Bean本身就是一个工厂,那么在其进行单独的实例化操作逻辑中,可能我们并不想走spring的那一套逻辑,此时就可以实现FactoryBean接口自己控制逻辑。

4.2:spring如何解决循环依赖问题

循环依赖问题就是A->B->A,spring在创建A的时候,发现需要依赖B,因为去创建B实例,发现B又依赖于A,又去创建A,因为形成一个闭环,无法停止下来就可能会导致cpu计算飙升

如何解决这个问题呢?spring解决这个问题主要靠巧妙的三层缓存,所谓的缓存主要是指这三个map,singletonObjects主要存放的是单例对象,属于第一级缓存;singletonFactories属于单例工厂对象,属于第二级缓存;earlySingletonObjects属于第二级缓存,如何理解early这个标识呢?它表示只是经过了实例化尚未初始化的对象。Spring首先从singletonObjects(一级缓存)中尝试获取,如果获取不到并且对象在创建中,则尝试从earlySingletonObjects(二级缓存)中获取,如果还是获取不到并且允许从singletonFactories通过getObject获取,则通过singletonFactory.getObject()(三级缓存)获取。如果获取到了则则移除对应的singletonFactory,将singletonObject放入到earlySingletonObjects,其实就是将三级缓存提升到二级缓存,这个就是缓存升级。spring在进行对象创建的时候,会依次从一级、二级、三级缓存中寻找对象,如果找到直接返回。由于是初次创建,只能从第三级缓存中找到(实例化阶段放入进去的),创建完实例,然后将缓存放到第一级缓存中。下次循环依赖的再直接从一级缓存中就可以拿到实例对象了。

  五:测试

我们来写一个测试类,验证一下上面的问题:

5.1:首先声明一个自定义的Bean

@Component
public class CustomBean {
    public CustomBean(){
        System.out.println("调用CustomBean空的构造方法");
    }
}

5.2:声明一个Bean来实现BeanPostProcessor

package com.wyq.spring.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.beans.PropertyDescriptor;

/**
 * @Author: wyq
 * @Desc:
 * @Date: 2019/9/1 15:36
 **/
@Component
@Scope("singleton")
public class TestBean implements BeanPostProcessor, SmartInitializingSingleton, InstantiationAwareBeanPostProcessor, DisposableBean{

    private static final String BEAN_NAME= "customBean";

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (BEAN_NAME.equals(beanName)) {
            System.out.println("==>BeanPostProcessor.postProcessBeforeInitialization");
        }
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (BEAN_NAME.equals(beanName)) {
            System.out.println("==>BeanPostProcessor.postProcessAfterInitialization");
        }
        return null;
    }


    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("==>SmartInitializingSingleton.afterSingletonsInstantiated");

    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (BEAN_NAME.equals(beanName)) {
            System.out.println("==>InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation");
        }
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (BEAN_NAME.equals(beanName)) {
            System.out.println("==>InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation");
        }
        return false;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("==>InstantiationAwareBeanPostProcessor.postProcessPropertyValues");
        return null;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("==>DisposableBean.destroy");
    }
}

5.3:启动容器:

六:总结

      本篇博客主要是介绍了Spring的一些实例化的过程,高屋建瓴的分析了一下spring的bean加载过程,没有详细展开某个细节分析。spring的内部源码非常复杂,每个接口的实现类都在5个以上,如果深入细节,恐怕不是一篇博客能讲清楚的。这篇博客的目的就是在阐述spring的基本脉络中心路线顺序,首先我们需要有一个总体的认识,然后再深入到细节就是轻而易举的了。这也是一种学习的方法论,通过本篇博客我希望能梳理清楚spring的基本流程,对spring有一个比较清晰的认识。并且学习到优秀开源框架的设计基本思想,还有就是进一步提升自己的阅读源码的能力。

 

Guess you like

Origin www.cnblogs.com/wyq178/p/11415877.html