Spring

什么是Spring框架

Spring是一种轻量级框架,旨在提高开发人员的开发效率和系统的可维护性。 我们一般说的Spring框架就是SPring Framework,他是很多模块的集合,使用这些模块可以很方便的协助我们进行开发。这些模块是核心容器、数据访问/集成、web、aop、工具、消息和测试模块。比如Core Container中的Core组件是Spring所有组件的核心,Beans组件和Context组件是实现IOC和DI的基础,AOP组件用来实现面向切面编程。

Spring官网列出来的Spring的6个特征:

  • 核心技术:依赖注入,aop,事件,资源,i18n,验证,数据绑定,类型转换,SpEL
  • 测试:模拟对象,TestContext框架,SPringMVC测试,WebTestClient
  • 数据访问:事务,DAO支持,JDBC,ORM,编组XML
  • Web支持:Spring MVC和SPring WebFlux Web框架
  • 集成:远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存
  • 语言:Kotlin,Groovy,动态语言
  • Spring中的单例bean的线程安全问题了解吗?

    大部分我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。

    有两种常见解决方案: 1、在bean对象中尽量避免定义可变的成员变量。 2、在类中定义一个ThreadLocal成员变量,将需要的可变的成员变量保存在ThreadLocal中。

    Spring中的bean生命周期?

    Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

  • Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中的init-method和destroy-method指定的方法
  • Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、ApplicationContext;当然也包括InitializingBean和DiposableBean这些接口的方法
  • 容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现,一般称它们的实现类为“后处理器”
  • 工厂后处理器接口方法:这个包括了AspectJWeavingEnabler,ConfigurationClassPostProcessor,CustomAutowireConfigurer等等非常有用的工厂后处理接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
  • 如何将Bean从XML配置中解析后放到IoC容器中得?

    初始化的入口

    对于xml配置的Spring应用,在main()方法中实例化ClasspathXmlApplication即可创建一个IoC容器。我们可以从这个构造方法开始,探究一下IoC容器的初始化过程。

    1
    2
    
     // create and configure beans
    ApplicationContext context = new ClassPathXmlApplicationContext("aspects.xml", "daos.xml", "services.xml");
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, (ApplicationContext)null);
    }
    
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        // 设置Bean资源加载器
        super(parent);
    
        // 设置配置路径
        this.setConfigLocations(configLocations);
    
        // 初始化容器
        if (refresh) {
            this.refresh();
        }
    }
    

    设置资源解析器和环境

    调用父类容器AbstractApplicationContext的构造方法(super(parent)方法)为容器设置好Bean资源加载器

    1
    2
    3
    4
    5
    6
    7
    
    public AbstractApplicationContext(@Nullable ApplicationContext parent) {
        // 默认构造函数初始化容器id, name, 状态 以及 资源解析器
        this();
    
        // 将父容器的Environment合并到当前容器
        this.setParent(parent);
    }
    

    通过AbstractApplicationContext默认构造器初始化容器id,name,状态以及资源解析器

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());
        this.id = ObjectUtils.identityToString(this);
        this.displayName = ObjectUtils.identityToString(this);
        this.beanFactoryPostProcessors = new ArrayList();
        this.active = new AtomicBoolean();
        this.closed = new AtomicBoolean();
        this.startupShutdownMonitor = new Object();
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.applicationListeners = new LinkedHashSet();
        this.resourcePatternResolver = this.getResourcePatternResolver();
    }
    // Spring资源加载器
    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }
    

    通过AbstractApplicationContext的setParent(parent)方法将父容器的Enviroment合并到当前容器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    public void setParent(@Nullable ApplicationContext parent) {
        this.parent = parent;
        if (parent != null) {
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment) {
                this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
            }
        }
    }
    

    设置配置路径

    在设置容器的资源加载器之后,接下来FileSystemXmlApplicationContent执行setConfigLocations方法通过调用其父类AbstractRefreshableConfigApplicationContext的方法进行对Bean定义资源文件的定位。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
    
            for(int i = 0; i < locations.length; ++i) {
                // 解析配置路径
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            }
        } else {
            this.configLocations = null;
        }
    }
    protected String resolvePath(String path) {
        // 从上一步Environment中解析
        return this.getEnvironment().resolveRequiredPlaceholders(path);
    }
    

    初始化的主体流程

    Spring IoC容器对Bean定义资源的加载是从refresh()函数开始的,refresh()是一个模板方法,refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh()之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。

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

    这里的设计上是一个非常典型的资源类加载处理型的思路

  • 模板方法设计模式,模板方法中使用典型的钩子方法
  • 将具体的初始化加载方法插入到钩子方法之间
  • 将初始化的阶段封装,用来记录当前初始化到什么阶段;常见的设计是xxxPhase/xxxStage
  • 资源加载初始化有失败等处理,必然是try/catch/finally
  • 初始化BeanFactory之obtainFreshBeanFactory

    AbstractApplicationContext的obtainFreshBeanFactory()方法调用子类容器的refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程,代码如下

    1
    2
    3
    4
    5
    
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
        refreshBeanFactory();
        return getBeanFactory();
    }
    

    AbstractApplicationCOntext类中只抽象定义了refreshBeanFactory()方法,容器真正调用的是子类的AbstractRefreshableApplicationContext实现的refreshBeanFactory()方法留在创建IoC容器之前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。方法源码如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    protected final void refreshBeanFactory() throws BeansException {
        // 如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 创建DefaultListableBeanFactory,并调用loadBeanDefinitions(beanFactory)装载bean定义
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory); // 对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等 
            loadBeanDefinitions(beanFactory); // 调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器  
            this.beanFactory = beanFactory;
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
    

    初始化BeanFactory之loadBeanDefinitions

    AbstractRefreshableApplicationContext中只定义了抽象的loadBeanDefinitions方法,容器真正调用的是其子类的AbstractXmlApplicationContext对该方法的实现,AbstractXmlApplicationContext的主要源码如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源  
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
        // 配置上下文的环境,资源加载器、解析器
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 为Bean读取器设置SAX xml解析器
    
        // 允许子类自行初始化(比如校验机制),并提供真正的加载方法
        initBeanDefinitionReader(beanDefinitionReader); // 当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制  
        loadBeanDefinitions(beanDefinitionReader);
    }
    
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        // 加载XML配置方式里的Bean定义的资源
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        // 加载构造函数里配置的Bean配置文件,即{"aspects.xml", "daos.xml", "services.xml"}
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }
    

    Xml Bean读取器(XmBeanDefinitionReader)调用其父类AbstractBeanDefinitionReader的reader.loadBeanDefinitions方法读取bean定义资源

    由于我们使用ClassPathXmlApplicationCOntext作为例子分析,因此getConfigResources的返回值为null,因此程序执行reader,loadBeanDefinitions(configLocations)分支。

    AbstractBeanDefinitionReader读取Bean定义资源

    AbstractBeanDifinitionReader的loadBeanDefinitions方法源码如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    
    @Override
    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(location, null);
    }
    
    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        }
    
        // 模式匹配类型的解析器,这种方式是加载多个满足匹配条件的资源
        if (resourceLoader instanceof ResourcePatternResolver) {
            try {
                // 获取到要加载的资源
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int count = loadBeanDefinitions(resources); // 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能  
                if (actualResources != null) {
                    Collections.addAll(actualResources, resources);
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
                }
                return count;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            // 只能通过绝对路径URL加载单个资源.
            Resource resource = resourceLoader.getResource(location);
            int count = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
            }
            return count;
        }
    }
    

    从对AbstractBeanDefinitionReader的loadBeanDefinitions方法源码分析可以看出该方法做了以下两件事:

    1、首先,调用资源加载器的获取资源方法resourceLoader.getResource(location),获取到要加载的资源。 2、其次,真正执行加载功能的是其子类XmlBeanDefinitionReader的loadBeanDefinitions方法

    XmlBeanDefinitionReader加载Bean定义资源

    继续看子类XmlBeanDefinitionReader的loadBeanDefinitions(Resource…)方法看到代表bean文件的资源定义以后的载入过程。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
    /**
        * 本质上是加载XML配置的Bean。
        * @param inputSource the SAX InputSource to read from
        * @param resource the resource descriptor for the XML file
        */
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
    
        try {
            Document doc = doLoadDocument(inputSource, resource); // 将Bean定义资源转换成Document对象
            int count = registerBeanDefinitions(doc, resource);
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            return count;
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }
    
    // 使用配置的DocumentLoader加载XML定义文件为Document.
    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
    }
    

    通过源码分析,载入Bean定义资源文件的最后一步是将Bean定义资源转换为Document对象,该过程由documentLoader实现

    DocumentLoader将Bean定义资源转换为Document对象

    DocumentLoader将Bean定义资源转换为Document对象的源码如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    
    // 使用标准的JAXP将载入的Bean定义资源转换成document对象
    @Override
    public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    
        // 创建文件解析器工厂
        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isTraceEnabled()) {
            logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        // 创建文档解析器
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        return builder.parse(inputSource); // 解析
    }
    
    protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
            throws ParserConfigurationException {
    
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(namespaceAware);
    
        // 设置解析XML的校验
        if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
            factory.setValidating(true);
            if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
                // Enforce namespace aware for XSD...
                factory.setNamespaceAware(true);
                try {
                    factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
                }
                catch (IllegalArgumentException ex) {
                    ParserConfigurationException pcex = new ParserConfigurationException(
                            "Unable to validate using XSD: Your JAXP provider [" + factory +
                            "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
                            "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
                    pcex.initCause(ex);
                    throw pcex;
                }
            }
        }
    
        return factory;
    }
    

    该解析过程调用JavaEE标准的JAXP标准进行处理。

    至此Spring IoC容器根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象过程完成。

    接下来我们继续分析Spring IoC容器将载入的Bean定义资源文件转换为Document对象之后,是如何将其解析为Spring IoC管理的Bean对象,并将其注册到容器中的。

    XmlBeanDefinitionReader解析载入的Bean定义资源文件

    XmlBeanDefinitionReader类中的doLoadBeanDefinitions方法是从特定的XML文件中实际载入Bean定义资源的方法,该方法在载入Bean定义资源之后将其转换为Document对象,接下来调用registerBeanDefinitions启动Spring IoC容器对Bean定义的解析过程,registerBeanDefinition方法源码如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    // 按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构 
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        // 解析过程入口,这里使用了委派模式,具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成  
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;  // 返回此次解析了多少个对象
    }
    
    // 创建BeanDefinitionDocumentReader对象,解析Document对象  
    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
        return BeanUtils.instantiateClass(this.documentReaderClass);
    }
    
    /**
        * Create the {@link XmlReaderContext} to pass over to the document reader.
        */
    public XmlReaderContext createReaderContext(Resource resource) {
        return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
                this.sourceExtractor, this, getNamespaceHandlerResolver());
    }
    

    Bean定义资源的载入解析分为以下两个过程:

    1、首先,通过调用XML解析器将Bean定义资源文件转换得到Document对象,但是这些Document对象并没有按照Spring的Bean规则进行解析。这一部是载入的过程 2、其次,在完成通用的XML解析之后,按照Spring的Bean规则对Document对象进行解析。

    按照Spring的Bean规则对Document对象解析的过程是在接口BeanDifinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader中实现的。

    DefaultBeanDefinitionDocumentReader对bean定义的Document对象解析

    BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类DefaultBeanDefinitionDocumentReader对Document对象进行解析,解析代码如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    
    // 注册<beans/>配置的Beans
    @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);
    
        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
    
        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate); // 从Document的根元素开始进行Bean定义的Document对象  
        postProcessXml(root);
    
        this.delegate = parent;
    }
    

    BeanDefinitionParserDelegate 解析Bean定义资源文件生成BeanDefinition

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    
    /**
        * Parse the elements at the root level in the document:
        * "import", "alias", "bean".
        * @param root the DOM root element of the document
        */
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }
    
    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
          
        // 如果元素节点是<Import>导入元素,进行导入解析
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        // 如果元素节点是<Alias>别名元素,进行别名解析 
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        // 如果元素节点<Bean>元素, 按照Spring的Bean规则解析元素  
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        // 如果元素节点<Beans>元素,即它是嵌套类型的
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // 递归解析
            doRegisterBeanDefinitions(ele);
        }
    }
    

    解析Bean生成BeanDefinitionHolder的方法

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    /**
        * Process the given bean element, parsing the bean definition
        * and registering it with the registry.
        */
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // 注册最终的装饰实例
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    

    解析过后的BeanDefinition在IoC容器中注册

    Document对象的解析后得到封装BeanDefinition的BeanDifinitionHold对象,然后调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean,BeanDefinitionReaderUtils的注册的源码如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    // 通过BeanDefinitionRegistry将BeanDefinitionHolder注册到BeanFactory
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {
    
        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }
    

    当调用BeanDefinitionReaderUtils向IoC容器注册解析的BeanDefinition时,真正完成注册功能的是DefaultListableBeanFactory.

    DefaultListableBeanFactory 向IoC容器注册解析后的BeanDefinition

    IoC容器本质上就是一个beanDefinitionMap,注册即将BeanDefinition put 到map中。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    
    /** Map of bean definition objects, keyed by bean name. */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    
    /** Map from bean name to merged BeanDefinitionHolder. */
    private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
    
    
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
    
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        // 如果已经注册
        if (existingDefinition != null) {
            // 检查是否可以覆盖
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 覆盖
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            }
            //重置所有已经注册过的BeanDefinition的缓存  
            this.frozenBeanDefinitionNames = null;
        }
    
        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
            clearByTypeCache();
        }
    }
    

    至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

    总结

    现在通过上面的代码,总结一下IoC容器初始化的基本步骤:

  • 初始化的入口在容器实现中的refresh()调用来完成
  • 对bean定义载入IoC容器使用的方法是loadBeanDefinition,其中大致过程如下:
    1、通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以从类路径,文件系统,URL等方式来定义为资源位置。如果是XmlBeanFactory作为IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过抽象成Resource来被IOC容器处理的。

    2、通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是XmlBeanDefinitionReader来解析bean的xml定义文件-实际的处理过程是委托给BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示-这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关方法-他们都是为处理BeanDefinitin服务的。 3、容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这由IOC实现BeanDefinitionRegister接口来实现。注册过程就是在IOC容器内部维护一个HashMap来保存得到的BeanDefinition的过程。这个HashMap是IoC容器持有bean信息的场所,以后对bean的操作都是围绕这个HashMap来实现的。

  • 然后我们就可以通过BeanFactory和ApplicationCOntext来享受到SPring IOC的服务了,在使用IoC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确IoC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。Spring本身提供了对声明式载入Web应用程序用法的应用程序上下文,并将其存储在ServletContext中的框架实现。
  • Spring中getBean的主体思路

    BeanFactory实现getBean方法在AbstractBeanFactory中,这个方法重载都是调用doGetBean方法进行实现的:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    public Object getBean(String name) throws BeansException {
      return doGetBean(name, null, null, false);
    }
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
      return doGetBean(name, requiredType, null, false);
    }
    public Object getBean(String name, Object... args) throws BeansException {
      return doGetBean(name, null, args, false);
    }
    public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
        throws BeansException {
      return doGetBean(name, requiredType, args, false);
    }
    

    接下来看下doGetBean方法(这个方法很长,我们主要看它的整体思路和设计要点):

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    
    // 参数typeCheckOnly:bean实例是否包含一个类型检查
    protected <T> T doGetBean(
    			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    			throws BeansException {
    
      // 解析bean的真正name,如果bean是工厂类,name前缀会加&,需要去掉
      String beanName = transformedBeanName(name);
      Object beanInstance;
    
      // Eagerly check singleton cache for manually registered singletons.
      Object sharedInstance = getSingleton(beanName);
      if (sharedInstance != null && args == null) {
        // 无参单例从缓存中获取
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
      }
    
      else {
        // 如果bean实例还在创建中,则直接抛出异常
        if (isPrototypeCurrentlyInCreation(beanName)) {
          throw new BeanCurrentlyInCreationException(beanName);
        }
    
        // 如果 bean definition 存在于父的bean工厂中,委派给父Bean工厂获取
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
          // Not found -> check parent.
          String nameToLookup = originalBeanName(name);
          if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                nameToLookup, requiredType, args, typeCheckOnly);
          }
          else if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
          }
          else if (requiredType != null) {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
          }
          else {
            return (T) parentBeanFactory.getBean(nameToLookup);
          }
        }
    
        if (!typeCheckOnly) {
          // 将当前bean实例放入alreadyCreated集合里,标识这个bean准备创建了
          markBeanAsCreated(beanName);
        }
    
        StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
            .tag("beanName", name);
        try {
          if (requiredType != null) {
            beanCreation.tag("beanType", requiredType::toString);
          }
          RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
          checkMergedBeanDefinition(mbd, beanName, args);
    
          // 确保它的依赖也被初始化了.
          String[] dependsOn = mbd.getDependsOn();
          if (dependsOn != null) {
            for (String dep : dependsOn) {
              if (isDependent(beanName, dep)) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
              }
              registerDependentBean(dep, beanName);
              try {
                getBean(dep); // 初始化它依赖的Bean
              }
              catch (NoSuchBeanDefinitionException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
              }
            }
          }
    
          // 创建Bean实例:单例
          if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
              try {
                // 真正创建bean的方法
                return createBean(beanName, mbd, args);
              }
              catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                destroySingleton(beanName);
                throw ex;
              }
            });
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
          }
          // 创建Bean实例:原型
          else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
              beforePrototypeCreation(beanName);
              prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
              afterPrototypeCreation(beanName);
            }
            beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
          }
          // 创建Bean实例:根据bean的scope创建
          else {
            String scopeName = mbd.getScope();
            if (!StringUtils.hasLength(scopeName)) {
              throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
            }
            Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
              throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
              Object scopedInstance = scope.get(beanName, () -> {
                beforePrototypeCreation(beanName);
                try {
                  return createBean(beanName, mbd, args);
                }
                finally {
                  afterPrototypeCreation(beanName);
                }
              });
              beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
              throw new ScopeNotActiveException(beanName, scopeName, ex);
            }
          }
        }
        catch (BeansException ex) {
          beanCreation.tag("exception", ex.getClass().toString());
          beanCreation.tag("message", String.valueOf(ex.getMessage()));
          cleanupAfterBeanCreationFailure(beanName);
          throw ex;
        }
        finally {
          beanCreation.end();
        }
      }
    
      return adaptBeanInstance(name, beanInstance, requiredType);
    }
    

    上述代码主要看中文注释即可:

  • 解析bean的真正name,如果bean是工厂类,name前缀会加&,需要去掉
  • 无参单例先从缓存中获取
  • 如果bean实例还在创建中,则直接抛出异常
  • 如果bean definition存在于的bean工厂中,委派给父Bean工厂获取
  • 标记这个beanName的实例正在创建
  • 确保它的依赖也被初始化
  • 真正创建:
    1. 单例时
    2. 原型时
    3. 根据bean的scope创建
  • 重点: SPring如何解决循环依赖问题

    首先我们需要声明,Spring只是解决了单例模式下属性依赖的循环问题;Spring为了解决单例的循环依赖问题,使用了三级缓存。

    Spring单例模式下的属性依赖

    先来看下这三级缓存

    1
    2
    3
    4
    5
    6
    7
    8
    
    /** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
     
    /** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
    
    /** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
    
  • 第一级缓存(singletonObjects): 单例对象缓存池,已经实例化并且属性赋值,这里的对象是成熟对象
  • 第二层缓存(earlySingletonObjects): 单例对象缓存池,已经实例化但尚未属性赋值,这里的对象是半成品对象
  • 第三层缓存(singletonFactories): 单例工厂的缓存
  • 如下是获取单例中:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
      // Spring首先从singletonObjects(一级缓存)中尝试获取
      Object singletonObject = this.singletonObjects.get(beanName);
      // 若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取
      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) {
                //若是仍是获取不到而且容许从singletonFactories经过getObject获取,则经过singletonFactory.getObject()(三级缓存)获取
                  singletonObject = singletonFactory.getObject();
                  //若是获取到了则将singletonObject放入到earlySingletonObjects,也就是将三级缓存提高到二级缓存中
                  this.earlySingletonObjects.put(beanName, singletonObject);
                  this.singletonFactories.remove(beanName);
              }
            }
        }
      }
      return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
    

    补充一些方法和参数

  • isSingletonCurrentlyIncreation(): 判断当前单例bean是否正在建立中,也就是没有初始化完成(好比A的构造器依赖了B对象因此得先去建立B对象,或则在A得populateBean过程当中依赖了B对象,得先去建立B对象,这时得A就是处于建立中的状态。)
  • allowEarlyRefrence: 是否容许从singletonFactories中经过getObject拿到对象
  • 分析getSinflwton()整个过程,Spring首先从一级缓存singletonObjects中获取。若是获取不到,而且对象正在建立中,就再从二级缓存earlySingletonObjects中获取。若是仍是获取不到且容许singletonFactories经过getObject()获取,就从三级缓存singlwtonFactory.getObject()(三级缓存)获取,若是获取到了则从三级缓存移动到了二级缓存。

    从上面三级缓存的分析,咱们能够知道,Spring解决循环依赖的诀窍就在于singletonFactories这个三级cache。这个cache的类型是ObjectFactory,定义以下:

    1
    2
    3
    
    public interface ObjectFactory<T> {
        T getObject() throws BeansException;
    }
    

    在bean建立过程当中,有两处比较重要的匿名内部类实现了该接口。一处是Spring利用其建立bean的时候,另外一处就是:

    1
    2
    3
    4
    
    addSingletonFactory(beanName, new ObjectFactory<Object>() {
       @Override   public Object getObject() throws BeansException {
          return getEarlyBeanReference(beanName, mbd, bean);
       }});
    

    此处就是解决循环依赖的关键,这段代码发生在createBeanInstance以后,也就是说单例对象此时已经被建立出来的。这个对象已经被生产出来了,虽然还不完美(尚未进行初始化的第二步和第三步),可是已经能被人认出来了(根据对象引用能定位到堆中的对象),因此Spring此时将这个对象提早曝光出来让你们认识,让你们使用。

    Spring为何不能解决非单例属性之外的循环依赖?

    Spring为什么不能解决构造器的循环依赖

    构造器注入形成的循环依赖: 也就是BeanB需要在beanA的构造函数中完成初始化,beanA也需要2在beanB的构造函数中完成初始化,这种情况的结果就是两个bean都不能完成初始化,循环依赖难以解决。

    Spring解决循环依赖主要是依赖三级缓存,但是得在调用构造方法之前还未将其放入三级缓存之中,因此后续得依赖调用构造方法的时候并不能从三级缓存中获取到依赖的Bean,因此不能解决。

    Spring为什么不能解决prototype作用域循环依赖

    这种循环依赖同样无法解决,因为Spring不会缓存prototype作用域的bean,而spring中循环依赖的解决正是通过缓存来实现的。

    Spring为什么不能解决多例的循环依赖?

    多实例Bean是每次调用一次getBean都会执行一次构造方法并且给属性赋值,根本没有三级缓存,因此不能解决循环依赖。

    那么其他循环依赖如何解决?

    在实际开发中,类似的依赖是如何解决?

  • 生成代理对象产生的循环依赖
  • 这类循环依赖解决方法有很多,主要有:

    1、使用@Lazy注解,延迟加载

    2、使用@DependsOn注解,指定加载先后关系

    3、修改文件名称,改变循环依赖类的加载顺序

  • 使用@DependsOn产生的循环依赖
  • 这类循环依赖问题要找到@DependsOn注解循环依赖的地方,迫使它不循环依赖就可以解决问题。
  • 多例循环依赖
  • 这类循环依赖问题可以通过把bean改成单例的解决
  • 构造器循环依赖
  • 这类循环依赖问题可以通过使用@Lazy注解解决。

    重点: Spring中Bean的生命周期

    Spring只帮我们管理单例模式Bean的完整的生命周期,对于prototype的bean,SPring在创建好交给使用者之后则不会再管理后续的生命周期。

    Spring容器可以管理singleton作用域Bean的生命周期,在此作用域下,SPring能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁。

    而对于prototype作用域的Bean,Spring只负责创建,当容器创建了Bean的实例后,Bean的实例就交给客户端代码管理,Spring容器就不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,SPring容器都会创建一个新的实例,并且不会管那些被配置成prototype作用域的Bean的生命周期。

    了解SPring生命周期的意义就在于,可以利用Bean在其存货期间的指定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,会在Bean被初始化后和被销毁前执行一些相关操作。

    Spring Bean生命周期流程

    在SPring中,Bean的生命周期是一个很复杂的执行过程,我们可以利用Spring提供的方法定制Bean的创建过程。

  • 如果BeanFactoryPostProcessor和Bean关联,则调用postProcessBeanFactory方法.(即首先尝试从Bean工厂中获取Bean)
  • 如果InstantiationAwareBeanPostProcessor和Bean关联,则调用postProcessBeforeInstantiation方法
  • 根据配置情况调用Bean构造方法实例化Bean。
  • 利用依赖注入完成Bean中所有属性值的配置注入。
  • 如果InstantiationAwareBeanPostProcessor和Bean关联,则调用postProcessAfterInstantition方法和postProcessProperties
  • 调用xxxAware接口(上图只是给了几个例子)
    1、如果bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()方法传入当前Bean的id值。
    2、如果Bean实现了BeanClassLoaderAware接口,则Spring调用setBeanClassLoader()方法传入classLoader的引用。
    3、如果Bean实现了BeanFactoryAware接口,则Spring调用setBeanFactory()方法传入当前工厂实例的引用。
  • 第二类Aware接口
    1、如果Bean实现了EnvironmentAware接口,则Spring调用setEnviroment()方法传入当前Enviroment实例的引用。
    2、如果Bean实现了EmbeddedValueResolverAware接口,则Spring调用setEmbeddedValueResolver()方法传入当前StringValueResolver实例的引用。
    3、如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicationContext()方法传入当前ApplicationContext实例的引用。
  • 如果BeanPostProcessor和Bean关联,则SPring将调用该接口的预初始化方法postProcessBeforeInitialzation()对Bean进行加工操作,此处非常重要,SPring的AOP就是利用它实现的
  • 如果Bean实现了InitializingBean接口,则SPring将调用afterPropertiesSet()方法。(或者有执行@PostConstruct注解的方法)
  • 如果在配置文件中通过init-method属性指定了初始化方法,则调用该初始化方法
  • 如果BeanPostProcessor和Bean关联,则Spring将调用该接口的初始化方法postProcesasAfterInitialization()。此时,Bean已经可以被应用系统使用了。
  • 如果在bean中指定了该Bean的作用范围为scope="singleton",则将该Bean放入Spring IoC的缓存池中,将触发Spring对该Bean的生命周期管理;如果在bean中指定了该Bean的作用范围为scope="prototype",则将该Bean交给调用者,调用者管理该Bean的生命周期,Spring不再管理该Bean.
  • 如果Bean实现了DisposableBean接口,则Spring会调用destory()方法将SPring中的Bean销毁;
  • 如果在配置文件中通过destory-method属性指定了Bean的销毁方法,则Spring将调用该方法对Bean进行销毁。
  • Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

  • Bean自身的方法: 这个包括了Bean本身调用的方法和通过配置文件中bean的init-method和destroy-method指定的方法
  • Bean级生命周期接口方法: 这个包括了BeanNameAware、BeanFactoryAware、ApplicationContextAware;当然也包括InitializingBean和DiposableBean这些接口的方法(可以被@PostConstruct和@PreDestroy注解替代)
  • 容器级生命周期接口方法: 这个包括了AspectJWeavingEnable,ConfigurationClassPostProcessor,CustomAutowireConfigurer等的非常有用的工厂后处理接口的方法,工厂后处理器也是容器级的。在应用上下文装配文件之后立即调用。