参考文献:
Spring源码-基础
BeanDefinition 为我们统一了 bean 的元数据,bean 的元数据就是指我们使用 xml 或者注解进行配置的数据,我们的 spring 容器启动之前的第一步就是加载配置数据,这些元数据会被加载到内存中以一个个 beanDefinition 的形式保存在一个 map 中。
一个 BeanDifinition
大概保存了以下信息:
结构图如下:
beanDefinition来源不同可能会有不同实现,目前我们最常用的实现就是GenericBeanDefinition这个实现类。
小知识:Generic(一般的,通用的),几乎所有以这个单词打头的实现,都是spring的通用实现。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 常量标志一个bean的作用范围
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// 设置父BeanDefinition,可以只对有父子关系的bean
void setParentName(@Nullable String parentName);
String getParentName();
// bean的类的全限定名
void setBeanClassName(@Nullable String beanClassName);
String getBeanClassName();
void setScope(@Nullable String scope);
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 设置依赖性,被依赖的bean会优先创建
void setDependsOn(@Nullable String... dependsOn);
String[] getDependsOn();
// 是否允许自动装配
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 设置是否主要bean
void setPrimary(boolean primary);
boolean isPrimary();
// 工厂bean和工厂方法
void setFactoryBeanName(@Nullable String factoryBeanName);
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String factoryMethodName);
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// 使用setter注入时的key-value对,都保存在这里
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// @since 5.1初始化方法和销毁方法
void setInitMethodName(@Nullable String initMethodName);
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
String getDestroyMethodName();
// 为bean设置角色
void setRole(int role);
int getRole();
// bean的描述
void setDescription(@Nullable String description);
String getDescription();
// 返回此bean定义的可解析类型,基于bean类或其他特定元数据。
// 这通常在运行时合并bean定义上完全解决但不一定是在配置时定义实例上。
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
}
该类对通用核心方法完成了实现(这也是抽象类的作用),同时对一些成员变量提供了默认值:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// 定义一些常量
public static final String SCOPE_DEFAULT = "";
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
// ...还有很多
// 初始化默认值
private volatile Object beanClass;
private String scope = SCOPE_DEFAULT
private boolean autowireCandidate = true;
private boolean primary = false;
// ...还有很多
// 构造器
protected AbstractBeanDefinition() {
this(null, null);
}
// 指定构造器参数和属性参数
protected AbstractBeanDefinition(@Nullable ConstructorArgumentValues cargs, @Nullable MutablePropertyValues pvs) {
this.constructorArgumentValues = cargs;
this.propertyValues = pvs;
}
// 使用深拷贝创建一个新的
protected AbstractBeanDefinition(BeanDefinition original) {
}
// 复制一个bean的定义到当前bean,通常父子bean合并时可用
public void overrideFrom(BeanDefinition other) {
}
// ...此处省略其他的方法实现
}
该类实现比较简单,提供了设置父子关系和构建实例的方法,该类及其子类是目前版本使用最多的BeanDifinition。
ublic class GenericBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
public GenericBeanDefinition() {
super();
}
// 通过深拷贝创建一个bean
public GenericBeanDefinition(BeanDefinition original) {
super(original);
}
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new GenericBeanDefinition(this);
}
}
@Test
public void testGenericBeanDefinition(){
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClassName("com.example.springanalyze.bean.MyTest");
definition.setScope(AbstractBeanDefinition.SCOPE_PROTOTYPE);
definition.setInitMethodName("init");
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("age",19);
definition.setPropertyValues(propertyValues);
System.out.println(definition);
}
@Test
public void testRootBeanDefinition() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
RootBeanDefinition dog = new RootBeanDefinition();
dog.setBeanClassName("com.ydlclass.Dog");
BeanMetadataAttribute color = new BeanMetadataAttribute("color","white");
BeanMetadataAttribute age = new BeanMetadataAttribute("age","3");
dog.addMetadataAttribute(color);
dog.addMetadataAttribute(age);
// 子Definition的创建需要依赖父Definition
ChildBeanDefinition teddy = new ChildBeanDefinition("dog");
teddy.setBeanClassName("com.ydlclass.TeddyDog");
BeanMetadataAttribute name = new BeanMetadataAttribute("name","doudou");
teddy.addMetadataAttribute(name);
}
GenericBeanDefinition 在很多场景下可以替换以下的内容,但是由于历史等原因,RootBeanDefinition 依旧存在而且很重要,后期的归一处理还是要将不同的 BeanDefinition 转换或合至成一个 RootBeanDefinition.
RootBeanDefinition不能有父BeanDefinition,可以和ChildBeanDefinition配合使用构建父子关系(bean是可以继承的)。
目前最常用的BeanDefinition是GenericBeanDefinition及其子类的实现,GenericBeanDefinition很强大,也可以很轻松的独立的构建父子关系。
有了统一标准的元数据之后,我们就可以统一管理,这就需要一个容器去存储,当然我们可以使用 map 这样的集合类,当然 spring 差不多就是这样做的。他为我们提供了一个接口 BeanDefinitionRegistry
。只要实现了这个接口,就会拥有注册 beanDefinition 的能力。
(就好像 mybatis 中类型的别名(TypeAilasRegistry)和类型处理(TypeHandleRegistry)一样,需要注册器进行全局注册)
接口代码如下:
public interface BeanDefinitionRegistry extends AliasRegistry {
// 注册一个BeanDefinition
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}
底层其实就是通过 Map 对 BeanDefinition 的注册操作进行处理的,且默认容量设置为了 256,即256*3/4=196 的时候进行第一次扩容。
@Test
public void testRootBeanDefinition() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 定义一个注册器
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
RootBeanDefinition dog = new RootBeanDefinition();
dog.setBeanClassName("com.ydlclass.Dog");
BeanMetadataAttribute color = new BeanMetadataAttribute("color", "white");
BeanMetadataAttribute age = new BeanMetadataAttribute("age", "3");
dog.addMetadataAttribute(color);
dog.addMetadataAttribute(age);
registry.registerBeanDefinition("dog", dog);
// 子Definition的创建需要依赖父Definition
ChildBeanDefinition teddy = new ChildBeanDefinition("dog");
teddy.setBeanClassName("com.ydlclass.TeddyDog");
BeanMetadataAttribute name = new BeanMetadataAttribute("name", "doudou");
teddy.addMetadataAttribute(name);
registry.registerBeanDefinition("teddy", teddy);
}
当然我们不可能为每一个类手动去编写与之对应的 BeanDefinition,元数据还是要从xml或者从配置类中获取的,spring 为我们提供了对应的工具。(对比 Mybatis 也是一样的,从mybatis核心配置xml里去得到你需要扫描的别名和类型处理器(当然类型处理器它自己内置了,如果自己自定义了的需要自己配置然后让它加载))。
1、 读取 xml 配置文件
该类通过解析 xml 完成 BeanDefinition 的读取,并且将它解析的 BeanDefinition 注册倒一个注册器中:
@Test
public void testRegistryByXml() {
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 创建一个 xml 的 reader
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("classpath:spring-test.xml");
System.out.println(registry);
}
2、加载带注解的 bean
@Test
public void testRegistryByXml() {
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 创建一个 xml 的 reader
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("classpath:spring-test.xml");
System.out.println(registry);
}
3、读取配置类
ConfigurationClassBeanDefinitionReader 可以读取配置类,只是这个类不让我们使用,该类提供了如下方法 :
private void loadBeanDefinitionsForConfigurationClass
private void registerBeanDefinitionForImportedConfigurationClass
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)
他会将读取的元数据封装成为:ConfigurationClassBeanDefinition.
4、类路径扫描
@Test
public void testRegistryByScanner(){
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 通过扫描包的方式去注册 BeanDefinition
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.scan("com.example.springanalyze.bean");
System.out.println(registry);
}
无论是扫包还是其他方式,我们解析一个类无非有以下俩种方式:
毫无疑问 spring 选择了第二种(使用 ASM 技术)
首先:第二种性能要优于第一种;
其次:第一种会将扫描的类全部加载到堆内存,无疑会浪费空间,增加 gc 次数,第二种可以根据元数据按需加载。
doScan
核心代码分析:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
// BeanDefinitionHolder持有 BeanDefinition实例和名字以及别名
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 这里是具体的扫描过程,找出全部符合过滤器要求的BeanDefinition
// 返回的BeanDefinition的实际类型为ScannedGenericBeanDefinition
// 实际是调用scanCandidateComponents方法
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
// 根据不同的bean类型做统一处理,如附默认值等
// 因为有些数据我们并没有配置,需要这里做默认处理
for (BeanDefinition candidate : candidates) {
// 如果存在,则解析@Scope注解,为候选bean设置代理的方式ScopedProxyMode,XML属性也能配置:scope-resolver、scoped-proxy,可以指定代理方式jdk或者cglib
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 首先从注解中获取bean的名字,如果没有
// 使用beanName生成器beanNameGenerator来生成beanName
// 在注解中的bean的默认名称和xml中是不一致的
// 注解中如果没有指定名字本质是通过ClassUtil 的 getShortName 方法获取的
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
// 将进一步设置应用于给定的BeanDefinition,使用AbstractBeanDefinition的一些默认属性值
//设置autowireCandidate属性,即XML的autowire-candidate属性,IoC学习的时候就见过该属性,默认为true,表示该bean支持成为自动注入候选bean
if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 如果bean定义是AnnotatedBeanDefinition类型,ScannedGenericBeanDefinition同样属于AnnotatedBeanDefinition类型
if (candidate instanceof AnnotatedBeanDefinition) {
// 4 处理类上的其他通用注解:@Lazy, @Primary, @DependsOn, @Role, @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查给定的 beanName,确定相应的bean 定义是否需要注册或与现有bean定义兼容
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 根据proxyMode属性的值,判断是否需要创建scope代理,一般都是不需要的
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
scanCandidateComponents
(candidate:候选)方法进行核心源码分析: private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
// 用 Set 去封装 BeanDefinition 进行返回
Set<BeanDefinition> candidates = new LinkedHashSet();
try {
// 去解析出报名,然后拼接成包的解析路径:如:classpath*:com.test/**/*.class
String var10000 = this.resolveBasePackage(basePackage);
String packageSearchPath = "classpath*:" + var10000 + "/" + this.resourcePattern;
// 通过上面拼接的要访问的路径然后获取对应 Resource 对象。
Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = this.logger.isTraceEnabled();
boolean debugEnabled = this.logger.isDebugEnabled();
// 深拷贝一组用于后续处理
Resource[] var7 = resources;
int var8 = resources.length;
for(int var9 = 0; var9 < var8; ++var9) { // 遍历获取到的 .class 对应的 resource 对象
Resource resource = var7[var9];
String filename = resource.getFilename();
if (filename == null || !filename.contains("$$")) {
try {
// 通过 resource 去获取元数据
MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);
// 匹配,也就是判断是否能通过候选需要加载
// 检查读取到的类是否可以作为候选组件,即是否符合TypeFilter类型过滤器的要求
// 使用IncludeFilter。就算目标类上没有@Component注解,它也会被扫描成为一个Bean
// 使用ExcludeFilter,就算目标类上面有@Component注解也不会成为Bean
// 还有会判断是否通过 Confitional 注解,如果配置了的话
if (this.isCandidateComponent(metadataReader)) {
// 如果成功的话就把元数据封装成 ScannerGenericBeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
// 这里的话还会再次进行判断,判断是否是独立的类,就是不是嵌套的类
// 当然静态内部类不一样,静态内部类是可以直接实例化的,这是源于加载阶段就。。。
if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
if (debugEnabled) {
this.logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
} catch (FileNotFoundException var14) {
if (traceEnabled) {
this.logger.trace("Ignored non-readable " + resource + ": " + var14.getMessage());
}
} catch (Throwable var15) {
throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var15);
}
}
}
return candidates;
} catch (IOException var16) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var16);
}
}
比如我在 Person 类上即用了 @Component 注解,也用了 @Conditional
注解,代码如下:
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
@Component
@Data
@Conditional(MyCondition.class)
public class Person {
private String name;
private Integer age;
}
那么由于我配置的 Condition 是返回 false 的,即在上述的扫描中通过不了,所以会导致元数据注册不了,如下所示:
构建 ClassPathBeanDefinitionScanner
包扫描器对象;
配置 @ComponentScan
注解及其属性配置,如:excludeFilters、includeFilters 配置.
调用 doScan
方法进行包扫描。
获取扫描包下的所有 .class 文件对应的 Resource 对象。
通过 ASM 技术获取字节码的文件信息。(此过程是没有经过类加载的,是直接用 ASM 技术处理的字节码)
进行 filter + 条件注解(@Condictional
)的判断;
进行独立类、接口、抽象类、@Lookup的判断。
判断生成的 BeanDefinition 是否重复;
放入集合返回,然后处理默认值等。
Java 中的内省(Introspection)是一种通过分析类的方法和属性来获取类的信息的机制。它允许在运行时检查类的属性和方法,并动态地调用它们。内省通常与Java的反射(Reflection)机制密切相关。
通过内省,可以在运行时获取类的属性(如名称、类型)和方法(如名称、参数等)的信息,并可以通过获取的信息来动态操作这些属性和方法。内省机制可以用来实现动态地设置和获取对象的属性值,以及动态地调用对象的方法。
内省的核心是
Introspector
类 和PropertyDescriptor
类。Introspector
类用于获取一个类的 Bean 信息,而PropertyDescriptor
类则用于描述一个 Bean 类的属性。内省提供了一种方便的方式来操作对象的属性和方法,特别适用于在运行时根据条件动态地处理对象。
获取到 BeanInfo 内省信息
// 获取到 Person.class 中的 beaninfo,且不继承 Object 中的bean信息
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class,Object.class);
然后通过 BeanInfo 获取对应的 Descriptor
然后通过 Descriptor 对象去获取对应的信息
@Test
public void testIntrospector() throws IntrospectionException {
// 获取到 Person.class 中的 beaninfo,且不继承 Object 中的bean信息
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class,Object.class);
MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
for (MethodDescriptor methodDescriptor : methodDescriptors) {
String name = methodDescriptor.getName();
System.out.println(name);
}
}
Spring 中的 BeanUtils 工具类就是通过内省实现的。它使用了 Java 的内省机制来获取和操作对象的属性,BeanUtils 提供了一系列静态方法,用于复制、合并、获取、设置对象的属性值等操作。
@Test
public void testBeanUtils() throws InvocationTargetException, IllegalAccessException {
Person person = new Person();
Method setAge = BeanUtils.findMethod(person.getClass(), "setAge", Integer.class);
setAge.invoke(person,11);
System.out.println(person);
Person personF = new Person();
BeanUtils.copyProperties(person,personF);
System.out.println(personF);
}
// Person(name=null, age=11)
// Person(name=null, age=11)
Spring 和 Mybatis 一样,提供了自定封装的反射工具,针对原生 API 的复杂性,Spring同样进行了封装,让其使用起来更简单。
这个Spring提供的反射工具是 BeanWrapper
,下面的例子展示了该类与 BeanDefinition 的配合使用:
@Test
public void testBeanWrapper() throws ClassNotFoundException {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClassName("com.example.springanalyze.bean.Person");
MutablePropertyValues multipartProperties = new MutablePropertyValues();
multipartProperties.addPropertyValue("age",12);
multipartProperties.addPropertyValue("name","傻逼");
definition.setPropertyValues(multipartProperties);
String className = definition.getBeanClassName();
Class<?> aClass = Class.forName(className);
BeanWrapper beanWrapper = new BeanWrapperImpl(aClass);
beanWrapper.setPropertyValues(definition.getPropertyValues());
Object obj = beanWrapper.getWrappedInstance();
System.out.println(obj);
}
@Test
public void testBatchCreate() throws ClassNotFoundException {
// 1、批量去加载 BeanDefinition 然后注册到 注册器中
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
int cnt = reader.loadBeanDefinitions("classpath:spring-test.xml");
log.info("加载的BeanDefinition的个数:{}", cnt);
// 2、去遍历每个 beanDefinition
String[] names = registry.getBeanDefinitionNames();
for (String name : names) {
BeanDefinition beanDefinition = registry.getBeanDefinition(name);
String beanClassName = beanDefinition.getBeanClassName();
Class<?> aClass = Class.forName(beanClassName);
// 3、 通过 BeanWrapper 去实例化
BeanWrapper beanWrapper = new BeanWrapperImpl(aClass);
beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());
Object obj = beanWrapper.getWrappedInstance();
System.out.println(obj);
}
使用 XmlBeanDefinitionReader 去得到 BeanDefinition 集然后去遍历就会出现问题:
是说无法将一个 TypedStringValue 类型 转化成 int/Integer,没有合适的转化器。
这是由于去解析 xml 得到的数据是字符串的,直接注入属性值从而导致不匹配。
使用 ClassPathBeanDefinitionScanner
扫描器的话不会有这样的问题,它也不存在属性。
该类可以封装Java类型,提供对超类类型、接口和泛型参数的访问,以及最终解析为类的能力,它能及其方便的简化对反射 api 的调用,在 Spring 的使用率非常高。
ResolvableType 可以从字段、方法参数、方法返回类型或类中获取,这个类上大多方法本身都会返回一个 ResolvableType,以便链式调用。
它提供了 类型、超类类型以及泛型参数,这也是注入所需要的。
private Map<String,Object> map;
private Integer mm;
@Test
public void testResolvableType() throws NoSuchFieldException {
ResolvableType resolvableType = ResolvableType.forField(this.getClass().getDeclaredField("map"));
System.out.println(resolvableType.getType());
// System.out.println(resolvableType.getSuperType());
System.out.println(resolvableType.asMap());
System.out.println(resolvableType.getSource());
System.out.println(resolvableType.getGenerics());
ResolvableType resolvableType1 = ResolvableType.forField(this.getClass().getDeclaredField("mm"));
System.out.println(resolvableType1.getType());
}
就是它能够获取你设的任何类型,是一个获取类型的强大工具。
从 xml 中搜集到的所有数据都是【字符串】,但是实际的类中的成员变量可能是数字,数组,集合,或者复杂的引用数据类型,所以 Spring 给我们提供了强大的转换服务(conversionService接口)
ConversionService
接口很简单,可以根据原类型和目标类型进行判断是否可以进行转换,并执行转换:
public interface ConversionService {
boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
@Nullable
<T> T convert(@Nullable Object source, Class<T> targetType);
// 将给定的{@code source}转换为指定的{@code targetType}。
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConversionService 默认提供了实现:DefaultConversionService
看看DefaultConversationService的源码,更多核心的功能是在父类中实现的,在构造实例的时候,他会默认传入大量可用的转化器(和Mybatis映射类型处理一样,同样是通过类型注册器去管理):
public class DefaultConversionService extends GenericConversionService {
// 这里添加 volatile 关键字,保证了指令的有序性
@Nullable
private static volatile DefaultConversionService sharedInstance;
public DefaultConversionService() {
// 添加大量的默认的转换器
addDefaultConverters(this);
}
// 类似单例的获取方式
// 双重校验实现懒汉式单例
public static ConversionService getSharedInstance() {
DefaultConversionService cs = sharedInstance;
if (cs == null) {
synchronized (DefaultConversionService.class) {
cs = sharedInstance;
if (cs == null) {
cs = new DefaultConversionService();
sharedInstance = cs;
}
}
}
return cs;
}
// 添加适合大多数环境的转换器
public static void addDefaultConverters(ConverterRegistry converterRegistry) {
// 添加简单类型的转换器
addScalarConverters(converterRegistry);
// 添加集合相关的转换器
addCollectionConverters(converterRegistry);
converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToTimeZoneConverter());
converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());
//...还有好多
}
// 增加通用的转换器,例如集合、数组、对象等
public static void addCollectionConverters(ConverterRegistry converterRegistry) {
ConversionService conversionService = (ConversionService) converterRegistry;
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
//...还有好多
}
// 新增标量的转化器,主要是字符串数字类型
private static void addScalarConverters(ConverterRegistry converterRegistry) {
converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToPropertiesConverter());
converterRegistry.addConverter(new PropertiesToStringConverter());
converterRegistry.addConverter(new StringToUUIDConverter());
//...还有好多
}
}
自定义转换器:
// 利用泛型指明转换类型
public class TypeStringValueToBoolean implements Converter<TypedStringValue, Boolean> {
@Override
public Boolean convert(TypedStringValue source) {
return Boolean.valueOf(source.getValue());
}
}
// 通过方法指明类型
public class TypedStringValueToInt implements GenericConverter {
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(TypedStringValue.class, Integer.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return Integer.valueOf(((TypedStringValue) source).getValue());
}
}
测试:
@Test
public void testBatchCreate() throws ClassNotFoundException {
// 1、批量去加载 BeanDefinition 然后注册到 注册器中
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
int cnt = reader.loadBeanDefinitions("classpath:spring-test.xml");
/*ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
int cnt = scanner.scan("com.example.springanalyze.bean");*/
log.info("加载的BeanDefinition的个数:{}", cnt);
// 2、去遍历每个 beanDefinition
String[] names = registry.getBeanDefinitionNames();
for (String name : names) {
BeanDefinition beanDefinition = registry.getBeanDefinition(name);
String beanClassName = beanDefinition.getBeanClassName();
Class<?> aClass = Class.forName(beanClassName);
// 3、 通过 BeanWrapper 去实例化
BeanWrapper beanWrapper = new BeanWrapperImpl(aClass);
DefaultConversionService conversionService = new DefaultConversionService();
// 添加转换器
conversionService.addConverter(new TypedStringValueToInt());
conversionService.addConverter(new TypeStringValueToBoolean());
beanWrapper.setConversionService(conversionService);
beanWrapper.setPropertyValues(beanDefinition.getPropertyValues());
Object obj = beanWrapper.getWrappedInstance();
System.out.println(obj);
}
}
下面是 ConverterFactory
源码(它是一个接口,利用了工厂设计模式,提供的职责是从S类型转换成R类型的工厂):
public interface ConverterFactory<S, R> {
/**
* Get the converter to convert from S to target type T, where T is also an instance of R.
* @param the target type
* @param targetType the target type to convert to
* @return a converter from S to T
*/
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
从
可以看出 R 泛型是转换器目标的上限,也就是说该工厂可以将 S 类型的转换成 R 类型的工厂,转换类型为 R 及其子实现。
如 CharacterToNumberFactory
的实现:
final class CharacterToNumberFactory implements ConverterFactory<Character, Number> {
@Override
public <T extends Number> Converter<Character, T> getConverter(Class<T> targetType) {
return new CharacterToNumber<>(targetType);
}
private static final class CharacterToNumber<T extends Number> implements Converter<Character, T> {
private final Class<T> targetType;
public CharacterToNumber(Class<T> targetType) {
this.targetType = targetType;
}
@Override
public T convert(Character source) {
return NumberUtils.convertNumberToTargetClass((short) source.charValue(), this.targetType);
}
}
}
使用 ConversationService 去添加转换器的时候都会通过以下方法调用:
@Override
public void addConverter(GenericConverter converter) {
this.converters.add(converter);// 将转换器存储到注册器中
invalidateCache();
}
converters 是 Converters 的实例对象,Converters 是 GenericConversationService 的一个静态内部类。 接下来对其源码进行一个分析(所有的 converter 即转换器都存储在 Converters 中):
private static class Converters {
// 存取通用的转换器,并不限定转换类型,一般用于兜底
// 一般不会到这...
private final Set<GenericConverter> globalConverters = new CopyOnWriteArraySet<>();
// 指定了类型对,对应的转换器们的映射关系。
// ConvertiblePair:表示一对,包含sourceType和targetType
// ConvertersForPair:这一对对应的转换器们(因为能处理一对类型转换可能存在多个转换器),内部使用一个双端队列Deque来存储,保证顺序
private final Map<ConvertiblePair, ConvertersForPair> converters = new ConcurrentHashMap<>(256);
public void add(GenericConverter converter) {
// 获得他的类型对儿
Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
if (convertibleTypes == null) {
// 如果没有限定转换类型,添加到globalConverters
this.globalConverters.add(converter);
}
else {
// 如果已经存在转换类型,我们写的都在这里
for (ConvertiblePair convertiblePair : convertibleTypes) {
// 找到与之匹配的加进去,这里是个链表
getMatchableConverters(convertiblePair).add(converter);
}
}
}
@Nullable
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
// 搜索完整的类型层次结构,父类--->
// 比如想要搜索【虎猫 -> 老虎】,但如过虎猫有父类(猫)
// 我们还需检索【猫 -> 老虎】
// 因为有些构造器转换对应类型是支持转换其子类的,比如上面提到的转换器工厂就这样设计的
List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
for (Class<?> sourceCandidate : sourceCandidates) {
for (Class<?> targetCandidate : targetCandidates) {
// 所有的类型都要匹配
ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
// 找到一个就返回
GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
if (converter != null) {
return converter;
}
}
}
return null;
}
@Nullable
private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
TypeDescriptor targetType, ConvertiblePair convertiblePair) {
// 根据convertiblePair获取ConvertersForPair
ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
// 如果对应的 convertersForPair 存在,就去获取对应的转换器
if (convertersForPair != null) {
GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
if (converter != null) {
return converter;
}
}
// 检查是否能匹配兜底的全局转换器
for (GenericConverter globalConverter : this.globalConverters) {
if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
return globalConverter;
}
}
return null;
}
}
ConvertiblePair
:表示一对,包含sourceType和targetType。
final class ConvertiblePair {
private final Class<?> sourceType;
private final Class<?> targetType;
}
ConvertersForPair
:这一对对应的是转换器们(因为能处理一对类型转换可能存在多个转换器),内部使用一个双端队列 Deque
来存储,保证顺序:
他的结构如下:
private static class ConvertersForPair {
// 内部维护的双向队列
private final Deque<GenericConverter> converters = new ConcurrentLinkedDeque<>();
public void add(GenericConverter converter) {
this.converters.addFirst(converter);
}
@Nullable
public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
// 此处的判断条件说明:
// 如果这个转换器实现了 ConditionalGenericConverter.match() 方法,就必须匹配成功;
// 如果没有实现这个 ConditionalGenericConverter 接口
// 此处表明,如果我们有特殊的需求,可以实现 ConditionalGenericConverter,实现特殊的匹配规则
// 不同的converter可以对应不同的匹配规则,这也是去匹配一个类型转换对应着多个转换器
for (GenericConverter converter : this.converters) {
if (!(converter instanceof ConditionalGenericConverter genericConverter) ||
genericConverter.matches(sourceType, targetType)) {
return converter;
}
}
return null;
}
@Override
public String toString() {
return StringUtils.collectionToCommaDelimitedString(this.converters);
}
}
其中添加转换器有三个重载方法:
// 这个方法支持泛型,可以指定转换器由什么类型转换成什么类型
// 然后构造成ConverterAdapter适配器进行添加进注册器中
// 其中这个 ConverterAdapter 适配器实现了 ConditionalGenericConverter
// 也就是实现了 match、convert、getConvertibleTypes方法
// 最后匹配这个转换器是根据 match 去走的。
@Override
public void addConverter(Converter<?, ?> converter) {
ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);
if (typeInfo == null && converter instanceof DecoratingProxy decoratingProxy) {
typeInfo = getRequiredTypeInfo(decoratingProxy.getDecoratedClass(), Converter.class);
}
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to determine source type and target type for your " +
"Converter [" + converter.getClass().getName() + "]; does the class parameterize those types?");
}
addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
}
// 这是添加有下线和上线的类型转换器
// 最后构造一个ConverterAdapter适配器去添加进注册器中
@Override
public <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter) {
addConverter(new ConverterAdapter(
converter, ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));
}
// 这个方法是核心,最后都是通过这个方法添加进conversations注册器中
@Override
public void addConverter(GenericConverter converter) {
this.converters.add(converter);
invalidateCache();
}
所以我们去实现自己的转换器,去实现 ConditionalGenericConverter
就可以了,当然不需要匹配规则的话,也可以直接去实现 GenericConverter
接口即可。
举个例子,假设我们有一个应用程序中的实体类 Person,它有属性 name 和 age。现在我们需要将 Person 对象转换成 DTO(Data Transfer Object)对象,以便在网络传输过程或持久化过程中使用。在转换过程中,我们可能会有以下几种转换方式:
- 通过直接复制相同属性名的方式进行转换,即将 Person 对象的 name 属性复制到 DTO 对象的 name 属性,将 age 属性复制到 DTO 对象的 age 属性;
- 通过自定义的转换逻辑进行转换,例如将 Person 对象的 age 属性按照一定的规则转换为 DTO 对象的 ageInfo 属性,表示年龄信息’’
- 通过调用其他服务接口或接口进行转换,例如根据 Person 对象的 name 属性查询其他系统获取到的 DTO 对象。
针对不同的转换方式,我们可以分别编写对应的转换器。在Spring 中,可以通过 ConvertiblePair 对象来表示源类型和目标类型的配对,ConvertersForPair 对象则是一个包含多个转换器的集合。为了匹配对应的转换器,我们可以去实现
ConditionalGenericConverter
接口去实现自己的转换器。
有人可能会关心存储在 Map 中,那不同的 ConvertiblePair
hash 一样导致 hash 冲突的话,不就引起了不同的类型转换用错了转换器吗?
其实在 ConvertiblePair 中重写了 equals 方法,其中最关键的代码如下(即在匹配的过程中会对源类型和目标类型进行 ==
判断):
return (this.sourceType == otherPair.sourceType && this.targetType == otherPair.targetType);
Spring 中有多种转换机制,其中主要包括类型转换器(
Converter
)和 HTTP 消息转换器(HTTPMessageConverter
)。
这里说的类加载器主要用于应用程序内部进行类型转换,例如将一个 Java 对象转换为另一个 Java 对象或基本数据类型的转换。它负责处理方法参数和返回值的类型转化,以及数据绑定等场景。
而 HTTP 消息转换器主要用于处理 Web 请求和响应的消息转换,例如将 Java 对象转换为 JSON 或 XML 格式的数据,以便于网络传输和处理。
Spring 的【org.springframework.core.io.Resource】抽象了对资源的访问的能力。下面提供了【Resource】接口的概述,Spring 本身广泛地使用了 Resource
接口。
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
boolean isFile();
URL getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
ReadableByteChannel readableChannel() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
Spring 包含了几个内置的 Resource 实现,如下所示:
UrlResource
:UrlResource 包装了 java.net.URL,可以用来访问任何需要通过 URL 访问的对象,例如文件、HTTPS目标、FTP目标等。所有URL都用一个标准化的字符串表示,这样就可以使用适当的标准化前缀来表示不同类型的URL。这包括用于访问文件系统的 file:
,用于通过https协议访问资源的 https:
,用于通过 ftp 访问资源的 ftp:
等。
ClassPathResource
:该类表示应该从【类路径】中获取的资源。它使用线程上下文类装入器、给定的类装入器或给定的类装入资源。
FileSystemResource:这是面向java.io的Resource实现,可以简单的实现对系统文件的操作。
InputStreamResource:给定的InputStream的Resource实现。 只有当没有特定的资源实现适用时,才应该使用它。
ByteArrayResource:这是一个给定字节数组的资源实现。
@Test
public void testClassPathResource() throws IOException {
Resource test = new ClassPathResource("spring-test.xml");
InputStream inputStream = test.getInputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
}
下面是它的结构图:
它提供了 getResource
、getResources
方法给我们使用。
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
// 留给我们的扩展的协议解析器,如自定义
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
if (location.startsWith("/")) {
return getResourceByPath(location);
}
// classpath:
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
} else {
try {
// 尝试将位置解析为URL…
URL url = ResourceUtils.toURL(location);
// 检测是不是file: vfsfile:打头的
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
}
}
// 一般是用于 classpath* 前缀的
@Override
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
// a class path resource (multiple resources for same name possible)
String locationPatternWithoutPrefix = locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length());
// Search the module path first.
Set<Resource> resources = findAllModulePathResources(locationPatternWithoutPrefix);
if (getPathMatcher().isPattern(locationPatternWithoutPrefix)) {
// a class path resource pattern
Collections.addAll(resources, findPathMatchingResources(locationPattern));
}
else {
// all class path resources with the given name
Collections.addAll(resources, findAllClassPathResources(locationPatternWithoutPrefix));
}
return resources.toArray(new Resource[0]);
}
else {
// Generally only look for a pattern after a prefix here,
// and on Tomcat only after the "*/" separator for its "war:" protocol.
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// a file pattern
return findPathMatchingResources(locationPattern);
}
else {
// a single resource with the given name
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}
测试:
@Test
public void testResolver() throws IOException {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:/META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource.getURI());
}
}
输出:
jar:file:/D:/Study/java/maven_work/maven_repositoryo/org/springframework/boot/spring-boot/3.0.1/spring-boot-3.0.1.jar!/META-INF/spring.factories
jar:file:/D:/Study/java/maven_work/maven_repositoryo/org/springframework/boot/spring-boot-autoconfigure/3.0.1/spring-boot-autoconfigure-3.0.1.jar!/META-INF/spring.factories
jar:file:/D:/Study/java/maven_work/maven_repositoryo/org/springframework/spring-aop/6.0.3/spring-aop-6.0.3.jar!/META-INF/spring.factories
jar:file:/D:/Study/java/maven_work/maven_repositoryo/org/springframework/boot/spring-boot-test/3.0.1/spring-boot-test-3.0.1.jar!/META-INF/spring.factories
jar:file:/D:/Study/java/maven_work/maven_repositoryo/org/springframework/boot/spring-boot-test-autoconfigure/3.0.1/spring-boot-test-autoconfigure-3.0.1.jar!/META-INF/spring.factories
jar:file:/D:/Study/java/maven_work/maven_repositoryo/org/springframework/spring-test/6.0.3/spring-test-6.0.3.jar!/META-INF/spring.factories
Spring 提供了 Event Multicaster,可以十分简单地实现发布订阅模式(观察者模式)。
Multicast:组播,多播;
这个多播器呢可以发布事件,事件会被对应的监听器监听,若事件被发布了,当然就会触发监听者执行相应的操作。Spring默认有个 SimpleApplicationEventMulticaster
多播器。
简单地测试使用如下:
@Test
void testEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster = new
SimpleApplicationEventMulticaster();
eventMulticaster.addApplicationListener(new EmailListener());
eventMulticaster.addApplicationListener(new MessageListener());
eventMulticaster.addApplicationListener(new EmailListener());
// 使用多播器发送事件
eventMulticaster.multicastEvent(new OrderEvent(this));
}
自定义事件可以去继承 ApplicationEvent
类,自定义监听器可以去实现 ApplicationListener
.实现如下:
public class MessageListener implements ApplicationListener<OrderEvent>
public class OrderEvent extends ApplicationEvent
但是实际使用都是通过 bean 进行注入的,ApplicationContext 中的事件处理是通过 ApplicationEvent 类和 ApplicationListener 接口提供的。如果将实现的 ApplicationListener 接口中的 bean 部署到了容器中,则每次将 ApplicationEvent 发布到 ApplicationContext 时,都会通知到该 bean,这是典型的观察者模式。
通过上面的 UML 图,咱可以有个大概的理解:
@EventListener
监听时间;Spring 默认注入的多播器是 SimpleApplicationEventMulticaster,也就是说如果你不自定义 Publisher 发布事件的话,默认就是通过多播器帮你发了:
一般情况下监听器都是通过bean注入的方式进去的,那bean的话又分为多例prototype,单利singleton。看看下图它是如何管理的:
当listener被调用执行后,如何进行了缓存:
当listener被调用执行后,如果是单例的,会被缓存到 RetrieverCache
中,其中key 是 eventtype 和 sourcetype 的封装,value 是对应的 listeners,当然一个事件可能对应多个监听嘛!当一个事件触发后,是先去从缓存中查找有无对应的事件监听,无的话再遍历查找。
SimpleApplicationEventMulticaster 源码如下:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 定义一个线程池,事件被触发时可由他来实现事件,默认为null
private Executor taskExecutor;
// 这个用来捕获listener执行过程中产生的异常
// 需要这用 赋值caster.setErrorHandler(new XxxErrorHandler())
private ErrorHandler errorHandler;
private volatile Log lazyLogger;
public SimpleApplicationEventMulticaster() {}
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
@Nullable
protected ErrorHandler getErrorHandler() {
return this.errorHandler;
}
//设置一个自定义执行器(线程池)来调用每个侦听器。
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
@Nullable
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
// 广播一个事件
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
// 广播一个事件的具体实现
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 核心一:getApplicationListeners(event, type)稍后看
// 他的重点是如何设计的缓存
// 获取所有与event事件匹配的listener并调用核心方法onApplicationEvent
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 如果你设置了线程池他会将任务丢给线程池
if (executor != null) {
// 核心二:调用Listener的方法invokeListener
executor.execute(() -> invokeListener(listener, event));
}
// 否则就以单线程的方式运行
else {
invokeListener(listener, event);
}
}
}
// 调用listener的方法
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
// ErrorHandler可以保存Listener在执行过程中产生的异常
// 其默认为null,我们可以独立设置
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
// 将执行listener时产生放入errorHandler
errorHandler.handleError(err);
}
}
else {
// 负责直接调用
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用方法
listener.onApplicationEvent(event);
}
// 捕获类型转化异常
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent && matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass())) ) {
// 可能是lambda定义的侦听器,我们无法为其解析泛型事件类型
// 让我们抑制异常。
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
} else {
throw ex;
}
}
}
private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
// 在Java 8上,消息以类名“Java .lang”开始。字符串不能强制转换…
if (classCastMessage.startsWith(eventClass.getName())) {
return true;
}
// 在Java 11中,消息以“class…”开头,也就是class . tostring ()
if (classCastMessage.startsWith(eventClass.toString())) {
return true;
}
// 在Java 9上,用于包含模块名称的消息:" Java .base/ Java .lang. lang. xml "。字符串不能强制转换…”
int moduleSeparatorIndex = classCastMessage.indexOf('/');
if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
return true;
}
// 假设一个不相关的类转换失败……
return false;
}
}
父类 AbstractApplicationEventMulticaster 源码分析:
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
// 真正保存listener的地方,他保存了传入的listener实例和容器里的监听器bean的名字
// 其结构如图1
private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();
// 这个集合是对已调用的event和listener的缓存
// ListenerCacheKey保存了一组event和source
// CachedListenerRetriever保存了已注册的、容器的单例bean、容器的非单例beanName
// 非单例的bean只能缓存name,实例会消亡
final Map<ListenerCacheKey, Cached Retriever> retrieverCache = new ConcurrentHashMap<>(64);
@Nullable
private ClassLoader beanClassLoader;
@Nullable
private ConfigurableBeanFactory beanFactory;
// 以编程的方式添加监听器
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
// 这个过程可能存在线程安全的问题,比如一线线程
synchronized (this.defaultRetriever) {
// 因为你的Aop可能影响到该listener
// 我们需要将代理对象从defaultRetriever中删除,因为我们并不需要
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
// 添加原生的监听器到defaultRetriever
this.defaultRetriever.applicationListeners.add(listener);
// 清理缓存
this.retrieverCache.clear();
}
}
// 直接以bean的方式将listenerBeanName添加到defaultRetriever
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
// 清理缓存
this.retrieverCache.clear();
}
}
// 获得所有的bean的实例
// 第一部分:编程式的bean的实例
// 第二部分:容器的bean,进行实例化
protected Collection<ApplicationListener<?>> getApplicationListeners() {
synchronized (this.defaultRetriever) {
return this.defaultRetriever.getApplicationListeners();
}
}
// ...省略掉大量雷同的crud(增删查改)代码
// 我们看一个比较有难度的方法,该方法根据事件获取满足条件的listeners
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
// 获得事件源(那个类中发布的时间(如OrderService类发布是orderEvent))
// source就是OrderService,event就是orderEvent
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
// 通过事件类型和源类型创建缓存key
// 第二次请求就避免了再次检索
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 定义新的Listener缓存器,他是作为retrieverCache的value
CachedListenerRetriever newRetriever = null;
// 核心:快速检查缓存中的内容
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
if (existingRetriever == null) {
// 满足条件,则在existingRetriever缓存一个新的条目
// key->ListenerCacheKey(eventType和sourceType)
// value->CachedListenerRetriever(保存了与key匹配的listeners)
if (this.beanClassLoader == null ||(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// 创建一个新的缓存器,目前里边为空
newRetriever = new CachedListenerRetriever();
// 将这个key和检索器放入整体缓存map中
existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
// 添加失败,则将newRetriever置空
// 多线程下可能会添加失败,两个线程同时添加,只能有一个成功
if (existingRetriever != null) {
// 将new的缓存器置空,复用其他线程创建的
newRetriever = null;
}
}
}
// 如果缓存命中(缓存中存在这一对key-value)
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
// 将缓存中的Listeners全部取出,返回
if (result != null) {
return result;
}
// 缓存命中没有拿到结果,此时result为null
// 这种一般出现在多线程情况,有一个线程已经创建了这个缓存器,但是还没有机会赋值
// 当前线程又拿到了这个缓存器,那我们就继续
}
// 该方法会为我们当前根据key过滤合适的listeners,并缓存器赋值
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
// 该方法会给传入的newRetriever赋值,检索过程相对复杂
// 这个方法会过滤满足条件的Listeners,并将过滤后的内容放到缓存中
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
// 保存所有过滤好的listeners
// 他包含编程式的实例和容器的bean
List<ApplicationListener<?>> allListeners = new ArrayList<>();
// 过滤后的监听器,将来做缓存用
Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
// 过滤后的监听器beanName,将来做缓存用
Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
// 每个线程拷贝独立的listeners和listenerBeans
synchronized (this.defaultRetriever) {
// 优先做一个拷贝
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// 将所有的listener实例遍历,过滤满足条件的
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
// 如果传递了缓存器,就将它存入filteredListeners
if (retriever != null) {
filteredListeners.add(listener);
}
allListeners.add(listener);
}
}
// bean要在这里获取初始化
if (!listenerBeans.isEmpty()) {
// 这里初始化
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
// 判断beanFactory是不是支持该事件
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
// 从bean工厂获取,实例化bean
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName,ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
// 如果是单例的就加入filteredListeners
if (beanFactory.isSingleton(listenerBeanName)) {
filteredListeners.add(listener);
}
// 如果不是单例bean,则加入filteredListenerBeans
// 原因是非单例bean使用结束可能会被gc,下次使用需要重新实例化
// 所以,我们并不缓存非单例的listenerbean
else {
filteredListenerBeans.add(listenerBeanName);
}
}
// 无论是不是单例,都将实例加入allListeners,
// 他将作为当前方法的返回值
allListeners.add(listener);
}
}
else {
// 删除不匹配的侦听器
// ApplicationListenerDetector,可能被额外的排除
// BeanDefinition元数据(例如工厂方法泛型)
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
filteredListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
// 给结果排序
AnnotationAwareOrderComparator.sort(allListeners);
// 实际进行缓存的地方
// 在这里我们缓存了applicationListeners(编程式的和单例的bean)
// 和applicationListenerBeans,主要是非单例bean的名字
// 下次从缓存获取的时候还是会再次实例化非单例的bean
if (retriever != null) {
// 如果啥也没有过滤则添加全部的Listeners和ListenerBeans到retriever
if (filteredListenerBeans.isEmpty()) {
retriever.applicationListeners = new LinkedHashSet<>(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
}
else {
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
return allListeners;
}
}
key:ListenerCacheKey的实现:
private static final class ListenerCacheKey implements Comparable<ListenerCacheKey> {
// 一个ListenerCacheKey包含了eventType和sourceType
// eventType事件类型 | sourceType发布事件的类的类型、
// 谁发布了这个事件
private final ResolvableType eventType;
private final Class<?> sourceType;
public ListenerCacheKey(ResolvableType eventType, @Nullable Class<?> sourceType) {
Assert.notNull(eventType, "Event type must not be null");
this.eventType = eventType;
this.sourceType = sourceType;
}
//...省略
}
value:CachedListenerRetriever的实现:
//listener缓存工具类,它封装了一组特定的目标侦听器,允许高效检索预先过滤的侦听器。每个事件类型和源类型缓存这个helper的实例。
private class CachedListenerRetriever {
// 保存了满足条件的applicationListeners
// 包含编程式的和容器内满足条件的单例bean
@Nullable
public volatile Set<ApplicationListener<?>> applicationListeners;
// 保存了满足条件的非单例的applicationListenerBeans
@Nullable
public volatile Set<String> applicationListenerBeans;
// 该方法是从特定缓存获取applicationListeners
// 这个方法会再次实例化非单例的bean
@Nullable
public Collection<ApplicationListener<?>> getApplicationListeners() {
Set<ApplicationListener<?>> applicationListeners = this.applicationListeners;
Set<String> applicationListenerBeans = this.applicationListenerBeans;
if (applicationListeners == null || applicationListenerBeans == null) {
// Not fully populated yet
return null;
}
// 创建一个临时的集合保存所有的监听器
List<ApplicationListener<?>> allListeners = new ArrayList<>(
applicationListeners.size() + applicationListenerBeans.size());
allListeners.addAll(applicationListeners);
// 这里实例化剩下的bean,容器内的非单例bean
// 这里不一样的地方是非单单例的bean,每次清除缓存都要重新实例化
if (!applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : applicationListenerBeans) {
try {
allListeners.add(beanFactory.getBean(listenerBeanName, ApplicationListener.class));
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
// 对他进行重排序
if (!applicationListenerBeans.isEmpty()) {
AnnotationAwareOrderComparator.sort(allListeners);
}
return allListeners;
}
}
默认的listener的存储器:
private class DefaultListenerRetriever {
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
public Collection<ApplicationListener<?>> getApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<>(
this.applicationListeners.size() + this.applicationListenerBeans.size());
allListeners.addAll(this.applicationListeners);
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans) {
try {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener)) {
allListeners.add(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// 单例侦听器实例(没有支持bean定义)消失,可能在销毁阶段的中间
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
}