当前位置: 首页 > news >正文

做网站月收入多少房地产招新人的坑

做网站月收入多少,房地产招新人的坑,网站定制哪个好,网站闪图怎么做的Bean的元数据和一些Spring工具 一、BeanDefinition1、认识 BeanDifinition2、AbstractBeanDefinition3、GenericBeanDefinition测试 二、BeanDefinition 注册器三、加载BeanDefinition四、包扫描过程分析包扫描过程总结 五、内省 API六、反射工具Bean 的创建批量构造Resolvable… Bean的元数据和一些Spring工具 一、BeanDefinition1、认识 BeanDifinition2、AbstractBeanDefinition3、GenericBeanDefinition测试 二、BeanDefinition 注册器三、加载BeanDefinition四、包扫描过程分析包扫描过程总结 五、内省 API六、反射工具Bean 的创建批量构造ResolvableType 七、类型转换1、转换服务2、自定义转换器3、转换器工厂ConverterFactory4、转换器注册器源码为什么一个类型转换成另一个类型还需要多种转换器存储在 Map 中的 Hash 问题 5、注意是类型转换器 八、资源获取1、内置的 Resource 的实现2、classpath 前缀3、PathMatchingResourcePatternResolver 九、Spring EventSimpleApplicationEventMulticaster源码分析 参考文献 Spring源码-基础 一、BeanDefinition BeanDefinition 为我们统一了 bean 的元数据bean 的元数据就是指我们使用 xml 或者注解进行配置的数据我们的 spring 容器启动之前的第一步就是加载配置数据这些元数据会被加载到内存中以一个个 beanDefinition 的形式保存在一个 map 中。 一个 BeanDifinition 大概保存了以下信息 定义了 id、别名与Bean的队友关系BeanDefinitionHolder具体的工厂方法Class 类型包括工厂方法的返回类型工厂方法的 Method 对象。构造函数、构造函数形参类型Bean 的 class 对象作用范围、是否懒加载等等 结构图如下 beanDefinition来源不同可能会有不同实现目前我们最常用的实现就是GenericBeanDefinition这个实现类。 小知识Generic一般的通用的几乎所有以这个单词打头的实现都是spring的通用实现。 1、认识 BeanDifinition public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {// 常量标志一个bean的作用范围String SCOPE_SINGLETON ConfigurableBeanFactory.SCOPE_SINGLETON;String SCOPE_PROTOTYPE ConfigurableBeanFactory.SCOPE_PROTOTYPE;// 设置父BeanDefinition可以只对有父子关系的beanvoid 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();// 设置是否主要beanvoid 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(); } 2、AbstractBeanDefinition 该类对通用核心方法完成了实现这也是抽象类的作用同时对一些成员变量提供了默认值 public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessorimplements 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_DEFAULTprivate 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) {}// ...此处省略其他的方法实现 } 3、GenericBeanDefinition 该类实现比较简单提供了设置父子关系和构建实例的方法该类及其子类是目前版本使用最多的BeanDifinition。 ublic class GenericBeanDefinition extends AbstractBeanDefinition {Nullableprivate String parentName;public GenericBeanDefinition() {super();}// 通过深拷贝创建一个beanpublic GenericBeanDefinition(BeanDefinition original) {super(original);}Overridepublic void setParentName(Nullable String parentName) {this.parentName parentName;}OverrideNullablepublic String getParentName() {return this.parentName;}Overridepublic AbstractBeanDefinition cloneBeanDefinition() {return new GenericBeanDefinition(this);} }测试 Testpublic 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的创建需要依赖父DefinitionChildBeanDefinition 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很强大也可以很轻松的独立的构建父子关系。 二、BeanDefinition 注册器 有了统一标准的元数据之后我们就可以统一管理这就需要一个容器去存储当然我们可以使用 map 这样的集合类当然 spring 差不多就是这样做的。他为我们提供了一个接口 BeanDefinitionRegistry。只要实现了这个接口就会拥有注册 beanDefinition 的能力。 就好像 mybatis 中类型的别名TypeAilasRegistry和类型处理TypeHandleRegistry一样需要注册器进行全局注册 接口代码如下 public interface BeanDefinitionRegistry extends AliasRegistry {// 注册一个BeanDefinitionvoid 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/4196 的时候进行第一次扩容。 Testpublic 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的创建需要依赖父DefinitionChildBeanDefinition teddy new ChildBeanDefinition(dog);teddy.setBeanClassName(com.ydlclass.TeddyDog);BeanMetadataAttribute name new BeanMetadataAttribute(name, doudou);teddy.addMetadataAttribute(name);registry.registerBeanDefinition(teddy, teddy);}三、加载BeanDefinition 当然我们不可能为每一个类手动去编写与之对应的 BeanDefinition元数据还是要从xml或者从配置类中获取的spring 为我们提供了对应的工具。对比 Mybatis 也是一样的从mybatis核心配置xml里去得到你需要扫描的别名和类型处理器当然类型处理器它自己内置了如果自己自定义了的需要自己配置然后让它加载。 1、 读取 xml 配置文件 该类通过解析 xml 完成 BeanDefinition 的读取并且将它解析的 BeanDefinition 注册倒一个注册器中 Testpublic void testRegistryByXml() {BeanDefinitionRegistry registry new SimpleBeanDefinitionRegistry();// 创建一个 xml 的 readerXmlBeanDefinitionReader reader new XmlBeanDefinitionReader(registry);reader.loadBeanDefinitions(classpath:spring-test.xml);System.out.println(registry);}2、加载带注解的 bean Testpublic void testRegistryByXml() {BeanDefinitionRegistry registry new SimpleBeanDefinitionRegistry();// 创建一个 xml 的 readerXmlBeanDefinitionReader 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、类路径扫描 Testpublic void testRegistryByScanner(){BeanDefinitionRegistry registry new SimpleBeanDefinitionRegistry();// 通过扫描包的方式去注册 BeanDefinitionClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(registry);scanner.scan(com.example.springanalyze.bean);System.out.println(registry);}四、包扫描过程分析 无论是扫包还是其他方式我们解析一个类无非有以下俩种方式 加载一个类倒内存获取 Class 对象通过反射获取到元数据直接操纵字节码文件.class读取字节码内的元数据。 毫无疑问 spring 选择了第二种使用 ASM 技术 首先第二种性能要优于第一种 其次第一种会将扫描的类全部加载到堆内存无疑会浪费空间增加 gc 次数第二种可以根据元数据按需加载。 doScan 核心代码分析 protected SetBeanDefinitionHolder doScan(String... basePackages) {// BeanDefinitionHolder持有 BeanDefinition实例和名字以及别名SetBeanDefinitionHolder beanDefinitions new LinkedHashSet();for (String basePackage : basePackages) {// 这里是具体的扫描过程找出全部符合过滤器要求的BeanDefinition// 返回的BeanDefinition的实际类型为ScannedGenericBeanDefinition// 实际是调用scanCandidateComponents方法SetBeanDefinition candidates findCandidateComponents(basePackage);// 根据不同的bean类型做统一处理如附默认值等// 因为有些数据我们并没有配置需要这里做默认处理for (BeanDefinition candidate : candidates) {// 如果存在则解析Scope注解为候选bean设置代理的方式ScopedProxyModeXML属性也能配置scope-resolver、scoped-proxy可以指定代理方式jdk或者cglibScopeMetadata 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支持成为自动注入候选beanif (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}// 如果bean定义是AnnotatedBeanDefinition类型ScannedGenericBeanDefinition同样属于AnnotatedBeanDefinition类型if (candidate instanceof AnnotatedBeanDefinition) {// 4 处理类上的其他通用注解Lazy, Primary, DependsOn, Role, DescriptionAnnotationConfigUtils.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 SetBeanDefinition scanCandidateComponents(String basePackage) {// 用 Set 去封装 BeanDefinition 进行返回SetBeanDefinition candidates new LinkedHashSet();try {// 去解析出报名然后拼接成包的解析路径如classpath*:com.test/**/*.classString 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)) {// 如果成功的话就把元数据封装成 ScannerGenericBeanDefinitionScannedGenericBeanDefinition 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 {Overridepublic 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 是否重复 放入集合返回然后处理默认值等。 五、内省 API 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 对象去获取对应的信息 Testpublic 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 提供了一系列静态方法用于复制、合并、获取、设置对象的属性值等操作。 Testpublic 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(namenull, age11) // Person(namenull, age11)六、反射工具 Spring 和 Mybatis 一样提供了自定封装的反射工具针对原生 API 的复杂性Spring同样进行了封装让其使用起来更简单。 Bean 的创建 这个Spring提供的反射工具是 BeanWrapper下面的例子展示了该类与 BeanDefinition 的配合使用 Testpublic 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);}批量构造 Testpublic 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、去遍历每个 beanDefinitionString[] 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 扫描器的话不会有这样的问题它也不存在属性。 ResolvableType 该类可以封装Java类型提供对超类类型、接口和泛型参数的访问以及最终解析为类的能力它能及其方便的简化对反射 api 的调用在 Spring 的使用率非常高。 ResolvableType 可以从字段、方法参数、方法返回类型或类中获取这个类上大多方法本身都会返回一个 ResolvableType以便链式调用。 它提供了 类型、超类类型以及泛型参数这也是注入所需要的。 private MapString,Object map;private Integer mm;Testpublic 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接口 1、转换服务 ConversionService 接口很简单可以根据原类型和目标类型进行判断是否可以进行转换并执行转换 public interface ConversionService {boolean canConvert(Nullable Class? sourceType, Class? targetType);boolean canConvert(Nullable TypeDescriptor sourceType, TypeDescriptor targetType);NullableT T convert(Nullable Object source, ClassT 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 关键字保证了指令的有序性Nullableprivate 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());//...还有好多}} 2、自定义转换器 自定义转换器 // 利用泛型指明转换类型 public class TypeStringValueToBoolean implements ConverterTypedStringValue, Boolean {Overridepublic Boolean convert(TypedStringValue source) {return Boolean.valueOf(source.getValue());} } // 通过方法指明类型 public class TypedStringValueToInt implements GenericConverter {Overridepublic SetConvertiblePair getConvertibleTypes() {return Collections.singleton(new ConvertiblePair(TypedStringValue.class, Integer.class));}Overridepublic Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {return Integer.valueOf(((TypedStringValue) source).getValue());} }测试 Testpublic 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、去遍历每个 beanDefinitionString[] 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);}}3、转换器工厂ConverterFactory 下面是 ConverterFactory 源码它是一个接口利用了工厂设计模式提供的职责是从S类型转换成R类型的工厂 public interface ConverterFactoryS, R {/*** Get the converter to convert from S to target type T, where T is also an instance of R.* param T the target type* param targetType the target type to convert to* return a converter from S to T*/T extends R ConverterS, T getConverter(ClassT targetType);}从 T extends R 可以看出 R 泛型是转换器目标的上限也就是说该工厂可以将 S 类型的转换成 R 类型的工厂转换类型为 R 及其子实现。 如 CharacterToNumberFactory 的实现 final class CharacterToNumberFactory implements ConverterFactoryCharacter, Number {Overridepublic T extends Number ConverterCharacter, T getConverter(ClassT targetType) {return new CharacterToNumber(targetType);}private static final class CharacterToNumberT extends Number implements ConverterCharacter, T {private final ClassT targetType;public CharacterToNumber(ClassT targetType) {this.targetType targetType;}Overridepublic T convert(Character source) {return NumberUtils.convertNumberToTargetClass((short) source.charValue(), this.targetType);}}}4、转换器注册器源码 使用 ConversationService 去添加转换器的时候都会通过以下方法调用 Overridepublic void addConverter(GenericConverter converter) {this.converters.add(converter);// 将转换器存储到注册器中invalidateCache();}converters 是 Converters 的实例对象Converters 是 GenericConversationService 的一个静态内部类。 接下来对其源码进行一个分析所有的 converter 即转换器都存储在 Converters 中 private static class Converters {// 存取通用的转换器并不限定转换类型一般用于兜底// 一般不会到这...private final SetGenericConverter globalConverters new CopyOnWriteArraySet();// 指定了类型对对应的转换器们的映射关系。// ConvertiblePair表示一对包含sourceType和targetType// ConvertersForPair这一对对应的转换器们因为能处理一对类型转换可能存在多个转换器内部使用一个双端队列Deque来存储保证顺序private final MapConvertiblePair, ConvertersForPair converters new ConcurrentHashMap(256);public void add(GenericConverter converter) {// 获得他的类型对儿SetConvertiblePair convertibleTypes converter.getConvertibleTypes();if (convertibleTypes null) {// 如果没有限定转换类型添加到globalConvertersthis.globalConverters.add(converter);}else {// 如果已经存在转换类型我们写的都在这里for (ConvertiblePair convertiblePair : convertibleTypes) {// 找到与之匹配的加进去这里是个链表getMatchableConverters(convertiblePair).add(converter);}}}Nullablepublic GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {// 搜索完整的类型层次结构父类---// 比如想要搜索【虎猫 - 老虎】但如过虎猫有父类猫// 我们还需检索【猫 - 老虎】// 因为有些构造器转换对应类型是支持转换其子类的比如上面提到的转换器工厂就这样设计的ListClass? sourceCandidates getClassHierarchy(sourceType.getType());ListClass? 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;}Nullableprivate GenericConverter getRegisteredConverter(TypeDescriptor sourceType, TypeDescriptor targetType, ConvertiblePair convertiblePair) {// 根据convertiblePair获取ConvertersForPairConvertersForPair 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 DequeGenericConverter converters new ConcurrentLinkedDeque();public void add(GenericConverter converter) {this.converters.addFirst(converter);}Nullablepublic 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;}Overridepublic String toString() {return StringUtils.collectionToCommaDelimitedString(this.converters);}}其中添加转换器有三个重载方法 // 这个方法支持泛型可以指定转换器由什么类型转换成什么类型// 然后构造成ConverterAdapter适配器进行添加进注册器中// 其中这个 ConverterAdapter 适配器实现了 ConditionalGenericConverter// 也就是实现了 match、convert、getConvertibleTypes方法// 最后匹配这个转换器是根据 match 去走的。Overridepublic 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 S and target type T for your Converter [ converter.getClass().getName() ]; does the class parameterize those types?);}addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));}// 这是添加有下线和上线的类型转换器// 最后构造一个ConverterAdapter适配器去添加进注册器中Overridepublic S, T void addConverter(ClassS sourceType, ClassT targetType, Converter? super S, ? extends T converter) {addConverter(new ConverterAdapter(converter, ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));}// 这个方法是核心最后都是通过这个方法添加进conversations注册器中Overridepublic void addConverter(GenericConverter converter) {this.converters.add(converter);invalidateCache();}所以我们去实现自己的转换器去实现 ConditionalGenericConverter 就可以了当然不需要匹配规则的话也可以直接去实现 GenericConverter 接口即可。 为什么一个类型转换成另一个类型还需要多种转换器 举个例子假设我们有一个应用程序中的实体类 Person它有属性 name 和 age。现在我们需要将 Person 对象转换成 DTOData Transfer Object对象以便在网络传输过程或持久化过程中使用。在转换过程中我们可能会有以下几种转换方式 通过直接复制相同属性名的方式进行转换即将 Person 对象的 name 属性复制到 DTO 对象的 name 属性将 age 属性复制到 DTO 对象的 age 属性通过自定义的转换逻辑进行转换例如将 Person 对象的 age 属性按照一定的规则转换为 DTO 对象的 ageInfo 属性表示年龄信息’’通过调用其他服务接口或接口进行转换例如根据 Person 对象的 name 属性查询其他系统获取到的 DTO 对象。 针对不同的转换方式我们可以分别编写对应的转换器。在Spring 中可以通过 ConvertiblePair 对象来表示源类型和目标类型的配对ConvertersForPair 对象则是一个包含多个转换器的集合。为了匹配对应的转换器我们可以去实现 ConditionalGenericConverter 接口去实现自己的转换器。 存储在 Map 中的 Hash 问题 有人可能会关心存储在 Map 中那不同的 ConvertiblePair hash 一样导致 hash 冲突的话不就引起了不同的类型转换用错了转换器吗 其实在 ConvertiblePair 中重写了 equals 方法其中最关键的代码如下即在匹配的过程中会对源类型和目标类型进行 判断 return (this.sourceType otherPair.sourceType this.targetType otherPair.targetType);5、注意是类型转换器 Spring 中有多种转换机制其中主要包括类型转换器Converter和 HTTP 消息转换器HTTPMessageConverter。 这里说的类加载器主要用于应用程序内部进行类型转换例如将一个 Java 对象转换为另一个 Java 对象或基本数据类型的转换。它负责处理方法参数和返回值的类型转化以及数据绑定等场景。 而 HTTP 消息转换器主要用于处理 Web 请求和响应的消息转换例如将 Java 对象转换为 JSON 或 XML 格式的数据以便于网络传输和处理。 在 Spring 中类型转换器主要由内置的 ConversionService 接口和实现类 DefaultConversionService 来管理将转换器注册到 Converters 中使用 MapConvertiblePair,ConvertersForPair converters 这样的数据结构来存储转换对应的多个转换器HttpMessageConverter 主要由内置的 HttpMessageConverter 接口和各种实现类来管理。它负责处理请求和响应的消息转换如将 Java 对象转换为 JSON 或 XML 格式的数据以及将 JSON 或 XML 格式数据转换成为 Java 对象。 八、资源获取 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(); }1、内置的 Resource 的实现 Spring 包含了几个内置的 Resource 实现如下所示 UrlResourceUrlResource 包装了 java.net.URL可以用来访问任何需要通过 URL 访问的对象例如文件、HTTPS目标、FTP目标等。所有URL都用一个标准化的字符串表示这样就可以使用适当的标准化前缀来表示不同类型的URL。这包括用于访问文件系统的 file: 用于通过https协议访问资源的 https: 用于通过 ftp 访问资源的 ftp: 等。 ClassPathResource该类表示应该从【类路径】中获取的资源。它使用线程上下文类装入器、给定的类装入器或给定的类装入资源。 FileSystemResource这是面向java.io的Resource实现可以简单的实现对系统文件的操作。 InputStreamResource给定的InputStream的Resource实现。 只有当没有特定的资源实现适用时才应该使用它。 ByteArrayResource这是一个给定字节数组的资源实现。 Testpublic 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));}}2、classpath 前缀 前缀 [classpath:*] 只会到你的 target 下面的 class 路径中查找找文件通常匹配一个资源前缀 [classpath*:]不仅包含 target 下面的 class 路径还包括 jar 文件中target 下面的class路径进行查找可以匹配多个资源这种场景非常多比如在实现了 springboot 自动装配相关的 jar 包中绝大多数都会由 spring.factories 文件。 3、PathMatchingResourcePatternResolver 下面是它的结构图 它提供了 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* 前缀的Overridepublic 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.SetResource resources findAllModulePathResources(locationPatternWithoutPrefix);if (getPathMatcher().isPattern(locationPatternWithoutPrefix)) {// a class path resource patternCollections.addAll(resources, findPathMatchingResources(locationPattern));}else {// all class path resources with the given nameCollections.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 patternreturn findPathMatchingResources(locationPattern);}else {// a single resource with the given namereturn new Resource[] {getResourceLoader().getResource(locationPattern)};}}}测试 Testpublic 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 Spring 提供了 Event Multicaster可以十分简单地实现发布订阅模式观察者模式。 Multicast组播多播 这个多播器呢可以发布事件事件会被对应的监听器监听若事件被发布了当然就会触发监听者执行相应的操作。Spring默认有个 SimpleApplicationEventMulticaster 多播器。 简单地测试使用如下 Testvoid testEventMulticaster() {SimpleApplicationEventMulticaster eventMulticaster newSimpleApplicationEventMulticaster();eventMulticaster.addApplicationListener(new EmailListener());eventMulticaster.addApplicationListener(new MessageListener());eventMulticaster.addApplicationListener(new EmailListener());// 使用多播器发送事件eventMulticaster.multicastEvent(new OrderEvent(this));}自定义事件可以去继承 ApplicationEvent 类自定义监听器可以去实现 ApplicationListener.实现如下 public class MessageListener implements ApplicationListenerOrderEvent public class OrderEvent extends ApplicationEvent 但是实际使用都是通过 bean 进行注入的ApplicationContext 中的事件处理是通过 ApplicationEvent 类和 ApplicationListener 接口提供的。如果将实现的 ApplicationListener 接口中的 bean 部署到了容器中则每次将 ApplicationEvent 发布到 ApplicationContext 时都会通知到该 bean这是典型的观察者模式。 通过上面的 UML 图咱可以有个大概的理解 事件和 ApplicationEventPublisher 事件发布者是聚合的关系事件是由 publisher 进行发布的而ApplicationContext 就是对 ApplicationEventPublisher 的实现就是说 ApplicationContext 操纵着事件的发布。Multicaster 拥有很多 Listener并在 ApplicationContext 中聚合当然 ApplicationContext 也可以对监听者进行添加也就是说 ApplicationContext 本身就担任监听器注册表的角色在其子类 AbstractApplicationContext 中就聚合了事件广播器和事件监听器并且提供了注册监听器的 addApplicationListener 方法。使用 定义一个继承 ApplicationEvent 事件定义一个实现 ApplicationListener 的监听器或者使用 EventListener 监听时间定义一个发送者调用 ApplicationContext 直接发布或者使用 ApplicationEventPublisher 来发布自定义事件。 SimpleApplicationEventMulticaster源码分析 Spring 默认注入的多播器是 SimpleApplicationEventMulticaster也就是说如果你不自定义 Publisher 发布事件的话默认就是通过多播器帮你发了 一般情况下监听器都是通过bean注入的方式进去的那bean的话又分为多例prototype单利singleton。看看下图它是如何管理的 当listener被调用执行后如何进行了缓存 当listener被调用执行后如果是单例的会被缓存到 RetrieverCache 中其中key 是 eventtype 和 sourcetype 的封装value 是对应的 listeners当然一个事件可能对应多个监听嘛当一个事件触发后是先去从缓存中查找有无对应的事件监听无的话再遍历查找。 SimpleApplicationEventMulticaster 源码如下 public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {// 定义一个线程池事件被触发时可由他来实现事件默认为nullprivate 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;}Nullableprotected ErrorHandler getErrorHandler() {return this.errorHandler;}//设置一个自定义执行器线程池来调用每个侦听器。public void setTaskExecutor(Nullable Executor taskExecutor) {this.taskExecutor taskExecutor;}Nullableprotected Executor getTaskExecutor() {return this.taskExecutor;}// 广播一个事件Overridepublic void multicastEvent(ApplicationEvent event) {multicastEvent(event, resolveDefaultEventType(event));}// 广播一个事件的具体实现Overridepublic void multicastEvent(final ApplicationEvent event, Nullable ResolvableType eventType) {ResolvableType type (eventType ! null ? eventType : resolveDefaultEventType(event));Executor executor getTaskExecutor();// 核心一getApplicationListeners(event, type)稍后看// 他的重点是如何设计的缓存// 获取所有与event事件匹配的listener并调用核心方法onApplicationEventfor (ApplicationListener? listener : getApplicationListeners(event, type)) {// 如果你设置了线程池他会将任务丢给线程池if (executor ! null) {// 核心二调用Listener的方法invokeListenerexecutor.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时产生放入errorHandlererrorHandler.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 AbstractApplicationEventMulticasterimplements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {// 真正保存listener的地方他保存了传入的listener实例和容器里的监听器bean的名字// 其结构如图1private final DefaultListenerRetriever defaultRetriever new DefaultListenerRetriever();// 这个集合是对已调用的event和listener的缓存// ListenerCacheKey保存了一组event和source// CachedListenerRetriever保存了已注册的、容器的单例bean、容器的非单例beanName// 非单例的bean只能缓存name实例会消亡final MapListenerCacheKey, Cached Retriever retrieverCache new ConcurrentHashMap(64);Nullableprivate ClassLoader beanClassLoader;Nullableprivate ConfigurableBeanFactory beanFactory;// 以编程的方式添加监听器Overridepublic void addApplicationListener(ApplicationListener? listener) {// 这个过程可能存在线程安全的问题比如一线线程synchronized (this.defaultRetriever) {// 因为你的Aop可能影响到该listener// 我们需要将代理对象从defaultRetriever中删除因为我们并不需要Object singletonTarget AopProxyUtils.getSingletonTarget(listener);if (singletonTarget instanceof ApplicationListener) {this.defaultRetriever.applicationListeners.remove(singletonTarget);}// 添加原生的监听器到defaultRetrieverthis.defaultRetriever.applicationListeners.add(listener);// 清理缓存this.retrieverCache.clear();}}// 直接以bean的方式将listenerBeanName添加到defaultRetrieverOverridepublic void addApplicationListenerBean(String listenerBeanName) {synchronized (this.defaultRetriever) {this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);// 清理缓存this.retrieverCache.clear();}}// 获得所有的bean的实例// 第一部分编程式的bean的实例// 第二部分容器的bean进行实例化protected CollectionApplicationListener? getApplicationListeners() {synchronized (this.defaultRetriever) {return this.defaultRetriever.getApplicationListeners();}}// ...省略掉大量雷同的crud增删查改代码// 我们看一个比较有难度的方法该方法根据事件获取满足条件的listenersprotected CollectionApplicationListener? getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {// 获得事件源那个类中发布的时间如OrderService类发布是orderEvent// source就是OrderServiceevent就是orderEventObject source event.getSource();Class? sourceType (source ! null ? source.getClass() : null);// 通过事件类型和源类型创建缓存key// 第二次请求就避免了再次检索ListenerCacheKey cacheKey new ListenerCacheKey(eventType, sourceType);// 定义新的Listener缓存器他是作为retrieverCache的valueCachedListenerRetriever 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-valueif (existingRetriever ! null) {CollectionApplicationListener? result existingRetriever.getApplicationListeners();// 将缓存中的Listeners全部取出返回if (result ! null) {return result;}// 缓存命中没有拿到结果此时result为null// 这种一般出现在多线程情况有一个线程已经创建了这个缓存器但是还没有机会赋值// 当前线程又拿到了这个缓存器那我们就继续}// 该方法会为我们当前根据key过滤合适的listeners并缓存器赋值return retrieveApplicationListeners(eventType, sourceType, newRetriever);}// 该方法会给传入的newRetriever赋值检索过程相对复杂// 这个方法会过滤满足条件的Listeners并将过滤后的内容放到缓存中private CollectionApplicationListener? retrieveApplicationListeners(ResolvableType eventType, Nullable Class? sourceType, Nullable CachedListenerRetriever retriever) {// 保存所有过滤好的listeners// 他包含编程式的实例和容器的beanListApplicationListener? allListeners new ArrayList();// 过滤后的监听器将来做缓存用SetApplicationListener? filteredListeners (retriever ! null ? new LinkedHashSet() : null);// 过滤后的监听器beanName将来做缓存用SetString filteredListenerBeans (retriever ! null ? new LinkedHashSet() : null);SetApplicationListener? listeners;SetString listenerBeans;// 每个线程拷贝独立的listeners和listenerBeanssynchronized (this.defaultRetriever) {// 优先做一个拷贝listeners new LinkedHashSet(this.defaultRetriever.applicationListeners);listenerBeans new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);}// 将所有的listener实例遍历,过滤满足条件的for (ApplicationListener? listener : listeners) {if (supportsEvent(listener, eventType, sourceType)) {// 如果传递了缓存器就将它存入filteredListenersif (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工厂获取实例化beanApplicationListener? listener beanFactory.getBean(listenerBeanName,ApplicationListener.class);if (!allListeners.contains(listener) supportsEvent(listener, eventType, sourceType)) {if (retriever ! null) {// 如果是单例的就加入filteredListenersif (beanFactory.isSingleton(listenerBeanName)) {filteredListeners.add(listener);}// 如果不是单例bean则加入filteredListenerBeans// 原因是非单例bean使用结束可能会被gc下次使用需要重新实例化// 所以我们并不缓存非单例的listenerbeanelse {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的名字// 下次从缓存获取的时候还是会再次实例化非单例的beanif (retriever ! null) {// 如果啥也没有过滤则添加全部的Listeners和ListenerBeans到retrieverif (filteredListenerBeans.isEmpty()) {retriever.applicationListeners new LinkedHashSet(allListeners);retriever.applicationListenerBeans filteredListenerBeans;}else {retriever.applicationListeners filteredListeners;retriever.applicationListenerBeans filteredListenerBeans;}}return allListeners;} } keyListenerCacheKey的实现 private static final class ListenerCacheKey implements ComparableListenerCacheKey {// 一个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;}//...省略 }valueCachedListenerRetriever的实现 //listener缓存工具类它封装了一组特定的目标侦听器允许高效检索预先过滤的侦听器。每个事件类型和源类型缓存这个helper的实例。 private class CachedListenerRetriever {// 保存了满足条件的applicationListeners// 包含编程式的和容器内满足条件的单例beanNullablepublic volatile SetApplicationListener? applicationListeners;// 保存了满足条件的非单例的applicationListenerBeansNullablepublic volatile SetString applicationListenerBeans;// 该方法是从特定缓存获取applicationListeners// 这个方法会再次实例化非单例的beanNullablepublic CollectionApplicationListener? getApplicationListeners() {SetApplicationListener? applicationListeners this.applicationListeners;SetString applicationListenerBeans this.applicationListenerBeans;if (applicationListeners null || applicationListenerBeans null) {// Not fully populated yetreturn null;}// 创建一个临时的集合保存所有的监听器ListApplicationListener? 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 SetApplicationListener? applicationListeners new LinkedHashSet();public final SetString applicationListenerBeans new LinkedHashSet();public CollectionApplicationListener? getApplicationListeners() {ListApplicationListener? 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;} }
http://www.zqtcl.cn/news/889118/

相关文章:

  • 网站seo设计北京市建设投标网站
  • 承德做网站设计的网络推广主要内容
  • 婚纱网站源代码重庆网站定制公司
  • 同一个ip网站太多 seo应用商店网站源码
  • 网站内容框架首页>新闻>正文 网站怎么做
  • 网站制作 搜索做效果图网站有哪些
  • 网站建设的相关技术网站的购物车怎么做
  • 免费建设公司网站腾讯云域名购买
  • 淘宝客网站应该怎么做网页浏览器推荐
  • 怎样做影视网站不侵权商丘专业做网站
  • 哪个网站做刷手最好鹤壁 网站建设
  • 设计接单子网站安徽网站开发推荐
  • 网站建设制作 优帮云怎样注册商标申请
  • 网站怎么做交易市场苏州吴江做网站公司
  • wordpress的字体禁用优化设计的答案
  • 网站建设开发五行属性如何做二级域名网站
  • 珠海做网站的公司介绍最近的新闻大事
  • 手机网站开发解决方案石碣镇网站建设
  • 保定网站建设公司哪家好app开发公司好吗
  • 网站域名备案证书网页素材大宝库
  • 沈阳网站制作的公司哪家好wordpress您访问的网页出错
  • 南京做公司网站有什么网站用名字做图片大全
  • 网站正在建设中页面wordpress 折叠文章
  • 广西建设科技协会网站手工做环保衣的网站
  • 怎么免费做网站教程开发专业网站
  • 鹿邑网站设计公司什么网站可以免费做找客户
  • wordpress模板站如何安装wordpress 查询语句
  • 给窗帘做网站淄博周村学校网站建设公司
  • 关于志愿者网站开发的论文做什么网站开发好
  • 做电影网站如何规避版权做新年公告图片的网站