跳至主要內容

属性源原理解析2

wangdx大约 28 分钟

BeanDefinitionReader

BeanDefinitionReader 简介

BeanDefinitionReader 关联结构

  • Spring 在使用 XML 文件进行配置定义时,所有需要注入的 Bean 实例都需要通过"<bean>”标签进行定义,在 W3C 的标准中提供了 DOM 解析标准,而在 Spring 中考虑到满足自身要求的 XML 文件读取机制,提供了一套自己的 XML 解析处理标准,同时该标准兼容 JDK 提供的 DOM 和 SAX 解析处理模型。在 Spring 提供的操作标准中最为重要的就是 BeanDefinitionReader 接口

1、
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>     <!-- 启用Annotation配置注解支持 -->
    <context:component-scan base-package="com.yootk"/>
    <context:property-placeholder location="classpath:config/*.properties"/>
    <bean id="messageListener" class="com.yootk.listener.MessageListener"
        init-method="openChannel" destroy-method="closeChannel"/>
    <bean id="companyA" class="com.yootk.vo.CompanyA">
        <property name="title" value="Hello Muyan"/>
    </bean>
    <bean id="companyB" class="com.yootk.vo.CompanyB">
        <property name="title" value="Hello Yootk"/>
    </bean>
</beans>

2、
package org.springframework.beans.factory.support;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.Nullable;
public interface BeanDefinitionReader { // Spring 1.1的时候提供的接口
   BeanDefinitionRegistry getRegistry();// 获取所有的注册器
   @Nullable
   ResourceLoader getResourceLoader();// 返回资源加载器,资源可能来自于CLASSPATH或者是外部的磁盘文件
   @Nullable
   ClassLoader getBeanClassLoader();// 获取资源的类加载器
   BeanNameGenerator getBeanNameGenerator();// Bean名称的生成器
   // 读取指定资源之中的Bean定义,它所返回的信息不是Bean的具体定义,而是Bean定义的数量
   int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
   int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
   int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
   int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

XmlBeanDefinitionReader

XmlBeanDefinitionReader

  • 如果要想进行 XML 资源读取,一般都会使用 XmlBeanDefinitionReader 子类,在进行该类对象实例化时需要提供一个 BeanDefinitionRegistry 接囗实例,而在之前所使用过的 AnnotationConfigApplicationContext(注解应用上下文),就属于该接口的实现子类
1、
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>     <!-- 启用Annotation配置注解支持 -->
    <context:component-scan base-package="com.yootk"/>
    <context:property-placeholder location="classpath:config/*.properties"/>
    <bean id="messageListener" class="com.yootk.listener.MessageListener"
        init-method="openChannel" destroy-method="closeChannel"/>
    <bean id="companyA" class="com.yootk.vo.CompanyA">
        <property name="title" value="Hello Muyan"/>
    </bean>
    <bean id="companyB" class="com.yootk.vo.CompanyB">
        <property name="title" value="Hello Yootk"/>
    </bean>
</beans>

2、

package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringSourceDemo { // 李兴华高薪就业编程训练营
    private static final Logger LOGGER = LoggerFactory.getLogger(SpringSourceDemo.class);
    public static void main(String[] args) { // 沐言科技:www.yootk.com
        BeanDefinitionRegistry registry = new AnnotationConfigApplicationContext();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
        reader.setValidating(true); // 启用读取的校验
        int count = reader.loadBeanDefinitions("classpath:spring/spring-base.xml");
        LOGGER.info("BEAN定义数量:{}", count);
    }
}

ResourceEntityResolver

ResourceEntityResolver

  • Spring 中的 XML 配置文件在定义时,必须遵循 XSD 定义标准进行编写,在进行 XML 配置项解析之前,一般都需要对当前配置项是否符合 Spring 官方的 XSD 规范要求,而后在进行具体的解析处理,所以在 Spring 提供的 XML 处理机制中,提供了 EntityResolver 接口,可以通过 publicld 和 systemld 获取指定的 XSD 规范描述(返回的结果为 rce 实例),该接口的继承结构如图所示。
1、
package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.ResourceEntityResolver;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.xml.sax.InputSource;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Scanner;

public class SpringSourceDemo { // 李兴华高薪就业编程训练营
    private static final Logger LOGGER = LoggerFactory.getLogger(SpringSourceDemo.class);
    public static void main(String[] args) throws Exception { // 沐言科技:www.yootk.com
        BeanDefinitionRegistry registry = new AnnotationConfigApplicationContext();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
        // 获取当前XML定义读取所对应的ResourceLoader接口实例
        ResourceEntityResolver resolver = new ResourceEntityResolver(reader.getResourceLoader());
        reader.setEntityResolver(resolver); // 定义解析器
        String publicId = "http://www.springframework.org/schema/context";
        String systemId = "http://www.springframework.org/schema/context/spring-context.xsd";
        InputSource source = resolver.resolveEntity(publicId, systemId);
        Scanner scanner = new Scanner(source.getByteStream()); // 要获取输入流
        scanner.useDelimiter("\n");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while(scanner.hasNext()) {
            String temp =  scanner.next() + "\n";
            bos.write(temp.getBytes());
        }
        System.out.println(bos);
    }
}

BeanDefinition

BeanDefinition 接口

  • Spring 容器之中除了会根据用户的配置需要保存有 Bean 实例之外还会为每一个保存的 Bean 实例分配相应的结构信息,例如:指定的 Bean 是否为单例 Bean 对应的完整类名称等,所有的结构信息都保存在 BeanDefinition 接口之中
1、
package org.springframework.beans.factory.config;
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
   String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; // 单例标记
   String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; // 原型标记
   int ROLE_APPLICATION = 0; // 角色的应用
   int ROLE_SUPPORT = 1; // 角色的支持
   int ROLE_INFRASTRUCTURE = 2;
   void setParentName(@Nullable String parentName);
   @Nullable
   String getParentName();// 定义父结构的Bean名称
   void setBeanClassName(@Nullable String beanClassName); // Bean的类名称
   @Nullable
   String getBeanClassName();// 获取保存的Bean类名称(包.类名称)
   void setScope(@Nullable String scope); // Scope有两种配置项:singleton、prototype
   @Nullable
   String getScope();// 获取Scope的配置项
   void setLazyInit(boolean lazyInit); // 设置延迟初始化
   boolean isLazyInit();// 判断延迟初始化
   void setDependsOn(@Nullable String... dependsOn); // 设置依赖的关联(配置顺序)
   @Nullable
   String[] getDependsOn();// 返回依赖结构
   void setAutowireCandidate(boolean autowireCandidate); // 自动注入处理
   boolean isAutowireCandidate();// 判断是否进行自动注入操作
   void setPrimary(boolean primary); // 设置主要的注入Bean
   boolean isPrimary();// 判断是否为主要自动注入Bean
   void setFactoryBeanName(@Nullable String factoryBeanName); // FactoryBean名称
   @Nullable
   String getFactoryBeanName();// 获取FactoryBean名称
   void setFactoryMethodName(@Nullable String factoryMethodName); // 工厂方法名称
   @Nullable
   String getFactoryMethodName();// 返回工厂方法的名称
   ConstructorArgumentValues getConstructorArgumentValues();// 构造方法的参数值
   default boolean hasConstructorArgumentValues() {// 是否存在有构造方法的参数值
      return !getConstructorArgumentValues().isEmpty();
   }
   MutablePropertyValues getPropertyValues();// 获取属性内容
   default boolean hasPropertyValues() { // 判断是否存在属性
      return !getPropertyValues().isEmpty();
   }
   void setInitMethodName(@Nullable String initMethodName); // 设置初始化方法名称
   @Nullable
   String getInitMethodName();// 获取初始化方法名称
   void setDestroyMethodName(@Nullable String destroyMethodName); // 设置销毁方法名称
   @Nullable
   String getDestroyMethodName();// 获取销毁方法名称
   void setRole(int role); // 设置角色
   int getRole();// 返回角色标记
   void setDescription(@Nullable String description); // 设置描述信息
   @Nullable
   String getDescription();// 得到描述信息
   ResolvableType getResolvableType();// 解析类型
   boolean isSingleton();// 是否为单例结构
   boolean isPrototype();// 是否为原型结构
   boolean isAbstract();// 是否为抽象
   @Nullable
   String getResourceDescription();// 获取资源描述
   @Nullable
   BeanDefinition getOriginatingBeanDefinition();// 获取原始的Bean定义信息
}


2、

package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        SmartInitializingSingleton s;
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
        context.scan("com.yootk.dao"); //  配置扫描包
        context.refresh(); // 刷新操作
        BeanDefinition definition = context.getBeanDefinition("deptDAOImpl"); // 获取Bean的信息项
        LOGGER.info("【Bean信息】类名称:{}", definition.getBeanClassName()); // 解析的结果
        LOGGER.info("【Bean信息】单例状态:{}、原型状态:{}", definition.isSingleton(), definition.isPrototype());
    }
}

BeanDefinitionParserDelegate

DocumentLoader

  • 基于 XML 配置的 Spring 环境,在上下文启动时,往往都需要定义配置资源路径,这样应用程序才可以对指定的资源数据进行解析处理,所以整个的解析流程由两个组成部分一个是获取 XML 文档,另一个就是进行文档的解析。W3C 标准中定义了 DOM 文档的获取流程,但是传统的 DOM 标准处理实在是过于繁琐为了简化这一操作流程,Spring 提供了一个 DocumentLoader 处理接口,该接口可以根据指定的 XML 数据、EntityResolver 创建 Document 接口实例,从而便于 Spring 的后续解析操作,DocumentLoader 接口的定义结构如图所示。

BeanDefinitionParserDelegate

  • 应用程序获取到了 Document 接口之后,就需要进行进一步的解析处理,由于整个的 XML 配置文件是以“<bean>”元素的定义为主,所以 Spring 提供了 BeanDefinitionParserDelegate 工具类,类关联结构如图所示。该类提供了一个“parseBeanDefinitionElement()”方法,使用此方法可以将每一个 XML 资源文件指定的 Element 资源实例转为 BeanDefinition 接口实例,从而为下一步的 Bean 实例化做出准备。
1、
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>     <!-- 启用Annotation配置注解支持 -->
    <context:component-scan base-package="com.yootk"/>
    <context:property-placeholder location="classpath:config/*.properties"/>
    <bean id="messageListener" class="com.yootk.listener.MessageListener"
        init-method="openChannel" destroy-method="closeChannel"/>
    <bean id="companyA" class="com.yootk.vo.CompanyA">
        <property name="title" value="Hello Muyan"/>
    </bean>
    <bean id="companyB" class="com.yootk.vo.CompanyB">
        <property name="title" value="Hello Yootk"/>
    </bean>
</beans>

2、
package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.util.xml.XmlValidationModeDetector;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Scanner;

public class SpringSourceDemo { // 李兴华高薪就业编程训练营
    private static final Logger LOGGER =
            LoggerFactory.getLogger(SpringSourceDemo.class);
    // 定义当前要解析的XML配置文件的路径(在Spring容器启动的时候,也会提供有资源获取的支持)
    public static final String RESOURCE_NAME = "classpath:spring/spring-base.xml";
    public static void main(String[] args) throws Exception { // 沐言科技:www.yootk.com
        BeanDefinitionRegistry registry = new AnnotationConfigApplicationContext();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
        int count = reader.loadBeanDefinitions(RESOURCE_NAME); // 获取Bean名称
        if (count > 0) {    // 当前的配置文件之中提供有Bean定义
            Document document = getDocument(reader); // 获取当前要操作文档的Document实例
            NodeList list = document.getElementsByTagName("bean"); // 获取Bean元素
            BeanDefinitionParserDelegate parserDelegate =
                    new BeanDefinitionParserDelegate(getReaderContext(reader));
            for (int x = 0; x < list.getLength(); x++) { // 迭代Node接口集合
                Element element = (Element) list.item(x); // 获取Bean元素
                BeanDefinitionHolder holder = parserDelegate.parseBeanDefinitionElement(element); // 元素解析
                BeanDefinition definition = holder.getBeanDefinition();
                LOGGER.info("【Bean配置】id = {}、class = {}",
                        element.getAttribute("id"), definition.getBeanClassName());
            }
        }
    }
    public static Document getDocument(XmlBeanDefinitionReader reader) throws Exception {
        // 获取资源实体解析的工具类对象实例
        ResourceEntityResolver resolver = new ResourceEntityResolver(reader.getResourceLoader());
        reader.setEntityResolver(resolver);
        DocumentLoader documentLoader = new DefaultDocumentLoader(); // 文档加载器
        // 通过当前给定的资源来获取指定的输入源对象实例
        InputSource inputSource = new InputSource(reader.getResourceLoader().getResource(RESOURCE_NAME).getInputStream());
        Document document = documentLoader.loadDocument(inputSource, resolver, new DefaultHandler(),
                XmlValidationModeDetector.VALIDATION_XSD, true);
        return document;
    }
    public static XmlReaderContext getReaderContext(XmlBeanDefinitionReader reader) {
        XmlReaderContext context = reader.createReaderContext(reader.getResourceLoader().getResource(RESOURCE_NAME));
        return context;
    }
}

BeanFactory

Spring 中的 Bean 管理

  • 在 Spring 使用过程中,不管是基于 XML 配置文件的模式,还是基于 Annotation 扫描注解的处理方式,最终所有配置的类都会被 Spring 自动进行实例化处理,而后统一放在当用户需要某一个 Bean 对象时 Spring 容器内进行存储,如图所示。可以通过 getBean()方法手工获取,后者是利用“@Autowired”注解自动注入,这之中主要依靠 BeanFactory 接口来提供支持。

1、
package org.springframework.beans.factory;
public interface BeanFactory { // 有Spring记录以来最古老的一个接口
   String FACTORY_BEAN_PREFIX = "&"; // FactoryBean获取标记
   Object getBean(String name) throws BeansException; // 根据名称获取Bean实例
   <T> T getBean(String name, Class<T> requiredType) throws BeansException;
   Object getBean(String name, Object... args) throws BeansException;
   <T> T getBean(Class<T> requiredType) throws BeansException; // 根据类型获取Bean
   <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
   <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
   <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
   boolean containsBean(String name); // 判断是否有指定名称的Bean存在
   boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
   boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
   boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; // 能否进行类型的匹配
   boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
   @Nullable
   Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 获取Bean的类型
   @Nullable
   Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
   String[] getAliases(String name); // 获取Bean的别名
}


2、
package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringSourceDemo { // 李兴华高薪就业编程训练营
    private static final Logger LOGGER =
            LoggerFactory.getLogger(SpringSourceDemo.class);
    public static void main(String[] args) throws Exception { // 沐言科技:www.yootk.com
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext();
        context.scan("com.yootk.dao"); // 设置扫描包
        context.refresh(); // 刷新上下文
        BeanFactory factory = context; // 子类实例转为父接口对象
        LOGGER.info("【BEAN信息】单例状态:{}", factory.isSingleton("deptDAOImpl"));
        LOGGER.info("【BEAN信息】原型状态:{}", factory.isPrototype("deptDAOImpl"));
        LOGGER.info("【BEAN信息】实例信息:{}", factory.getType("deptDAOImpl"));
    }
}

ListableBeanFactory

ListableBeanFactory

  • 为了便于对象依赖注入的配置管理,Spring 容器在启动时就必须将所有用到的 Bean 实例保存在容器之中,这样就可以依靠 BeanFactory 接口提供的方法获取指定的 Bean 实例,但是在一些开发的场景中,除了 Bean 本身的需求之外,也需要一些额外的配置信言,例如:同一类型的 Bean 存在的数量、容器中包含的 Bean 数量、使用指定注解 Bean 的信息等

1、
package org.springframework.beans.factory;
import java.lang.annotation.Annotation;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
public interface ListableBeanFactory extends BeanFactory { // 出生在2001年
   boolean containsBeanDefinition(String beanName); // 判断是否有指定的Bean定义
   int getBeanDefinitionCount();// 获取Bean定义的个数
   String[] getBeanDefinitionNames();// 获取Bean的名称
   <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit);
   <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit);
   String[] getBeanNamesForType(ResolvableType type); // 根据类型获取Bean名称
   String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
   String[] getBeanNamesForType(@Nullable Class<?> type); // 根据类型获取Bean名称集合
   String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
   <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
   <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
         throws BeansException;
   String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
   Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
   @Nullable
   <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
         throws NoSuchBeanDefinitionException;
   @Nullable
   <A extends Annotation> A findAnnotationOnBean(
         String beanName, Class<A> annotationType, boolean allowFactoryBeanInit)
         throws NoSuchBeanDefinitionException;
}


2、
package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Repository;

import java.util.Arrays;

public class SpringSourceDemo { // 李兴华高薪就业编程训练营
    private static final Logger LOGGER =
            LoggerFactory.getLogger(SpringSourceDemo.class);
    public static void main(String[] args) throws Exception { // 沐言科技:www.yootk.com
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext();
        context.scan("com.yootk.dao"); // 设置扫描包
        context.refresh(); // 刷新上下文
        LOGGER.info("Spring容器之中Bean的数量:{}", context.getBeanDefinitionCount());
        LOGGER.info("Spring容器之中Bean的名称:{}", Arrays.toString(context.getBeanDefinitionNames()));
        LOGGER.info("拥有Repository注解的Bean名称:{}", context.getBeansWithAnnotation(Repository.class));
    }
}

ConfigurableBeanFactory 获取单例 Bean

ConfigurableBeanFactory

  • 在 Spring 容器之中存在有两种类型的 Bean,一种是基于“Singleton”模式的单例 Bean,另外一种是基"Prototype"模式的原型 Bean,所有的 Bean 实例都可以通过 BeanFactory 接口定义的 getBean()方法获取,而为了更加规范化的管理 Bean 模式,Spring 提供了一个 ConfigurableBeanFactory 接口,如图所示。可以发现该接口继承了主要扩展了--个单例 Bean 注册管理父接口(SingletonBeanRegistry)而 SingletonBeanRegistry 接口里面提供有一个 getSingleton()方法,此方法只能够获取单例模式的 Bean,而无法获取 Prototype 模式的 Bean。
1、
package com.yootk.vo;

import org.springframework.stereotype.Component;

@Component
public class Member {
    public String toString() {
        return "【" + super.hashCode() + "】Member对象实例";
    }
}


2、
package com.yootk.main;

import com.yootk.vo.Member;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
        context.scan("com.yootk.vo"); //  配置扫描包
        context.refresh(); // 刷新操作
        LOGGER.info("{}", context.getBean(Member.class));
        LOGGER.info("{}", context.getBean(Member.class));
        LOGGER.info("{}", context.getBean(Member.class));
    }
}


3、
package org.springframework.beans.factory.config;
public interface ConfigurableBeanFactory extends
              HierarchicalBeanFactory, SingletonBeanRegistry {
   String SCOPE_SINGLETON = "singleton"; // 单例标记
   String SCOPE_PROTOTYPE = "prototype"; // 原型标记
   // 设置父BeanFactory
   void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
   void setBeanClassLoader(@Nullable ClassLoader beanClassLoader); // 类加载器
   @Nullable
   ClassLoader getBeanClassLoader();// 获取类加载器
   void setTempClassLoader(@Nullable ClassLoader tempClassLoader); // 临时类加载器
   @Nullable
   ClassLoader getTempClassLoader();// 返回临时类加载器
   void setCacheBeanMetadata(boolean cacheBeanMetadata); // 缓存Bean元数据
   boolean isCacheBeanMetadata();// 是否存在有缓存Bean元数据
   void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver); // 表达式解析
   @Nullable
   BeanExpressionResolver getBeanExpressionResolver();// 获取表达式解析
   void setConversionService(@Nullable ConversionService conversionService); // 转换服务
   @Nullable
   ConversionService getConversionService();// 返回转换服务实例
   void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar); // 属性编辑器注册类
   void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass); // 属性编辑器
   void copyRegisteredEditorsTo(PropertyEditorRegistry registry); // 拷贝处理
   void setTypeConverter(TypeConverter typeConverter); // 类型转换器
   TypeConverter getTypeConverter();// 获取类型转换器
   void addEmbeddedValueResolver(StringValueResolver valueResolver); // 字符串解析工具
   boolean hasEmbeddedValueResolver();
   @Nullable
   String resolveEmbeddedValue(String value); // 字符串解析
   void addBeanPostProcessor(BeanPostProcessor beanPostProcessor); // BeanPostProcessor
   int getBeanPostProcessorCount();// BeanPostProcessor个数
   void registerScope(String scopeName, Scope scope); // 注册Scope
   String[] getRegisteredScopeNames();// 返回注册的Scope的名称集合
   @Nullable
   Scope getRegisteredScope(String scopeName); // 获取Scope
   void setApplicationStartup(ApplicationStartup applicationStartup); // 启动步骤
   ApplicationStartup getApplicationStartup();// 启动步骤返回
   void copyConfigurationFrom(ConfigurableBeanFactory otherFactory); // 配置拷贝
   void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;
   void resolveAliases(StringValueResolver valueResolver); // 解析别名
   BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; // 合并Bean信息
   boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;
   void setCurrentlyInCreation(String beanName, boolean inCreation);
   boolean isCurrentlyInCreation(String beanName);
   void registerDependentBean(String beanName, String dependentBeanName);
   String[] getDependentBeans(String beanName);
   String[] getDependenciesForBean(String beanName);
   void destroyBean(String beanName, Object beanInstance);
   void destroyScopedBean(String beanName);
   void destroySingletons();
}


4、
package com.yootk.main;

import com.yootk.vo.Member;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        ConfigurableBeanFactory s;
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
        context.scan("com.yootk.vo"); //  配置扫描包
        context.refresh(); // 刷新操作
        ConfigurableBeanFactory configurableBeanFactory = context.getBeanFactory();
        LOGGER.info("{}", configurableBeanFactory.getBean(Member.class)); // 父接口继承而来的
        LOGGER.info("{}", configurableBeanFactory.getSingleton("member"));
        LOGGER.info("{}", configurableBeanFactory.getSingleton("member"));
    }
}

Bean 创建

AutowireCapableBeanFactory

  • BeanFactory 接口的核心功能在于 Bean 的管理,所有被解析完成的 Bean 配置,都可以通过 BeanFactory 提供的方法进行注册,这样就可以在容器上下文中保存对应的实例。但是在 Spring 设计时,充分考虑到了功能结构的划分,所以在 BeanFactory 接口中只提供了 Bean 的获取操作而 Bean 的注册操作则是由 AutowireCapableBeanFactory 子接口完成。

doCreateBean() 方法调用流程

  • AutowireCapableBeanFactory 接口中提供的 createBean()方法需要接收目标类的 Class 实例,由于在实例化前后还需要进行一些 Bean 结构的存储,所以使用 RootBeanDefinition 类进行包装,随后交由 doCreateBean()方法进行对象实例化处理而此方法的调用结构如图所示。

Spring 三级缓存

  • 所有被 Spring 解析生成的 Bean 实例,最终都是保存在 Spring 上下文容器之中,而具体的存放位置是在 DefaultSingletonBeanRegistry 类属性之中,在该类提供有三个核心属性,定义如下:

ObjectProvider

ObjectProvider

  • Spring 传统的开发中,所有在容器中的 Bean 都可以通过 BeanFactory 接口提供的 getBean()方法进行操作,而在 Spring 4.3 版本后,为了进一步规范化 Bean 的管理机制提供了 ObjectProvider 操作接口

ObjectProvider 获取对象流程

  • ObjectProvider 是 ObjectFactory 的子接口,当用户获取到了 ObjectProvider 之后,就可以利用 getObject()方法获取 Spring 容器中已经保存的,指定类型的 Bean 实例,为了便于读者理解,下面将采用图所示的结构进行具体操作的实现。
1、
package com.yootk.main;

import com.yootk.vo.Member;
import com.yootk.vo.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
        context.scan("com.yootk.vo"); //  配置扫描包
        context.refresh(); // 刷新操作
        ObjectProvider<Member> provider = context.getBeanProvider(Member.class);
        LOGGER.info("【实现类】{}", provider);
        for (Member member : provider) {
            LOGGER.info("【Member信息】{}", member);
        }
    }
}


2、
package com.yootk.main;

import com.yootk.config.NewCompanyConfig;
import com.yootk.vo.ICompany;
import com.yootk.vo.Member;
import com.yootk.vo.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
//        context.scan("com.yootk.vo"); //  配置扫描包
        context.register(NewCompanyConfig.class);
        context.refresh(); // 刷新操作
        ObjectProvider<ICompany> provider = context.getBeanProvider(ICompany.class);
        LOGGER.info("【实现类】{}", provider);
        for (ICompany company : provider) {
            LOGGER.info("【Member信息】{}", company);
        }
    }
}


3、
package com.yootk.main;

import com.yootk.config.NewCompanyConfig;
import com.yootk.vo.ICompany;
import com.yootk.vo.Member;
import com.yootk.vo.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
//        context.scan("com.yootk.vo"); //  配置扫描包
        context.register(NewCompanyConfig.class);
        context.refresh(); // 刷新操作
        ObjectProvider<ICompany> provider = context.getBeanProvider(ICompany.class);
        LOGGER.info("【Bean实例】{}", provider.stream().findFirst().orElse(null));
    }
}

FactoryBean

FactoryBean 接口

  • Spring 为了加强 Bean 的管理,同时也为了更好的节约 JVM 的内存占用问题,所有存储在 Spring 容器中的 Bean 默认全部采用单例模式进行存储,虽然这种存储管理解决了大部分的用户需要,可是也会存在有一些特殊情况无法满足。例如:现在有一个 Dept 信息类,开发者要求在 Spring 容器中保存有多个内容不同的 Dept 对象实例,很明显这样的处理机制就无法单纯的依靠 BeanFactory 接口实现的,此时就需要使用到 FactoryBean 接口,该接口定义如下,
1、
package com.yootk.vo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Dept {
    private Long deptno;
    private String dname;
    private String loc;

    public Dept() {}

    public Dept(Long deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }

    public Long getDeptno() {
        return deptno;
    }

    public void setDeptno(Long deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    @Override
    public String toString() {
        return "【部门信息 - " + super.hashCode() + "】编号:" + this.deptno + "、名称:" + this.dname + "、位置:" + this.loc;
    }
}


2、
package com.yootk.factory;

import com.yootk.vo.Dept;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component
public class DeptFactoryBean implements FactoryBean<Dept> {
    @Override
    public Dept getObject() throws Exception {
        return new Dept(10L, "沐言科技教学研发部", "洛阳"); // 返回对象实例
    }

    @Override
    public Class<?> getObjectType() {
        return Dept.class;
    }
}


3、
package com.yootk.main;

import com.yootk.vo.Dept;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
        context.scan("com.yootk.factory"); //  配置扫描包
        context.refresh(); // 刷新操作
        FactoryBean<Dept> factoryBean = context.getBean("&deptFactoryBean", FactoryBean.class);
        LOGGER.info("{}", factoryBean.getObject());
        LOGGER.info("{}", factoryBean.getObject());
    }
}

BeanFactoryPostProcessor

BeanFactoryPostProcessor 处理逻辑

  • Spring 之中会存在有大量的 Bean 实例,所有的 Bean 在进行初始化配置时,一般都只会设置一些基础的信息,但是有可能某些配置属性的内容是需要进行一-些逻辑处理后才可以配置的,所以此时就提供了 BeanFactoryPostProcessor 处理接口
1、
package com.yootk.config;

public class MessageChannel { // 随意定义一个程序类
    private String host;
    private String token;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}


2、
package com.yootk.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // 配置Bean
public class MessageConfig {
    @Bean
    public MessageChannel messageChannel() {
        MessageChannel channel = new MessageChannel(); // 对象实例化
        channel.setHost("jixianit.com"); // 配置一个初期的属性内容
        channel.setToken("yootk-jixianit");// 配置一个初期的属性内容
        return channel; // 返回对象实例
    }
}


3、
package com.yootk.processor;

import com.yootk.config.MessageChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MessageBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    private static final Logger LOGGER =
            LoggerFactory.getLogger(MessageBeanFactoryPostProcessor.class);
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 此时已经可以在此方法之中直接使用BeanFactory接口实例获取Bean(Spring三级缓存结构)
        // 严格来讲此时表示的是BeanFactory已经构建成功了
        MessageChannel channel = beanFactory.getBean(MessageChannel.class); // 获取指定类型的Bean
        LOGGER.info("【默认消息通道配置】服务主机:{}、访问Token:{}", channel.getHost(), channel.getToken());
        channel.setHost("edu.yootk.com"); // 修改了Bean属性定义
        channel.setToken("Yootk-TOKEN"); // 修改了Bean属性定义
    }
}


4、

package com.yootk.main;

import com.yootk.config.MessageChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
        context.scan("com.yootk.config", "com.yootk.processor"); //  配置扫描包
        context.refresh(); // 刷新操作
        MessageChannel channel = context.getBean(MessageChannel.class); // 获取Bean实例
        LOGGER.info("【消息通道】服务主机:{}、访问Token:{}",
                channel.getHost(), channel.getToken());
    }
}

BeanFactoryPostProcessor 结构解析

BeanFactoryPostProcessor 调用流程

  • 在 Spring 内部所有关于 BeanFactoryPostProcessor 接口的调用逻辑都是通过 PostProcessorRegistrationDelegate 类中提供的 invokeBeanFactoryPostProcessors()方法进行调用的
1、
package com.yootk.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;

public class MessageChannel implements SmartInitializingSingleton { // 随意定义一个程序类
    private final static Logger LOGGER = LoggerFactory.getLogger(MessageChannel.class);
    private String host;
    private String token;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    @Override
    public void afterSingletonsInstantiated() {
        LOGGER.info("MessageChannel初始化处理。");
    }
}

EventListenerMethodProcessor 定义事件处理

EventListenerMethodProcessor 定义结构

  • Spring 中提供的自定义事件管理中,需要开发者通过 ApplicationListener 接口实现事件监听类的定义,而所有配置的事件监听类最终要想被 Spring 容器所管理,那么就要通过 EventListenerMethodProcessor 类来进行处理
1、
@Override
public void afterSingletonsInstantiated() {
   ConfigurableListableBeanFactory beanFactory = this.beanFactory; // 引用处理
   Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
   String[] beanNames = beanFactory.getBeanNamesForType(Object.class); // 获取对象名称
   for (String beanName : beanNames) { // 名称迭代
      if (!ScopedProxyUtils.isScopedTarget(beanName)) { // 判断Scope类型
         Class<?> type = null; // 保存对象类型
         try { // 通过代理工具类检查目标类型的对象实例
            type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
         } catch (Throwable ex) { … }
         if (type != null) { // 现在获取到了指定的实例
            if (ScopedObject.class.isAssignableFrom(type)) { // 是否已经有了指派
               try { // 获取目标类型
                  Class<?> targetClass = AutoProxyUtils.determineTargetClass(
                        beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
                  if (targetClass != null) {
                     type = targetClass;
                  }
               }
               catch (Throwable ex) { … }
            try {
               processBean(beanName, type); // 事件的处理操作
            } catch (Throwable ex) { … }
         }
      }
   }
}


2、
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   this.beanFactory = beanFactory; // 保存BeanFactory实例
   Map<String, EventListenerFactory> beans =
                 beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
   List<EventListenerFactory> factories = new ArrayList<>(beans.values());
   AnnotationAwareOrderComparator.sort(factories); // 工厂Bean的排序处理
   this.eventListenerFactories = factories;
}

CustomEditorConfigurer 属性编辑器配置

CustomEditorConfigurer 类关联结构

  • Spring 中考虑到属性资源的注入处理问题,提供了 PropertyEditor 属性编辑器,所有自定义的属性编辑器都需要通过 CustomEditorConfigurer 类进行注册,而该类也属于 BeanFactoryPostProcessor 子类
1、
private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered
@Nullable
private PropertyEditorRegistrar[] propertyEditorRegistrars; // 属性编辑器的注册器
@Nullable
private Map<Class<?>, Class<? extends PropertyEditor>> customEditors; // 自定义属性编辑器
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   if (this.propertyEditorRegistrars != null) { // 是否存在有属性编辑器的注册集合
      for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
         beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar); // Spring存储
      }
   }
   if (this.customEditors != null) { // 判断编辑器的集合不为空
      this.customEditors.forEach(beanFactory::registerCustomEditor); // 注册自定义编辑器
   }
}
public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) {
   this.propertyEditorRegistrars = propertyEditorRegistrars;
}
public void setCustomEditors(Map<Class<?>, Class<? extends PropertyEditor>> customEditors) {
   this.customEditors = customEditors;
}

PropertySourcesPlaceholderConfigurer 属性资源配置

PropertySourcesPlaceholderConfigurer

  • Spring 中可以通过资源文件进行配置项的定义,所有的配置项可以利用“@Value("${资源 KEY}")”注解,进行对应资源内容的注入处理。Spring 中为了实现该操作内容的解析处理,提供了 PropertySourcesPlaceholderConfigurer 配置类,此类主要实现资源的解析与属性注入处理操作

Bean 属性解析

  • 在 PropertySourcesPlaceholderConfigurer 类中实现的 postProcessBeanFactory()方法中会对所有注入的资源属性进行处理,并将这些属性源保存在 MutablePropertySources 属性源集合之中进行管理,随后调用了该类中的 processProperties()方法进行属性的处理。在此方法中就会对资源解析中的“${”前缀和“}”后缀进行配置,由于具体的属性解析处理操作需要通过 StringValueResolver 接口处理,所以定义了一个匿名内部类,利用 PropertySourcesPropertyResolver 实例实现了属性内容的解析处理,而最终属性内容的赋值操作,则是由 doProcessProperties()方法处理的。
  • doProcessProperties()方法内部主要是通过 BeanDefinitionVisitor 类处理的,该类实现了一个 Bean 的属性遍历访问与 Properties 资源的填充处理功能。在该类中首先会通过 visitBeanDefinition()方法进行 Bean 相关信息的获取,随后利用该类中的 visitPropertyValues()方法对属性的内容进行解析,由于属性的类型可能有多种,所以在 BeanDefinitionVisitor 类中是通过 resolveValue()方法实现属性内容的解析操作,这些方法的定义如下图所示,这样就实现了最终资源内容的读取与属性设置操作。
1、
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   try {
      Properties mergedProps = mergeProperties();// 合并属性
      // Convert the merged properties, if necessary.
      convertProperties(mergedProps); // 转换属性
      processProperties(beanFactory, mergedProps); // 交给子类进行属性的处理
   } catch (IOException ex) {
      throw new BeanInitializationException("Could not load properties", ex);
   }
}


2、
protected Properties mergeProperties() throws IOException {
   Properties result = new Properties();// 保存新的结果,本地配置优先
   if (this.localOverride) { // 是否允许本地覆盖
      loadProperties(result); // 通过程序配置的资源实现属性的加载
   }
   if (this.localProperties != null) {
      for (Properties localProp : this.localProperties) { // 迭代
         CollectionUtils.mergePropertiesIntoMap(localProp, result); // 属性合并
      }
   }
   if (!this.localOverride) {
      // Load properties from file afterwards, to let those properties override.
      loadProperties(result);
   }
   return result;
}


3、
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
      StringValueResolver valueResolver) {
   BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
   String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();// 获取Bean名称
   for (String curName : beanNames) { // Bean名称迭代
      // Check that we're not parsing our own bean definition,
      // to avoid failing on unresolvable placeholders in properties file locations.
      if (!(curName.equals(this.beanName) &&
                  beanFactoryToProcess.equals(this.beanFactory))) {
         // 为了将对象实例化的步骤进行有效的拆分,会首先解析出所有的Bean定义信息
         BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); // Bean定义
         try {
            visitor.visitBeanDefinition(bd); // 进行Bean的解析
         } catch (Exception ex) { … }
      }
   }
   // New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
   beanFactoryToProcess.resolveAliases(valueResolver); // 别名的解析
   // New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
   beanFactoryToProcess.addEmbeddedValueResolver(valueResolver); // 内嵌解析
}

ConfigurationClassPostProcessor 配置类解析

ConfigurationClassPostProcessor

  • Spring 内部支持有 Bean 配置注解,在一个 Bean 中可以使用“@Configuration”注解定义配置 Bean,或者直接基于扫描包的的定义使用"@Component 注解实现扫描配置,而实现这些注"@Service""@Repository"@Action"解配置的处理类就是 ConfigurationClassPostProcessor,该类为 BeanFactoryPostProcessor 接子类
1、
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); // Bean配置集合
   String[] candidateNames = registry.getBeanDefinitionNames();     // 获取所有Bean的名称
   for (String beanName : candidateNames) { // Bean迭代
      // 所有的配置类最终都会向Spring容器里面进行注册处理的,主要就是由如下代码执行的
      BeanDefinition beanDef = registry.getBeanDefinition(beanName); // Bean注册
      if (beanDef.getAttribute(ConfigurationClassUtils
                 .CONFIGURATION_CLASS_ATTRIBUTE) != null) { // 存在有指定的属性
      } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(
beanDef, this.metadataReaderFactory)) {
         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); // 保存配置Bean
      }
   }
   if (configCandidates.isEmpty()) { // 如果没有@Configruation类存在
      return; // 直接结束方法调用
   }
   // 如果配置的Bean上使用了@Order注解进行定义,那么就需要进行顺序的排列
   configCandidates.sort((bd1, bd2) -> {
      int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
      int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
      return Integer.compare(i1, i2);
   });
   // Detect any custom bean name generation strategy supplied through the enclosing application context
   SingletonBeanRegistry sbr = null; // 进行单例Bean的注册
   if (registry instanceof SingletonBeanRegistry) { // 当前所获取到的注册器的类型是否匹配
      sbr = (SingletonBeanRegistry) registry; // 进行指定类型的对象实例转型
      if (!this.localBeanNameGeneratorSet) { // 判断是否要生成Bean名称
         // 配置类之中使用的Bean名称就是方法名称,如果通过“<bean>”XML配置项进行的定义没有设置id
         BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
               AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); // 生成Bean名称
         if (generator != null) { // 生成器不为空
            this.componentScanBeanNameGenerator = generator; // 保存生成器
            this.importBeanNameGenerator = generator;
         }
      }
   }
   if (this.environment == null) { // 获取Environment接口实例
      this.environment = new StandardEnvironment();
   }
   // 解析每一个拥有 @Configuration 注解的配置类
   ConfigurationClassParser parser = new ConfigurationClassParser(
         this.metadataReaderFactory, this.problemReporter, this.environment,
         this.resourceLoader, this.componentScanBeanNameGenerator, registry);
   Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
   Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
   do {
      StartupStep processConfig =
           this.applicationStartup.start("spring.context.config-classes.parse");
      parser.parse(candidates); // Bean解析处理
      parser.validate();// 校验
      Set<ConfigurationClass> configClasses =
              new LinkedHashSet<>(parser.getConfigurationClasses());
      configClasses.removeAll(alreadyParsed);
      // Read the model and create bean definitions based on its content
      if (this.reader == null) {
         this.reader = new ConfigurationClassBeanDefinitionReader(
               registry, this.sourceExtractor, this.resourceLoader, this.environment,
               this.importBeanNameGenerator, parser.getImportRegistry());
      }
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
      candidates.clear();
      if (registry.getBeanDefinitionCount() > candidateNames.length) {
         String[] newCandidateNames = registry.getBeanDefinitionNames();
         Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
         Set<String> alreadyParsedClasses = new HashSet<>();
         for (ConfigurationClass configurationClass : alreadyParsed) {
            alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
         }
         for (String candidateName : newCandidateNames) {
            if (!oldCandidateNames.contains(candidateName)) {
               BeanDefinition bd = registry.getBeanDefinition(candidateName);
               if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd,
                            this.metadataReaderFactory) &&
                     !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                  candidates.add(new BeanDefinitionHolder(bd, candidateName));
               }
            }
         }
         candidateNames = newCandidateNames;
      }
   }
   while (!candidates.isEmpty());// 处理完全部的配置类
   // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
   if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
      sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
   }
   if (this.metadataReaderFactory instanceof
            CachingMetadataReaderFactory cachingMetadataReaderFactory) {
      // Clear cache in externally provided MetadataReaderFactory; this is a no-op
      // for a shared cache since it'll be cleared by the ApplicationContext.
      cachingMetadataReaderFactory.clearCache();
   }
}


2、
public void parse(Set<BeanDefinitionHolder> configCandidates) {
   for (BeanDefinitionHolder holder : configCandidates) {
      BeanDefinition bd = holder.getBeanDefinition();
      try {
         if (bd instanceof AnnotatedBeanDefinition) {
            parse(((AnnotatedBeanDefinition) bd).getMetadata(),
                         holder.getBeanName());
         } else if (bd instanceof AbstractBeanDefinition &&
                       ((AbstractBeanDefinition) bd).hasBeanClass()) {
            parse(((AbstractBeanDefinition) bd).getBeanClass(),
                     holder.getBeanName());
         } else {
            parse(bd.getBeanClassName(), holder.getBeanName());
         }
      } catch (BeanDefinitionStoreException ex) {
         throw ex;
      } catch (Throwable ex) { … }
   }
   this.deferredImportSelectorHandler.process();
}


3、
protected final void parse(@Nullable String className, String beanName) throws IOException {
   Assert.notNull(className, "No bean class name for configuration class bean definition");
   MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
   processConfigurationClass(new ConfigurationClass(reader, beanName),
               DEFAULT_EXCLUSION_FILTER);
}
protected final void parse(Class<?> clazz, String beanName) throws IOException {
   processConfigurationClass(new ConfigurationClass(clazz, beanName),
              DEFAULT_EXCLUSION_FILTER);
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
   processConfigurationClass(new ConfigurationClass(metadata, beanName),
            DEFAULT_EXCLUSION_FILTER);
}


4、
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
   if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(),
ConfigurationPhase.PARSE_CONFIGURATION)) {
      return;
   }
   ConfigurationClass existingClass = this.configurationClasses.get(configClass);
   if (existingClass != null) {
      if (configClass.isImported()) {
         if (existingClass.isImported()) {
            existingClass.mergeImportedBy(configClass);
         }
         // Otherwise ignore new imported config class; existing non-imported class overrides it.
         return;
      } else {
         // Explicit bean definition found, probably replacing an import.
         // Let's remove the old one and go with the new one.
         this.configurationClasses.remove(configClass);
         this.knownSuperclasses.values().removeIf(configClass::equals);
      }
   }
   // Recursively process the configuration class and its superclass hierarchy.
   SourceClass sourceClass = asSourceClass(configClass, filter);
   do {
      sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
   } while (sourceClass != null);
   this.configurationClasses.put(configClass, configClass);
}


5、
@Nullable
protected final SourceClass doProcessConfigurationClass(
      ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
      throws IOException {
   if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
      // Recursively process any member (nested) classes first
      processMemberClasses(configClass, sourceClass, filter); // Component注解配置
   }
   // 处理包含有@PropertySource注解的操作,在进行资源注入的时候使用过该注解
   for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), PropertySources.class,
         org.springframework.context.annotation.PropertySource.class)) {
      if (this.environment instanceof ConfigurableEnvironment) {
         processPropertySource(propertySource);
      } else {
         logger.info("Ignoring @PropertySource annotation …");
      }
   }
   // 处理所有的@ComponentScan注解
   Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
   if (!componentScans.isEmpty() &&
         !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
      for (AnnotationAttributes componentScan : componentScans) {
         Set<BeanDefinitionHolder> scannedBeanDefinitions =
               this.componentScanParser.parse(componentScan,
                   sourceClass.getMetadata().getClassName());
         // Check the set of scanned definitions for any further config classes and parse recursively if needed
         for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
            if (bdCand == null) {
               bdCand = holder.getBeanDefinition();
            }
            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand,
                          this.metadataReaderFactory)) {
               parse(bdCand.getBeanClassName(), holder.getBeanName());
            }
         }
      }
   }
   // 处理包含有@Import注解
   processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
   // 处理包含有@ImportResource注解的操作
   AnnotationAttributes importResource =
         AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
   if (importResource != null) {
      String[] resources = importResource.getStringArray("locations");
      Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
      for (String resource : resources) {
         String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
         configClass.addImportedResource(resolvedResource, readerClass);
      }
   }
   // 处理Bean方法定义
   Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
   for (MethodMetadata methodMetadata : beanMethods) {
      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
   }
   // Process default methods on interfaces
   processInterfaces(configClass, sourceClass); // 处理接口
   // Process superclass, if any
   if (sourceClass.getMetadata().hasSuperClass()) {
      String superclass = sourceClass.getMetadata().getSuperClassName();
      if (superclass != null && !superclass.startsWith("java") &&
            !this.knownSuperclasses.containsKey(superclass)) {
         this.knownSuperclasses.put(superclass, configClass);
         // Superclass found, return its annotation metadata and recurse
         return sourceClass.getSuperClass();
      }
   }
   // No superclass -> processing is complete
   return null;
}

BeanPostProcessor 初始化处理

BeanPostProcessor

  • Spring 容器中会管理大量的 Bean 实例,所有用户定义的 Bean 在 Spring 容器之中都可以进行初始化的前后控制处理,如图所示。而实现这一功能的就是 BeanPostProcessor 接口,该接口可以在 Bean 初始化的前后自动调用。
1、
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;
public interface BeanPostProcessor {
   @Nullable
   default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 在Bean初始化之前进行调用
      return bean;
   }
   @Nullable
   default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // 在Bean初始化之后进行调用
      return bean;
   }
}


2、
package com.yootk.processor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component // 通过扫描进行注册配置
public class MessageBeanPostProcessor implements BeanPostProcessor {
    private static final Logger LOGGER = LoggerFactory.getLogger(MessageBeanPostProcessor.class);

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在这个处理方法上会自动传递Bean对象实例,以及BeanName
        LOGGER.info("【postProcessBeforeInitialization() - Bean初始化之前】Bean = {}, BeanName = {}",
                bean, beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        LOGGER.info("【postProcessAfterInitialization() - Bean初始化之后】Bean = {}, BeanName = {}",
                bean, beanName);
        return bean;
    }
}


3、

package com.yootk.main;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.concurrent.TimeUnit;

public class StartYootkSpringApplication { // Spring容器的启动类
    private static final Logger LOGGER =
            LoggerFactory.getLogger(StartYootkSpringApplication.class);
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(); // 注解方式来启动Spring容器
        context.scan("com.yootk.config", "com.yootk.processor"); //  配置扫描包
        context.refresh(); // 刷新操作
        TimeUnit.SECONDS.sleep(2); // 慢一点结束
    }
}

Bean 初始化流程

Bean 初始化生命周期

  • Spring 在使用时需要将所有的 Bean 对象实例统一归纳到 Spring 上下文之中进行管理这样才可以方便的实现不同 Bean 实例之间的依赖关联,以及生命周期控制。而在 Spring 框架中针对于生命周期的控制提供了不少的处理操作逻辑,这些逻辑的处理顺

demo


上次编辑于: