spring bean 加载过程(spring)

以classpathXmlApplication为例

入口方法包含3个部分,

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

1.继承父类,没什么东西

2.设置配置文件

3.执行refresh方法(关键)。下面我们就这两个方法看看内部实现

设置配置文件,这块其实没什么东西,就是给context对象设置一个configLocations的数组,我们看一下context类的继承关系

下面看重点的refresh方法

 1 public void refresh() throws BeansException, IllegalStateException {
 2         synchronized (this.startupShutdownMonitor) {//锁住一个对象,防止多线程同时执行初始化的操作
 3             // Prepare this context for refreshing.准备上下文,这里设置一下开始实现,准备propery等
 4             prepareRefresh();
 5
 6             // Tell the subclass to refresh the internal bean factory.
 7             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 8
 9             // Prepare the bean factory for use in this context.
10             prepareBeanFactory(beanFactory);
11
12             try {
13                 // Allows post-processing of the bean factory in context subclasses.
14                 postProcessBeanFactory(beanFactory);
15
16                 // Invoke factory processors registered as beans in the context.
17                 invokeBeanFactoryPostProcessors(beanFactory);
18
19                 // Register bean processors that intercept bean creation.
20                 registerBeanPostProcessors(beanFactory);
21
22                 // Initialize message source for this context.
23                 initMessageSource();
24
25                 // Initialize event multicaster for this context.
26                 initApplicationEventMulticaster();
27
28                 // Initialize other special beans in specific context subclasses.
29                 onRefresh();
30
31                 // Check for listener beans and register them.
32                 registerListeners();
33
34                 // Instantiate all remaining (non-lazy-init) singletons.
35                 finishBeanFactoryInitialization(beanFactory);
36
37                 // Last step: publish corresponding event.
38                 finishRefresh();
39             }
40
41             catch (BeansException ex) {
42                 if (logger.isWarnEnabled()) {
43                     logger.warn("Exception encountered during context initialization - " +
44                             "cancelling refresh attempt: " + ex);
45                 }
46
47                 // Destroy already created singletons to avoid dangling resources.
48                 destroyBeans();
49
50                 // Reset ‘active‘ flag.
51                 cancelRefresh(ex);
52
53                 // Propagate exception to caller.
54                 throw ex;
55             }
56
57             finally {
58                 // Reset common introspection caches in Spring‘s core, since we
59                 // might not ever need metadata for singleton beans anymore...
60                 resetCommonCaches();
61             }
62         }
63     }

这个代码有点长,我们把每个方法干什么先研究一下,在深入看每个方法怎么实现的。

从7行开始看,这个方法是为了一个refreshBeanFactory。返回的类是ConfigurableListableBeanFactory,而这个factory是一个接口,我们待会看看这个接口有哪些实现,先看看这个方法内部实现

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

我们看到最后return的beanFactory就是ConfigurableListableBeanFactory。而这个接口只有一个default实现类DefaultListableBeanFactory。我们看看这个类主要有哪些成员变量

 1 private boolean allowEagerClassLoading = true;
 2
 3     /** Optional OrderComparator for dependency Lists and arrays */
 4     private Comparator<Object> dependencyComparator;
 5
 6     /** Resolver to use for checking if a bean definition is an autowire candidate */
 7     private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
 8
 9     /** Map from dependency type to corresponding autowired value */
10     private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<Class<?>, Object>(16);
11
12     /** Map of bean definition objects, keyed by bean name */
13     private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
14
15     /** Map of singleton and non-singleton bean names, keyed by dependency type */
16     private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
17
18     /** Map of singleton-only bean names, keyed by dependency type */
19     private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);
20
21     /** List of bean definition names, in registration order */
22     private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);
23
24     /** List of names of manually registered singletons, in registration order */
25     private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);
26
27     /** Cached array of bean definition names in case of frozen configuration */
28     private volatile String[] frozenBeanDefinitionNames;
29
30     /** Whether bean definition metadata may be cached for all beans */
31     private volatile boolean configurationFrozen = false;

这些成员变量有机会我们一个个分析下,我们知道每个bean 有一个beanDefinition对象来定义。在13行,我们看到有一个BeanDefinition的Map,我们随便调试一下,看看这个里面存了什么东西。

这里面竟然只有7个对象,分别是:ConfigurationClassPostProcessor、DefaultEventListenerFactory、MessageResolver、EventListenerMethodProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PropertiesFactoryBean、RequiredAnnotationBeanPostProcessor。这七个对象怎么来的呢,举个例子来看ConfigurationClassPostProcessor,这个类说明是,当配置文件中

Registered by default when using {@code <context:annotation-config/>} or
* {@code <context:component-scan/>}有这两个配置的时候,便会注入这么个类。好吧,那我们看看在哪里register的。我们猜测是在

refreshBeanFactory();这个方法里面。那看看这个方法
 1 protected final void refreshBeanFactory() throws BeansException {
 2         if (hasBeanFactory()) {
 3             destroyBeans();
 4             closeBeanFactory();
 5         }
 6         try {
 7             DefaultListableBeanFactory beanFactory = createBeanFactory();
 8             beanFactory.setSerializationId(getId());
 9             customizeBeanFactory(beanFactory);
10             loadBeanDefinitions(beanFactory);
11             synchronized (this.beanFactoryMonitor) {
12                 this.beanFactory = beanFactory;
13             }
14         }
15         catch (IOException ex) {
16             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
17         }
18     }

我们看到第7行,创建了一个DefaultListableBeanFactory ,第10行有loadBeanDefinition。应该是在这里处理的。我们还是先调试下看看。执行7行代码,这个时候beanDefinitionMap是空的。执行完10行代码,我们的beanDefinitionMap有值了。这里面为了加深理解,我们在我们的spring-config.xml文件中加一个bean看看会怎么样。原来的spring-config.xml文件如下

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:util="http://www.springframework.org/schema/util"
 6        xsi:schemaLocation="
 7            http://www.springframework.org/schema/beans
 8            http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
 9            http://www.springframework.org/schema/context
10            http://www.springframework.org/schema/context/spring-context-4.1.xsd
11            http://www.springframework.org/schema/util
12            http://www.springframework.org/schema/util/spring-util-4.1.xsd">
13
14     <context:annotation-config/>
15
16     <context:component-scan base-package="com.newbie.common"></context:component-scan>
17
18     <util:properties id="systemProperties" location="classpath:conf/user.properties" />
19
20
21 </beans>

我们随便加一个bean,如下图所示,有多个一个beanDefinition。所以这个地就是定义所以beanDefinition的入口,而我们从autowire的bean是由相关processor处理的,这个今后如果有时间的话,我们在分析。我们继续往下看

我们回到原来的refresh方法里面。

 1 public void refresh() throws BeansException, IllegalStateException {
 2         synchronized (this.startupShutdownMonitor) {
 3             // Prepare this context for refreshing.
 4             prepareRefresh();
 5
 6             // Tell the subclass to refresh the internal bean factory.
 7             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 8
 9             // Prepare the bean factory for use in this context.
10             prepareBeanFactory(beanFactory);
11
12             try {
13                 // Allows post-processing of the bean factory in context subclasses.
14                 postProcessBeanFactory(beanFactory);
15
16                 // Invoke factory processors registered as beans in the context.
17                 invokeBeanFactoryPostProcessors(beanFactory);
18
19                 // Register bean processors that intercept bean creation.
20                 registerBeanPostProcessors(beanFactory);
21
22                 // Initialize message source for this context.
23                 initMessageSource();
24
25                 // Initialize event multicaster for this context.
26                 initApplicationEventMulticaster();
27
28                 // Initialize other special beans in specific context subclasses.
29                 onRefresh();
30
31                 // Check for listener beans and register them.
32                 registerListeners();
33
34                 // Instantiate all remaining (non-lazy-init) singletons.
35                 finishBeanFactoryInitialization(beanFactory);
36
37                 // Last step: publish corresponding event.
38                 finishRefresh();
39             }
40
41             catch (BeansException ex) {
42                 if (logger.isWarnEnabled()) {
43                     logger.warn("Exception encountered during context initialization - " +
44                             "cancelling refresh attempt: " + ex);
45                 }
46
47                 // Destroy already created singletons to avoid dangling resources.
48                 destroyBeans();
49
50                 // Reset ‘active‘ flag.
51                 cancelRefresh(ex);
52
53                 // Propagate exception to caller.
54                 throw ex;
55             }
56
57             finally {
58                 // Reset common introspection caches in Spring‘s core, since we
59                 // might not ever need metadata for singleton beans anymore...
60                 resetCommonCaches();
61             }
62         }
63     }

我们现在知道第7行返回的这个ConfigurableListableBeanFactory 有我们所有的beanDefintion。这个方法是给ConfigurableListableBeanFactory 设置了若干预设变量,现在我们也不清楚这个变量是干嘛的,我们先跳过这个方法,等回头再分析他。

第14行postProcessBeanFactory(ConfigurableListableBeanFactory )。我们看看这个代码是做什么事情,我们有一个关注点,我们@autowired的bean是怎么被处理的。这个代码,会根据不同context子类加入不同Processors,这个我们也暂时不分析他,等回头再看

第17行invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory )。这个方法应该就是能看到bean是如何创建的。这个代码比较长,我们先把调用关系简单画出来

执行invokeBeanFactoryPostProcessors之后,这里主要是讲各个processors类注册进去,这里需要获得具体的bean了,根据beanName和BeanDefinition。如何获得bean,通过DefaultListableBeanFactory的getBean方法,这里判断bean是单利还是原型的,进入不同的getBean的逻辑,之后调用的AbstractAutowireCapableBeanFactory的createBean方法,之后通过反射来获得对应的bean。注意看一下doCreateBean方法里面的populateBean()方法,这里能够完成对属性的注入。

上面这个方法,我们调用的时候发现就注册了一个ConfigurationClassPostProcessor,也不知道干嘛的。后来通过搜索了解到这个方法主要是用于处理spring的后置处理器的相关内容,参考https://www.cnblogs.com/sishang/p/6588542.html和https://www.cnblogs.com/sishang/p/6576665.html。

 

原文地址:https://www.cnblogs.com/snail-tomorrow/p/10199240.html

时间: 2024-07-31 02:39:17

spring bean 加载过程(spring)的相关文章

看看Spring的源码——Bean加载过程

最近几天跟同事聊起Spring的一些问题,对一些地方有些疑问,趁这两天有点空,看看Spring的源码,了解下具体的实现细节.本文基于Spring 4.0.5版本. 首先Web项目使用Spring是通过在web.xml里面配置org.springframework.web.context.ContextLoaderListener初始化IOC容器的. <listener> <listener-class>org.springframework.web.context.ContextL

Spring IOC bean加载过程

首先我们不要在学习Spring的开始产生畏难情绪.Spring没有臆想的那么高深,相反,它帮我们再项目开发中制定项目框架,简化项目开发.它的主要功能是将项目开发中繁琐的过程流程化,模式化,使用户仅在固定文件中增加特定标签并实现特定逻辑层的代码就能完成项目开发.下面我们来分析web项目启动时bean的初始化过程. 我们遵循类的依赖,引用关系来理清spring在这一过程中的架构和细节实现.java web项目入口在web.xml,Spring在此配置入口servlet完成bean的加载.Dispat

07.Spring Bean 加载 - BeanDefinitionReader

基本概念 BeanDefinitionReader ,该接口的作用就是加载 Bean. 在 Spring 中,Bean 一般来说都在配置文件中定义.而在配置的路径由在 web.xml 中定义.所以加载 Bean 的步骤大致就是: 加载资源,通过配置文件的路径(Location)加载配置文件(Resource) 解析资源,通过解析配置文件的内容得到 Bean. 下面来看它的接口定义: public interface BeanDefinitionReader { BeanDefinitionReg

看看Spring的源码(一)——Bean加载过程

首先Web项目使用Spring是通过在web.xml里面配置org.springframework.web.context.ContextLoaderListener初始化IOC容器的. <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 那就以此为切入点顺藤摸瓜. public class

SSH 之 Spring的源码(一)——Bean加载过程

看看Spring的源码,看看巨人的底层实现,拓展思路,为了更好的理解原理,看看源码,深入浅出吧.本文基于Spring 4.0.8版本. 首先Web项目使用Spring是通过在web.xml里面配置 org.springframework.web.context.ContextLoaderListener初始化IOC容器的 <span style="font-family:SimSun;font-size:18px;"><listener> <listene

【Spring源码分析】Bean加载流程概览

代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已,Spring的加载过程相对是不太透明的,不太好去找加载的代码入口. 下面有很简单的一段代码可以作为Spring代码加载的入口: 1 ApplicationContext ac = new Clas

深入理解 spring 容器,源码分析加载过程

Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC源码分析介绍它的核心实现原理. Tomcat服务器启动入口文件是web.xml,通过在其中配置相关的Listener和Servlet即可加载Spring MVC所需数据.基于Spring MVC最简单的配置如下. <!-- 加载Spring配置文件 --> <context-param>

spring项目加载非常慢

请检查spring是否运行在debug模式下,是跳转到2 否则跳转到3 查看spring在run模式下是否运行依旧缓慢 是跳转到3,否则跳转到4 请检验是否spring bean加载了多次(quartz加载很有可能导致部分bean被是实例两次) 是跳转到 http://blog.csdn.net/chaijunkun/article/details/6925889 否则跳转到 http://jinnianshilongnian.iteye.com/blog/1883013 按照步骤检验 请将代码

Spring源码学习-bean加载

1. 场景 一个applicationContext.xml配置文件,这个不可少一个bean,这里我没用接口,直接用一个普通的类做为Spring的bean一个Junit测试类 applicationContext.xml <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://w