美文网首页SpringSpring源码走读
Spring之Bean加载-解析-生命周期

Spring之Bean加载-解析-生命周期

作者: 南乡清水 | 来源:发表于2018-08-16 21:38 被阅读213次

1 概要

使用Spring框架,我们需要了解Bean的创建加载过程,需要熟悉Bean是如何获取和使用的。
下面我们通过分析下Spring加载XML文件的过程来分析Bean的数据流。
当前调试的Spring 版本是最新的 4.1.0 release 版本

调试代码主入口

 ApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
        System.out.println("Consumer Started");
        ConsumerBean bean = context.getBean(ConsumerBean.class);
        String secretKey = bean.getProperties().getProperty("SecretKey");
        System.out.println(secretKey);

2 解析过程

创建 ClassPathXmlApplicationContext对象,会调用refresh()方法

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // 获取xml文件的信息,存储在beanFactory对象中
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        .................省略中间代码

                // 注册bean信息
                invokeBeanFactoryPostProcessors(beanFactory);
                // 实例化bean
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

之后会进入AbstractApplicationContext对象,处理如下方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化DefaultListableBeanFactory对象和DefaultSingletonBeanRegistry对象
        refreshBeanFactory(); 

        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

接下来的数据调用链:
getBeanFactory() --> loadBeanDefinitions(beanFactory)

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        //创建XmlBeanDefinitionReader对象用于解析xml
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
//载入xml信息
        loadBeanDefinitions(beanDefinitionReader);
    }

最终会进入loadBeanDefinitions()方法,来载入xml

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

使用EncodeResource封装资源文件。如指定编码则使用指定编码读取资源
判断该资源是否已经加载过
构造InputStream实例,然后调用 doLoadBeanDefinitions() 方法

解析XML文件内容,得到一个Document对象

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
    //通过dom框架解析成Document对象
            Document doc = doLoadDocument(inputSource, resource);
//缓存每个bean的信息
            return registerBeanDefinitions(doc, resource);
        }

}

封装成BeanDefinition对象过程

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        documentReader.setEnvironment(this.getEnvironment());
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
//获取bean标签元素
        Element root = doc.getDocumentElement();
        doRegisterBeanDefinitions(root);
    }

最终处理的方法

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

    ........省略
        BeanDefinition oldBeanDefinition;

        synchronized (this.beanDefinitionMap) {
            oldBeanDefinition = this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) {
                if (!this.allowBeanDefinitionOverriding) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                            "': There is already [" + oldBeanDefinition + "] bound.");
                }
                else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                    // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                                " with a framework-generated bean definition ': replacing [" +
                                oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
                else {
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Overriding bean definition for bean '" + beanName +
                                "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                }
            }
            else {
                this.beanDefinitionNames.add(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

最后xml的的信息会存入DefaultListableBeanFactoryprivate final Map<String, BeanDefinition> beanDefinitionMap对象中

在执行invokeBeanFactoryPostProcessors(beanFactory)方法和finishBeanFactoryInitialization(beanFactory)方法的时候,会将beanDefinitionMap中的信息实例化具体bean对象,其主要过程如下:

public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        List<String> beanNames;
        synchronized (this.beanDefinitionMap) {
            // Iterate over a copy to allow for init methods which in turn register new bean definitions.
            // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
            beanNames = new ArrayList<String>(this.beanDefinitionNames);
        }

        // Trigger initialization of all non-lazy singleton beans...
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        ............................
                }
                else {
                    getBean(beanName);
                }
            }
        }

缓存Bean的过程

    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }

在 DefaultSingletonBeanRegistry中private final Map<String, Object> singletonObjects属性中缓存bean对象

3 获取Bean

方法调用链如下:
getBeanFactory().getBean(requiredType) --> doGetBean(name, requiredType, args, false) --> Object sharedInstance = getSingleton(beanName)

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

获取bean方法就很明显了,默认的单例对象,会在singletonObjects中获取

4 Bean生命周期

Spring Bean 的生命周期状态图如下:


生命周期

4.1 BeanNameAware

Spring Bean存活于容器之中,如果需要知道Bean的beanName,即可让该bean的类实现BeanNameAware接口


class UserBean implements BeanNameAware{

    private String name;

    @Override
    public void setBeanName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

consumer.xml中注入bean

<bean id="aaa" class="com.aliyun.openservices.spring.example.normal.UserBean" >
    </bean>

运行代码

ApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
        UserBean userBean = context.getBean(UserBean.class);
        System.out.println(userBean.getName());

这样控制台就能打印出结果,获取到UserBean的beanName是 aaa

4.2 ApplicationContextAware

该接口用于获取ApplicationContext的上下文,获取spring的一些信息

@Component
public class SpringBootTestAware implements ApplicationContextAware {
    private ApplicationContext applicationContext ;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext ;
    }
}

这样我们就可以拿到ApplicationContext的对象做一些处理

4.3 InitializingBean

如果希望在bean的属性被创建后,做些额外处理,则可以考虑让这个bean实现InitializingBean接口。InitializingBean接口中的方法afterPropertiesSet()可以实现所需要的工作

在bean的声明周期中,afterPropertiesSet()方法的调用介于postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法之间。

public abstract class AbstractFdxProcessor implements FdxProcessor, InitializingBean, BeanNameAware/*, BeanPostProcessor*/ {

    //实现 BeanNameAware 接口,为了获得每个processor 在 Spring context 中的 beanName
    //实现 InitializingBean 接口(Spring 提供的一些生命周期接口中的一个),在 Spring 完成该Bean初始化之后,将 beanName 注册到注册中心去
    @Autowired
    private FdxProcessorRegistry fdxProcessorRegistry;

    protected String beanName;

    @Override
    public void setBeanName(String name) {
        beanName = name;
    }

    protected abstract FdxProcessorRegistry.FdxKeyPair getKeyPair();

    @Override
    public void afterPropertiesSet() throws Exception {
        fdxProcessorRegistry.put(getKeyPair(), beanName);
    }

}

@Service
public class XxxFdxProcessorImpl extends AbstractFdxProcessor{
    @Override
    public void process(FdxDto<?> fdxDto) {
        //do business
    }

    @Override
    protected FdxProcessorRegistry.FdxKeyPair getKeyPair() {
        return new FdxProcessorRegistry.FdxKeyPair("XXX","XXX");
    }
}

实际业务中,可以根据不同的beanName做缓存,然后路由到不同的业务,很适合if比较多的语句

4.4 自定义初始化和销毁方法

@Component
class StartAndDestroyBean {

    private final static Logger LOGGER = LoggerFactory.getLogger(StartAndDestroyBean.class);

    @PostConstruct
    public void start(){
        LOGGER.error("init-method start");
    }
    @PreDestroy
    public void destroy(){
        LOGGER.error("destroy-method start");
    }
}

4.5 BeanPostProcessor

BeanPostProcessor接口则可以提供全局的、定制多个bean的初始化过程。BeanPostProcessor接口有两个方法:postProcessBeforeInitialization()方法在bean的属性值设置之前执行;postProcessAfterInitialization()方法在bean的属性值设置之后执行。

public abstract class AbstractFdxProcessor implements FdxProcessor, BeanPostProcessor {

    //实现 BeanNameAware 接口,为了获得每个processor 在 Spring context 中的 beanName
    //实现 InitializingBean 接口(Spring 提供的一些生命周期接口中的一个),在 Spring 完成该Bean初始化之后,将 beanName 注册到注册中心去
    @Autowired
    private FdxProcessorRegistry fdxProcessorRegistry;

    protected String beanName;

    protected abstract FdxProcessorRegistry.FdxKeyPair getKeyPair();

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        FdxCategory fdxCategory = bean.getClass().getAnnotation(FdxCategory.class);
        //通过 fdxCategory 拿到 category, 作为 key 和 beanName 一起进入注册中心完成注册
        return new Object();
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException{
        return bean;
    }
}

可以过滤出固定的bean做一些处理

4.6 DisposableBean

实现该对象,需要重写销毁方法

@Service
public class SpringBootTest implements DisposableBean{
    private final static Logger LOGGER = LoggerFactory.getLogger(SpringBootTest.class);

    @Override
    public void destroy() throws Exception {
        LOGGER.info("destroy-method");
    }
}

该方法会在自定义销毁方法前调用

Reference

Life Cycle Management of a Spring Bean

相关文章

网友评论

本文标题:Spring之Bean加载-解析-生命周期

本文链接:https://www.haomeiwen.com/subject/kilwbftx.html