属性源原理解析2
大约 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