Spring 源码学习(七)——注解后处理器-2
五 InitDestroyAnnotationBeanPostProcessor 类
1 属性
InitDestroyAnnotationBeanPostProcessor 类用于处理初始化与销毁注解;其中第一个属性为用于标识初始化方法与销毁方法注解类型的 initAnnotationType 与 destroyAnnotationType 属性、还有一个用于标识执行顺序的 order 属性,默认为最大值、用于缓存生命周期元数据的 lifecycleMetadataCache 及一个标识空生命周期元数据对象的 emptyLifecycleMetadata 属性;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private final transient LifecycleMetadata emptyLifecycleMetadata =new LifecycleMetadata(Object.class, Collections.emptyList(), Collections.emptyList()) {@Overridepublic void checkConfigMembers(RootBeanDefinition beanDefinition) {}@Overridepublic void invokeInitMethods(Object target, String beanName) {}@Overridepublic void invokeDestroyMethods(Object target, String beanName) {}@Overridepublic boolean hasDestroyMethods() {return false;}};protected transient Log logger = LogFactory.getLog(getClass());@Nullableprivate Class<? extends Annotation> initAnnotationType;@Nullableprivate Class<? extends Annotation> destroyAnnotationType;private int order = Ordered.LOWEST_PRECEDENCE;@Nullableprivate final transient Map<Class<?>, LifecycleMetadata> lifecycleMetadataCache = new ConcurrentHashMap<>(256);public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {this.initAnnotationType = initAnnotationType;}public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {this.destroyAnnotationType = destroyAnnotationType;}public void setOrder(int order) {this.order = order;}@Overridepublic int getOrder() {return this.order;}
}
2 类方法
2.1 postProcessMergedBeanDefinition 方法
postProcessMergedBeanDefinition 方法在通过 findLifecycleMetadata 方法创建 LifecycleMetadata 对象后并使用 beanDefinition 执行其的 checkConfigMembers 方法向对象注册表中注册初始化与销毁方法;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {LifecycleMetadata metadata = findLifecycleMetadata(beanType);metadata.checkConfigMembers(beanDefinition);}
}
findLifecycleMetadata 方法在 lifecycleMetadataCache 缓存为 null 时直接执行 buildLifecycleMetadata 方法创建 LifecycleMetadata 对象并返回,否则首先尝试从该缓存中获取 clazz 对应的元数据,获取到时直接返回缓存对象,否则 buildLifecycleMetadata 方法创建 LifecycleMetadata 对象并保存到 lifecycleMetadataCache 缓存中同时返回;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {if (this.lifecycleMetadataCache == null) {return buildLifecycleMetadata(clazz);}LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {synchronized (this.lifecycleMetadataCache) {metadata = this.lifecycleMetadataCache.get(clazz);if (metadata == null) {metadata = buildLifecycleMetadata(clazz);this.lifecycleMetadataCache.put(clazz, metadata);}return metadata;}}return metadata;}
}
buildLifecycleMetadata 方法在 clazz 参数没有使用 initAnnotationType 与 destroyAnnotationType 注解进行修饰时直接返回 emptyLifecycleMetadata 空生命周期元数据,然后寻找 clazz 参数及其所有父类中使用 initAnnotationType 与 destroyAnnotationType 注解修饰方法并使用 LifecycleElement 类对其进行封装,最后在查询完毕后,使用 clazz 、查询到的初始化方法与销毁方法封装对象数组创建 LifecycleMetadata 对象并返回;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {return this.emptyLifecycleMetadata;}List<LifecycleElement> initMethods = new ArrayList<>();List<LifecycleElement> destroyMethods = new ArrayList<>();Class<?> targetClass = clazz;do {final List<LifecycleElement> currInitMethods = new ArrayList<>();final List<LifecycleElement> currDestroyMethods = new ArrayList<>();ReflectionUtils.doWithLocalMethods(targetClass, method -> {if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {LifecycleElement element = new LifecycleElement(method);currInitMethods.add(element);if (logger.isTraceEnabled()) {logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);}}if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {currDestroyMethods.add(new LifecycleElement(method));if (logger.isTraceEnabled()) {logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);}}});initMethods.addAll(0, currInitMethods);destroyMethods.addAll(currDestroyMethods);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :new LifecycleMetadata(clazz, initMethods, destroyMethods));}
}
2.2 postProcessBeforeInitialization 方法
postProcessBeforeInitialization 方法首先通过 findLifecycleMetadata 查询 bean 参数对应的生命周期元数据并调用其 invokeInitMethods 方法执行初始化方法并在执行完成后返回 bean 参数;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());try {metadata.invokeInitMethods(bean, beanName);}catch (InvocationTargetException ex) {throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());}catch (Throwable ex) {throw new BeanCreationException(beanName, "Failed to invoke init method", ex);}return bean;}
}
2.3 postProcessAfterInitialization 方法
postProcessAfterInitialization 方法不执行任何逻辑直接返回 bean 参数;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
2.4 postProcessBeforeDestruction 方法
postProcessBeforeDestruction 方法首先通过 findLifecycleMetadata 查询 bean 参数对应的生命周期元数据并调用其 invokeDestroyMethods 方法执行销毁方法;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());try {metadata.invokeDestroyMethods(bean, beanName);}catch (InvocationTargetException ex) {String msg = "Destroy method on bean with name '" + beanName + "' threw an exception";if (logger.isDebugEnabled()) {logger.warn(msg, ex.getTargetException());}else {logger.warn(msg + ": " + ex.getTargetException());}}catch (Throwable ex) {logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);}}
}
2.5 requiresDestruction 方法
requiresDestruction 方法获取 bean 参数对应的生命周期元数据并然后其使用拥有销毁方法;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {@Overridepublic boolean requiresDestruction(Object bean) {return findLifecycleMetadata(bean.getClass()).hasDestroyMethods();}
}
3 LifecycleElement 内部类
3.1 属性及构造方法
3.1.1 类属性
LifecycleElement 类用于封装方法对象,其拥有保存封装 Method 方法对象的 method 属性与方法名标识的 identifier 属性;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private static class LifecycleElement {private final Method method;private final String identifier;public Method getMethod() {return this.method;}public String getIdentifier() {return this.identifier;}}
}
3.1.2 构造方法
LifecycleElement 类只有一个构造方法,其只有一个 Method 类型参数,在创建过程中首先对 method 参数的参数个数进行空验证,即不为空直接报错;验证通过后首先将 method 属性初始化为 method 参数值,随后在若 mothod 为私有方法时将 identifer 属性初始化为全限定类名 + 方法名,否则直接初始化为方法名;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private static class LifecycleElement {public LifecycleElement(Method method) {if (method.getParameterCount() != 0) {throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method);}this.method = method;this.identifier = (Modifier.isPrivate(method.getModifiers()) ?ClassUtils.getQualifiedMethodName(method) : method.getName());}}
}
3.2 invoke 方法
invoke 方法直接执行 method 属性的 invoke 方法;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private static class LifecycleElement {public void invoke(Object target) throws Throwable {ReflectionUtils.makeAccessible(this.method);this.method.invoke(target, (Object[]) null);}}
}
4 LifecycleMetadata 内部类
4.1 属性及构造方法
4.1.1 类属性
LifecycleMetadata 类用于封装类以向外提供对生命周期元数据的处理,其中 targerClass 属性保存的时封装的 Class 类型对象、initMethods 与 checkedInitMethods 属性分别保存所有初始化方法元数据封装集合与通过验证后的初始化方法元数据封装集合及保存所有销毁方法元数据封装集合与通过验证后的销毁方法元数据封装集合的 destroyMethods 与 checkedDestroyMethods 属性;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private class LifecycleMetadata {private final Class<?> targetClass;private final Collection<LifecycleElement> initMethods;private final Collection<LifecycleElement> destroyMethods;@Nullableprivate volatile Set<LifecycleElement> checkedInitMethods;@Nullableprivate volatile Set<LifecycleElement> checkedDestroyMethods;}
}
4.1.2 构造方法
LifecycleMetadata 类只有一个分别将 targetClass、initMethods 与 destroyMethods 属性初始化为对应的入参属性值;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private class LifecycleMetadata {public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods,Collection<LifecycleElement> destroyMethods) {this.targetClass = targetClass;this.initMethods = initMethods;this.destroyMethods = destroyMethods;}}
}
4.2 类方法
4.2.1 checkConfigMembers 方法
checkConfigMembers 方法分别将 beanDefinition 中未注册 initMethods 与 destroyMethods 属性中的元素注册到该对象注册表并保存到 checkedInitMethods 与 checkedDestroyMethods 属性中;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private class LifecycleMetadata {public void checkConfigMembers(RootBeanDefinition beanDefinition) {Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());for (LifecycleElement element : this.initMethods) {String methodIdentifier = element.getIdentifier();if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);checkedInitMethods.add(element);if (logger.isTraceEnabled()) {logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + element);}}}Set<LifecycleElement> checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size());for (LifecycleElement element : this.destroyMethods) {String methodIdentifier = element.getIdentifier();if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);checkedDestroyMethods.add(element);if (logger.isTraceEnabled()) {logger.trace("Registered destroy method on class [" + this.targetClass.getName() + "]: " + element);}}}this.checkedInitMethods = checkedInitMethods;this.checkedDestroyMethods = checkedDestroyMethods;}}
}
4.2.2 invokeInitMethods 方法
invokeInitMethods 方法在 checkedInitMethods 属性不为空依次执行所有元素,否则依次执行 initMethods 属性中的所有元素;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private class LifecycleMetadata {public void invokeInitMethods(Object target, String beanName) throws Throwable {Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;Collection<LifecycleElement> initMethodsToIterate =(checkedInitMethods != null ? checkedInitMethods : this.initMethods);if (!initMethodsToIterate.isEmpty()) {for (LifecycleElement element : initMethodsToIterate) {if (logger.isTraceEnabled()) {logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());}element.invoke(target);}}}}
}
4.2.3 hasDestroyMethods 方法
hasDestroyMethods 方法直接返回 checkedDestroyMethods 与 destroyMethods 属性是否全没有任何元素;
public class InitDestroyAnnotationBeanPostProcessorimplements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {private class LifecycleMetadata {public boolean hasDestroyMethods() {Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods;Collection<LifecycleElement> destroyMethodsToUse =(checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);return !destroyMethodsToUse.isEmpty();}}
}
六 CommonAnnotationBeanPostProcessor 类
1 属性及构造方法
1.1 常量
CommonAnnotationBeanPostProcessor 拥有三个常量,其中 webServiceRefClass 属性保存的是 webService 服务声明注解,ejbClass 属性保存的则是 EJB 服务声明注解,最后一个常量为 resourceAnnotationTypes,其保存的则是资源声明注解 set 集合;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {@Nullableprivate static final Class<? extends Annotation> webServiceRefClass;@Nullableprivate static final Class<? extends Annotation> ejbClass;private static final Set<Class<? extends Annotation>> resourceAnnotationTypes = new LinkedHashSet<>(4);
}
CommonAnnotationBeanPostProcessor 的三个常量都是在静态代码块中进行赋值,其首先分别将 webServiceRefClass 与 ejbClass 常量加载为 javax.xml.ws.WebServiceRef 与 javax.ejb. EJB 注解对象,随后首先向 resourceAnnotationTypes 常量中添加 Resource 对象,随后将加载到的 webServiceRefClass 与 ejbClass 常量值依次添加到 resourceAnnotationTypes 常量中;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {static {webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");ejbClass = loadAnnotationType("javax.ejb.EJB");resourceAnnotationTypes.add(Resource.class);if (webServiceRefClass != null) {resourceAnnotationTypes.add(webServiceRefClass);}if (ejbClass != null) {resourceAnnotationTypes.add(ejbClass);}}
}
loadAnnotationType 方法直接尝试加载 name 参数对应类并将其转化为 Annotation 注解类型对象并返回,若未找到 name 对应类时直接返回 null。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {@Nullableprivate static Class<? extends Annotation> loadAnnotationType(String name) {try {return (Class<? extends Annotation>)ClassUtils.forName(name, CommonAnnotationBeanPostProcessor.class.getClassLoader());}catch (ClassNotFoundException ex) {return null;}}
}
1.2 类属性
CommonAnnotationBeanPostProcessor 类的 ignoredResourceTypes 属性用于保存注入时需忽略的类名,fallbackToDefaultTypeMatch 属性则标识是否需要会退匹配注入类型,默认为 true,alwaysUseJndiLookup 属性则是表明检索资源时是否需要从 jndiFactory 中查询 mappedName 对象,jndiFactory、resourceFactory 及 beanFactory 三个对象工厂属性分别保存的是 jndi 对象工厂、资源对象工厂及当前工厂对象,embeddedValueResolver 属性保存的是字符串解析对象,injectionMetadataCache 属性则是注入元数据的缓存;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private final Set<String> ignoredResourceTypes = new HashSet<>(1);private boolean fallbackToDefaultTypeMatch = true;private boolean alwaysUseJndiLookup = false;private transient BeanFactory jndiFactory = new SimpleJndiBeanFactory();@Nullableprivate transient BeanFactory resourceFactory;@Nullableprivate transient BeanFactory beanFactory;@Nullableprivate transient StringValueResolver embeddedValueResolver;private final transient Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);public void ignoreResourceType(String resourceType) {Assert.notNull(resourceType, "Ignored resource type must not be null");this.ignoredResourceTypes.add(resourceType);}public void setFallbackToDefaultTypeMatch(boolean fallbackToDefaultTypeMatch) {this.fallbackToDefaultTypeMatch = fallbackToDefaultTypeMatch;}public void setAlwaysUseJndiLookup(boolean alwaysUseJndiLookup) {this.alwaysUseJndiLookup = alwaysUseJndiLookup;}public void setJndiFactory(BeanFactory jndiFactory) {Assert.notNull(jndiFactory, "BeanFactory must not be null");this.jndiFactory = jndiFactory;}public void setResourceFactory(BeanFactory resourceFactory) {Assert.notNull(resourceFactory, "BeanFactory must not be null");this.resourceFactory = resourceFactory;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) {Assert.notNull(beanFactory, "BeanFactory must not be null");this.beanFactory = beanFactory;if (this.resourceFactory == null) {this.resourceFactory = beanFactory;}if (beanFactory instanceof ConfigurableBeanFactory) {this.embeddedValueResolver = new EmbeddedValueResolver((ConfigurableBeanFactory) beanFactory);}}
}
1.3 构造方法
CommonAnnotationBeanPostProcessor 类只有一个构造方法,其分别将 Ordered.LOWEST_PRECEDENCE - 3、PostConstruct 类型及 PreDestroy 类型保存到 order、initAnnotationType 及 destroyAnnotationType 属性中,并在最后将 javax.xml.ws.WebServiceContext 添加到 ignoredResourceTypes 属性中 ;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {public CommonAnnotationBeanPostProcessor() {setOrder(Ordered.LOWEST_PRECEDENCE - 3);setInitAnnotationType(PostConstruct.class);setDestroyAnnotationType(PreDestroy.class);ignoreResourceType("javax.xml.ws.WebServiceContext");}
}
ignoreResourceType 方法在完成了 resourceType 参数的非空验证后,将其添加到 ignoredResourceTypes 属性中;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {public void ignoreResourceType(String resourceType) {Assert.notNull(resourceType, "Ignored resource type must not be null");this.ignoredResourceTypes.add(resourceType);}
}
2 类方法
2.1 postProcessMergedBeanDefinition 方法
postProcessMergedBeanDefinition 方法在执行完父对象的 postProcessMergedBeanDefinition 方法完成对对象初始化和销毁方法元数据的处理后,执行 findResourceMetadata 方法创建 findResourceMetadata 对象并使用该对象对 beanDefinition 参数执行 checkConfigMembers 方法;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);}
}
findResourceMetadata 方法首先尝试从 injectionMetadataCache 中获取 beanName 或 clazz 类名对应的 InjectionMetadata 对象,并在该对象需要刷新时,调用 buildResourceMetadata 对象创建 InjectionMetadata 对象并将其添加到 injectionMetadataCache 缓存中并返回;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {synchronized (this.injectionMetadataCache) {metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {if (metadata != null) {metadata.clear(pvs);}metadata = buildResourceMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;}
}
buildResourceMetadata 首先在 clazz 参数没有 resourceAnnotationTypes 属性所包含的注解时,直接返回 InjectionMetadata 的 EMPTY 空 InjectionMetadata 对象;随后对 clazz 及其所有父类中所有使用 webServiceRefClass、ejbClass 属性及 Resource 注解对象修饰的字段与方法对象创建 InjectedElement 对象数组,并在最后使用该对象数组创建 InjectionMetadata 对象并返回;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private InjectionMetadata buildResourceMetadata(Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();ReflectionUtils.doWithLocalFields(targetClass, field -> {if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {if (Modifier.isStatic(field.getModifiers())) {throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");}currElements.add(new WebServiceRefElement(field, field, null));}else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {if (Modifier.isStatic(field.getModifiers())) {throw new IllegalStateException("@EJB annotation is not supported on static fields");}currElements.add(new EjbRefElement(field, field, null));}else if (field.isAnnotationPresent(Resource.class)) {if (Modifier.isStatic(field.getModifiers())) {throw new IllegalStateException("@Resource annotation is not supported on static fields");}if (!this.ignoredResourceTypes.contains(field.getType().getName())) {currElements.add(new ResourceElement(field, field, null));}}});ReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {if (Modifier.isStatic(method.getModifiers())) {throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");}if (method.getParameterCount() != 1) {throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);}PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));}else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {if (Modifier.isStatic(method.getModifiers())) {throw new IllegalStateException("@EJB annotation is not supported on static methods");}if (method.getParameterCount() != 1) {throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);}PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new EjbRefElement(method, bridgedMethod, pd));}else if (bridgedMethod.isAnnotationPresent(Resource.class)) {if (Modifier.isStatic(method.getModifiers())) {throw new IllegalStateException("@Resource annotation is not supported on static methods");}Class<?>[] paramTypes = method.getParameterTypes();if (paramTypes.length != 1) {throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);}if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new ResourceElement(method, bridgedMethod, pd));}}}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);}
}
2.2 resetBeanDefinition 方法
resetBeanDefinition 方法直接移除 injectionMetadataCache 缓存中的 beanName 参数对应的缓存值;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {@Overridepublic void resetBeanDefinition(String beanName) {this.injectionMetadataCache.remove(beanName);}
}
2.3 postProcessProperties 方法
postProcessProperties 方法在执行 findResourceMetadata 方法获取对应的 InjectionMetadata 对象后执行其 inject 方法将对象注入到该元数据中;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);try {metadata.inject(bean, beanName, pvs);}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);}return pvs;}
}
3 InjectionMetadata 类
3.1 变量及构造方法
3.1.1 常量
InjectionMetadata 类只有一个空 InjectionMetadata 对象的常量 EMPTY,其将 checkConfigMembers、inject 及 clear 方法的方法体置为空,同时 needsRefresh 方法直接返回 false;
public class InjectionMetadata {public static final InjectionMetadata EMPTY = new InjectionMetadata(Object.class, Collections.emptyList()) {@Overrideprotected boolean needsRefresh(Class<?> clazz) {return false;}@Overridepublic void checkConfigMembers(RootBeanDefinition beanDefinition) {}@Overridepublic void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) {}@Overridepublic void clear(@Nullable PropertyValues pvs) {}};
}
3.1.2 类变量
InjectionMetadata 类用三个不同的属性,其中 targetClass 属性保存的是关联类对象,injectedElements 属性保存的是原始注入元素集合而 checkedElements 属性则保存的是通过验证的注入元素 Set 集合;
public class InjectionMetadata {private final Class<?> targetClass;private final Collection<InjectedElement> injectedElements;@Nullableprivate volatile Set<InjectedElement> checkedElements;
}
3.1.3 构造方法
InjectionMetadata 类只有一个将 targetClass 与 injectedElements 属性初始化为对应入参值;
public class InjectionMetadata {public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {this.targetClass = targetClass;this.injectedElements = elements;}
}
3.2 类方法
3.2.1 needsRefresh 方法
needsRefresh 方法直接返回 clazz 入参值是否等于 targetClass 属性;
public class InjectionMetadata {protected boolean needsRefresh(Class<?> clazz) {return this.targetClass != clazz;}
}
3.2.2 checkConfigMembers 方法
checkConfigMembers 方法将 injectedElements 中还未注入到 beanDefinition 参数的元素注册到 beanDefinition 参数中同时将其保存到 checkedElements 属性中;
public class InjectionMetadata {public void checkConfigMembers(RootBeanDefinition beanDefinition) {Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());for (InjectedElement element : this.injectedElements) {Member member = element.getMember();if (!beanDefinition.isExternallyManagedConfigMember(member)) {beanDefinition.registerExternallyManagedConfigMember(member);checkedElements.add(element);}}this.checkedElements = checkedElements;}
}
3.2.3 inject 方法
inject 方法目标对象注入到 checkedElements 或 injectedElements 的所有元素中;
public class InjectionMetadata {public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {for (InjectedElement element : elementsToIterate) {element.inject(target, beanName, pvs);}}}
}
3.2.4 clear 方法
clear 方法调用 checkedElements 或 injectedElements 的所有元素的 clearPropertySkipping 方法来跳过 pvs 参数属性;
public class InjectionMetadata {public void clear(@Nullable PropertyValues pvs) {Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {for (InjectedElement element : elementsToIterate) {element.clearPropertySkipping(pvs);}}}
}
3.3 静态方法
3.3.1 forElements 方法
forElements 方法直接使用两个入参创建 InjectionMetadata 对象并返回。
public class InjectionMetadata {public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {return (elements.isEmpty() ? new InjectionMetadata(clazz, Collections.emptyList()) :new InjectionMetadata(clazz, elements));}
}
3.3.2 needsRefresh 方法
needsRefresh 方法直接返回 metadata 参数是否为 null 或 metadata 的 needsRefresh 方法直接结果。
public class InjectionMetadata {public static boolean needsRefresh(@Nullable InjectionMetadata metadata, Class<?> clazz) {return (metadata == null || metadata.needsRefresh(clazz));}
}
3.4 InjectedElement 内部类
3.4.1 属性及构造方法
InjectedElement 类拥有 4 个属性,其中 member 属性用于保存注入属性或方法对象,isField 属性则是当前元素是否为属性字段,pd 则是属性访问器对象以及用于标识当前元素是否需要跳过。
public class InjectionMetadata {public abstract static class InjectedElement {protected final Member member;protected final boolean isField;@Nullableprotected final PropertyDescriptor pd;@Nullableprotected volatile Boolean skip;}
}
InjectedElement 类的构造方法直接将 member 与 pd 属性初始化为对应入参值,同时将 isfield 属性更新为 member 参数是否为 Field 对象。
public class InjectionMetadata {public abstract static class InjectedElement {protected InjectedElement(Member member, @Nullable PropertyDescriptor pd) {this.member = member;this.isField = (member instanceof Field);this.pd = pd;}}
}
3.4.2 getResourceType 方法
getResourceType 方法在 isField 属性为 true 时,直接将 member 转化为 Field 对象并返回其类型,否则在 pd 属性不为 null 时,返回其属性类型;否则将会将 member 转化为 Method 对象的第一个参数参数类型;
public class InjectionMetadata {public abstract static class InjectedElement {protected final Class<?> getResourceType() {if (this.isField) {return ((Field) this.member).getType();}else if (this.pd != null) {return this.pd.getPropertyType();}else {return ((Method) this.member).getParameterTypes()[0];}}}
}
3.4.3 checkResourceType 方法
checkResourceType 方法判断当前对象关联类型是否为 resourceType 子类或父类;
public class InjectionMetadata {public abstract static class InjectedElement {protected final void checkResourceType(Class<?> resourceType) {if (this.isField) {Class<?> fieldType = ((Field) this.member).getType();if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) {throw new IllegalStateException("Specified field type [" + fieldType +"] is incompatible with resource type [" + resourceType.getName() + "]");}}else {Class<?> paramType =(this.pd != null ? this.pd.getPropertyType() : ((Method) this.member).getParameterTypes()[0]);if (!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(resourceType))) {throw new IllegalStateException("Specified parameter type [" + paramType +"] is incompatible with resource type [" + resourceType.getName() + "]");}}}}
}
3.4.4 inject 方法
inject 方法判断当前对象关联类型是否为 resourceType 子类或父类;
public class InjectionMetadata {public abstract static class InjectedElement {protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable {if (this.isField) {Field field = (Field) this.member;ReflectionUtils.makeAccessible(field);field.set(target, getResourceToInject(target, requestingBeanName));}else {if (checkPropertySkipping(pvs)) {return;}try {Method method = (Method) this.member;ReflectionUtils.makeAccessible(method);method.invoke(target, getResourceToInject(target, requestingBeanName));}catch (InvocationTargetException ex) {throw ex.getTargetException();}}}@Nullableprotected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {return null;}}
}
checkPropertySkipping 方法在 skip 属性不为 null 时直接返回该属性值,在 pvs 参数为 null 时将 skip 属性置为 false 并返回 false;随后在 pd 属性不为 null 时,若 pvs 参数中是否包含 bd 属性时将 skip 属性置为 true 并返回 true,而在 pvs 参数为 MutablePropertyValues 对象时将 pd 属性注册为已处理过,并在最后将 skip 置为 false 并返回 false;
public class InjectionMetadata {public abstract static class InjectedElement {protected boolean checkPropertySkipping(@Nullable PropertyValues pvs) {Boolean skip = this.skip;if (skip != null) {return skip;}if (pvs == null) {this.skip = false;return false;}synchronized (pvs) {skip = this.skip;if (skip != null) {return skip;}if (this.pd != null) {if (pvs.contains(this.pd.getName())) {this.skip = true;return true;}else if (pvs instanceof MutablePropertyValues) {((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());}}this.skip = false;return false;}}}
}
3.4.4 clearPropertySkipping 方法
clearPropertySkipping 方法在 pvs 参数为 null 时直接返回,否则若 skip 属性为 false、pd 属性不为 null 且 pvs 参数为 MutablePropertyValues 对象时,则会清除 pvs 中的 pd 属性注册标识;
public class InjectionMetadata {public abstract static class InjectedElement {protected void clearPropertySkipping(@Nullable PropertyValues pvs) {if (pvs == null) {return;}synchronized (pvs) {if (Boolean.FALSE.equals(this.skip) && this.pd != null && pvs instanceof MutablePropertyValues) {((MutablePropertyValues) pvs).clearProcessedProperty(this.pd.getName());}}}}
}
4 LookupElement 内部类
4.1 变量及构造方法
4.1.1 类变量
LookupElement 类用于向泛型字段或 set 方法中注入对象;其拥有四个不同的属性字段,name 属性保存的是 Resource 注解的 name 属性值,或在其为空时为属性名称、isDefaultName 属性为 Resource 注解是否未设置 name 属性标识、lookupType 属性保存的是 Resource 注解的 type 属性值,或在其为空时为属性类型及保存 Resource 注解的 lookup 或 mappedName 属性值的 mappedName 属性。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {protected abstract static class LookupElement extends InjectionMetadata.InjectedElement {protected String name = "";protected boolean isDefaultName = false;protected Class<?> lookupType = Object.class;@Nullableprotected String mappedName;public final String getName() {return this.name;}public final Class<?> getLookupType() {return this.lookupType;}}
}
4.1.2 构造方法
在 LookupElement 对象的创建过程中直接使用入参值执行父类的构造方法;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {protected abstract static class LookupElement extends InjectionMetadata.InjectedElement {public LookupElement(Member member, @Nullable PropertyDescriptor pd) {super(member, pd);}}
}
4.2 类方法
4.2.1 getDependencyDescriptor 方法
getDependencyDescriptor 方法使用 member 与 lookupType 属性创建 LookupDependencyDescriptor 对象并返回;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {protected abstract static class LookupElement extends InjectionMetadata.InjectedElement {public final DependencyDescriptor getDependencyDescriptor() {if (this.isField) {return new LookupDependencyDescriptor((Field) this.member, this.lookupType);}else {return new LookupDependencyDescriptor((Method) this.member, this.lookupType);}}}
}
5 ResourceElement 内部类
5.1 变量及构造方法
5.1.1 类变量
ResourceElement 类继承了 LookupElement 类,扩展了其 Resource 注解的解析及懒加载功能,其只有一个用于标识是否需要懒加载的 lazyLookup 属性,即 Lazy 注解设置的;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class ResourceElement extends LookupElement {private final boolean lazyLookup;}
}
5.1.2 构造方法
ResourceElement 类构造方法首先也是使用 member 与 pd 属性执行父类的构造方法,随后将 isDefaultName 属性值更新为 ae 参数的 Resource 注解是否未设置 name 属性值,为 true 时,会将 resourceName 变量更新为 member 关联属性名,否则直接将 resourceName 变量设置为 Resource 注解的 name 属性值并在 embeddedValueResolver 属性不为空时,进一步使用该属性的 resolveStringValue 方法处理 Resource 注解的 name 属性值来对 resourceName 变量值进行更新;随后在 Resource 注解的 type 属性值为 Object 对象时,执行 checkResourceType 对该属性进行验证,否则将 resourceType 局部变量值更新为 getResourceType 方法执行结果;最后分别将 name、lookupType、mappedName 及 lazyLookup 属性分别更新为 resourceName 变量值、resourceType 变量值、Resource 注解的 lookup 或 mappedName 属性值及 Lazy 注解值;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class ResourceElement extends LookupElement {public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {super(member, pd);Resource resource = ae.getAnnotation(Resource.class);String resourceName = resource.name();Class<?> resourceType = resource.type();this.isDefaultName = !StringUtils.hasLength(resourceName);if (this.isDefaultName) {resourceName = this.member.getName();if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {resourceName = Introspector.decapitalize(resourceName.substring(3));}}else if (embeddedValueResolver != null) {resourceName = embeddedValueResolver.resolveStringValue(resourceName);}if (Object.class != resourceType) {checkResourceType(resourceType);}else {// No resource type specified... check field/method.resourceType = getResourceType();}this.name = (resourceName != null ? resourceName : "");this.lookupType = resourceType;String lookupValue = resource.lookup();this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());Lazy lazy = ae.getAnnotation(Lazy.class);this.lazyLookup = (lazy != null && lazy.value());}}
}
5.2 类方法
5.2.1 getResourceToInject 方法
getResourceToInject 方法在 lazyLookup 为 true 时,使用当前对象与 requestingBeanName 属性执行 buildLazyResourceProxy 方法执行懒加载代理对象并返回,否则使用当前对象及 requestingBeanName 参数执行 getResource 方法创建 Resource 对象并返回;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class ResourceElement extends LookupElement {@Overrideprotected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :getResource(this, requestingBeanName));}}
}
buildLazyResourceProxy 方法直接创建 TargetSource 对象,并重写了其中的 getTargetClass、isStatic、getTarget 及 releaseTarget 方法,其中 getTargetClass 方法直接返回 element 参数的 lookupType 属性值,isStatic 方法直接返回 false,getTarget 方法直接使用 element 与 requestingBeanName 参数执行 getResource 方法并返回,而 releaseTarget 方法没有任何实现;随后使用创建的 TargetSource 对象构造 ProxyFactory 对象工厂并执行其 getProxy 方法创建代理对象并返回;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {protected Object buildLazyResourceProxy(final LookupElement element, final @Nullable String requestingBeanName) {TargetSource ts = new TargetSource() {@Overridepublic Class<?> getTargetClass() {return element.lookupType;}@Overridepublic boolean isStatic() {return false;}@Overridepublic Object getTarget() {return getResource(element, requestingBeanName);}@Overridepublic void releaseTarget(Object target) {}};ProxyFactory pf = new ProxyFactory();pf.setTargetSource(ts);if (element.lookupType.isInterface()) {pf.addInterface(element.lookupType);}ClassLoader classLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : null);return pf.getProxy(classLoader);}
}
getResource 方法在 element 的 mappedName 属性不为空时,直接从 jndiFactory 对象工厂中获取 mappedName 属性对应对象并返回;随后在 alwaysUseJndiLookup 属性为 true 时,则尝试从 jndiFactory 对象工厂中获取 element 的 name 属性关联对象并返回;之后在 resourceFactory 不为空时直接执行 autowireResource 方法并返回,否则直接抛出异常;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {protected Object getResource(LookupElement element, @Nullable String requestingBeanName)throws NoSuchBeanDefinitionException {if (StringUtils.hasLength(element.mappedName)) {return this.jndiFactory.getBean(element.mappedName, element.lookupType);}if (this.alwaysUseJndiLookup) {return this.jndiFactory.getBean(element.name, element.lookupType);}if (this.resourceFactory == null) {throw new NoSuchBeanDefinitionException(element.lookupType,"No resource factory configured - specify the 'resourceFactory' property");}return autowireResource(this.resourceFactory, element, requestingBeanName);}
}
autowireResource 方法在 factory 参数为 AutowireCapableBeanFactory 对象,同时在 fallbackToDefaultTypeMatch 属性、element 参数的 isDefaultName 属性全为 true 且 factory 参数中不包含 element 参数关联对象时,通过 factory 的 resolveDependency 方法获取 requestingBeanName 关联对象并更新 autowiredBeanNames 变量值,未获取到时直接抛出异常时;否则会分别将 resource 与 autowiredBeanNames 变量值更新为使用 factory 参数获取的 element 关联对象及该参数关联名称;之后在 factory 为 ConfigurableBeanFactory 对象时,将 autowiredBeanNames 中的所有元素与 requestingBeanName 参数对照关系向 factory 注册依赖映射,并在最后返回 resource 变量值;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)throws NoSuchBeanDefinitionException {Object resource;Set<String> autowiredBeanNames;String name = element.name;if (factory instanceof AutowireCapableBeanFactory) {AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;DependencyDescriptor descriptor = element.getDependencyDescriptor();if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {autowiredBeanNames = new LinkedHashSet<>();resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);if (resource == null) {throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");}}else {resource = beanFactory.resolveBeanByName(name, descriptor);autowiredBeanNames = Collections.singleton(name);}}else {resource = factory.getBean(name, element.lookupType);autowiredBeanNames = Collections.singleton(name);}if (factory instanceof ConfigurableBeanFactory) {ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;for (String autowiredBeanName : autowiredBeanNames) {if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);}}}return resource;}
}
6 WebServiceRefElement 内部类
6.1 变量及构造方法
6.1.1 类变量
WebServiceRefElement 类也继承了 LookupElement 类,扩展了其对 webService 相关参数解析;该类拥有两个参数,其中 elementType 属性保存的是当前元素属性对象,而 wsdlLocation 则保存的是 webService 属性对应的地址;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class WebServiceRefElement extends LookupElement {private final Class<?> elementType;private final String wsdlLocation;}
}
6.1.2 构造方法
WebServiceRefElement 类只有一个构造方法,其首先也是使用 member 与 pd 参数执行父类的构造方法;随后使用 WebServiceRef 注解利用创建 ResourceElement 对象的逻辑分别为 name、elementType、lookupType、isDefaultName 及 mappedName 属性进行赋值,同时将 wsdlLocation 属性初始化为 WebServiceRef 注解对象的 wsdlLocation 属性值;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class WebServiceRefElement extends LookupElement {public WebServiceRefElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {super(member, pd);WebServiceRef resource = ae.getAnnotation(WebServiceRef.class);String resourceName = resource.name();Class<?> resourceType = resource.type();this.isDefaultName = !StringUtils.hasLength(resourceName);if (this.isDefaultName) {resourceName = this.member.getName();if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {resourceName = Introspector.decapitalize(resourceName.substring(3));}}if (Object.class != resourceType) {checkResourceType(resourceType);}else {resourceType = getResourceType();}this.name = resourceName;this.elementType = resourceType;if (Service.class.isAssignableFrom(resourceType)) {this.lookupType = resourceType;}else {this.lookupType = resource.value();}this.mappedName = resource.mappedName();this.wsdlLocation = resource.wsdlLocation();}}
}
6.2 类方法
6.2.1 getResourceToInject 方法
getResourceToInject 方法首先尝试使用当前对象与 requestingBeanName 参数执行 getResource 方法并使用其结果为 service 变量进行赋值;若在该方法的执行过程中未查询到关联对象注册表时,在 lookupType 属性为 Service 对象时直接抛出异常,随后若 wsdlLocation 属性不为空时,尝试获取 lookupType 属性的 WebServiceClient 注解对象,并在不存在该注解时直接抛出异常,否则将 service 变量更新为创建的 lookupType 对象,而在 wsdlLocation 属性为空时直接创建空 lookupType 对象;最后使用 service 变量的 getPort 方法获取 elementType 属性关联节点并返回;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class WebServiceRefElement extends LookupElement {@Overrideprotected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {Service service;try {service = (Service) getResource(this, requestingBeanName);}catch (NoSuchBeanDefinitionException notFound) {if (Service.class == this.lookupType) {throw new IllegalStateException("No resource with name '" + this.name + "' found in context, " +"and no specific JAX-WS Service subclass specified. The typical solution is to either specify " +"a LocalJaxWsServiceFactoryBean with the given name or to specify the (generated) Service " +"subclass as @WebServiceRef(...) value.");}if (StringUtils.hasLength(this.wsdlLocation)) {try {Constructor<?> ctor = this.lookupType.getConstructor(URL.class, QName.class);WebServiceClient clientAnn = this.lookupType.getAnnotation(WebServiceClient.class);if (clientAnn == null) {throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +"] does not carry a WebServiceClient annotation");}service = (Service) BeanUtils.instantiateClass(ctor,new URL(this.wsdlLocation), new QName(clientAnn.targetNamespace(), clientAnn.name()));}catch (NoSuchMethodException ex) {throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +"] does not have a (URL, QName) constructor. Cannot apply specified WSDL location [" +this.wsdlLocation + "].");}catch (MalformedURLException ex) {throw new IllegalArgumentException("Specified WSDL location [" + this.wsdlLocation + "] isn't a valid URL");}}else {service = (Service) BeanUtils.instantiateClass(this.lookupType);}}return service.getPort(this.elementType);}}
}
7 EjbRefElement 内部类
7.1 变量及构造方法
7.1.1 类变量
EjbRefElement 类中只有一个保存对象名的 beanName 属性;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class EjbRefElement extends LookupElement {private final String beanName;}
}
7.1.2 构造方法
EjbRefElement 类的构造方法在使用 member 与 pd 参数执行父类的构造方法,同时使用修饰 ae 参数的 EJB 注解对象的属性值去更新 LookupElement 参数的属性及 beanName 属性;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class EjbRefElement extends LookupElement {public EjbRefElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {super(member, pd);EJB resource = ae.getAnnotation(EJB.class);String resourceBeanName = resource.beanName();String resourceName = resource.name();this.isDefaultName = !StringUtils.hasLength(resourceName);if (this.isDefaultName) {resourceName = this.member.getName();if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {resourceName = Introspector.decapitalize(resourceName.substring(3));}}Class<?> resourceType = resource.beanInterface();if (Object.class != resourceType) {checkResourceType(resourceType);}else {resourceType = getResourceType();}this.beanName = resourceBeanName;this.name = resourceName;this.lookupType = resourceType;this.mappedName = resource.mappedName();}}
}
7.2 类方法
7.2.1 getResourceToInject 方法
getResourceToInject 方法在 beanName 属性不为空时,若 beanFactory 属性中包含名为 beanName 属性的对象时,则会从 beanFactory 属性中获取对应对象,若 requestingBeanName 参数不为空且 beanFactory 属性为 ConfigurableBeanFactory 对象时则同时会向其中注册依赖映射同时返回获取到对象;而在 beanFactory 属性中没有名为 beanName 属性的对象、isDefaultName 属性且 mappedName 属性为空时直接抛出异常,若不满足上述条件则使用当前对象与 requestingBeanName 参数执行 getResource 方法获取对象并返回。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private class EjbRefElement extends LookupElement {@Overrideprotected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {if (StringUtils.hasLength(this.beanName)) {if (beanFactory != null && beanFactory.containsBean(this.beanName)) {Object bean = beanFactory.getBean(this.beanName, this.lookupType);if (requestingBeanName != null && beanFactory instanceof ConfigurableBeanFactory) {((ConfigurableBeanFactory) beanFactory).registerDependentBean(this.beanName, requestingBeanName);}return bean;}else if (this.isDefaultName && !StringUtils.hasLength(this.mappedName)) {throw new NoSuchBeanDefinitionException(this.beanName,"Cannot resolve 'beanName' in local BeanFactory. Consider specifying a general 'name' value instead.");}}return getResource(this, requestingBeanName);}}
}
8 LookupDependencyDescriptor 内部类
8.1 变量及构造方法
8.1.1 类变量
LookupDependencyDescriptor 类中只有一个保存查询类型的 lookupType 属性;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private static class LookupDependencyDescriptor extends DependencyDescriptor {private final Class<?> lookupType;}
}
8.1.2 构造方法
LookupDependencyDescriptor 类拥有两个不同的构造方法,其分别使用 Field 或 Method 对象创建本对象,在创建过程中,首先使用参数执行父类的构造方法同时将 lookupType 属性初始化为 lookupType 参数;
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private static class LookupDependencyDescriptor extends DependencyDescriptor {public LookupDependencyDescriptor(Field field, Class<?> lookupType) {super(field, true);this.lookupType = lookupType;}public LookupDependencyDescriptor(Method method, Class<?> lookupType) {super(new MethodParameter(method, 0), true);this.lookupType = lookupType;}}
}
8.2 类方法
8.2.1 getDependencyType 方法
LookupDependencyDescriptor 类只重写了 getDependencyType 方法,其直接返回 lookupType 属性值。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessorimplements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {private static class LookupDependencyDescriptor extends DependencyDescriptor {@Overridepublic Class<?> getDependencyType() {return this.lookupType;}}
}
七 EventListenerMethodProcessor 类
1 属性及构造方法
1.1 类变量
EventListenerMethodProcessor 拥有 5 个不同的属性,其中 applicationContext 与 beanFactory 属性分别保存的是当前所使用的上下文及使用的对象工厂、eventListenerFactories 属性保存的是当前所使用的时间监听器工厂列表、evaluator 属性则是事件表达式计算器及用于保存为使用注解修饰的 Class 对象 set 集合的 nonAnnotatedClasses 属性;
public class EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {@Nullableprivate ConfigurableApplicationContext applicationContext;@Nullableprivate ConfigurableListableBeanFactory beanFactory;@Nullableprivate List<EventListenerFactory> eventListenerFactories;private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator();private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
}
2 类方法
2.1 setApplicationContext 方法
setApplicationContext 方法首先验证了 applicationContext 参数是否为 ConfigurableApplicationContext 对象,通过后将该参数转换为 ConfigurableApplicationContext 对象并使用该值来初始化 applicationContext 属性;
public class EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext,"ApplicationContext does not implement ConfigurableApplicationContext");this.applicationContext = (ConfigurableApplicationContext) applicationContext;}
}
2.2 postProcessBeanFactory 方法
postProcessBeanFactory 方法首先将 beanFactory 属性更新为 beanFactory 参数值,同时将其中所有的 EventListenerFactory 对象排好序然后保存到 eventListenerFactories 属性之中;
public class EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {this.beanFactory = beanFactory;Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);List<EventListenerFactory> factories = new ArrayList<>(beans.values());AnnotationAwareOrderComparator.sort(factories);this.eventListenerFactories = factories;}
}
2.3 afterSingletonsInstantiated 方法
afterSingletonsInstantiated 方法对 beanFactory 中的所有对象进行遍历,使用 processBean 方法对其中的非作用域代理对象进行处理;
public class EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {@Overridepublic void afterSingletonsInstantiated() {ConfigurableListableBeanFactory beanFactory = this.beanFactory;Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");String[] beanNames = beanFactory.getBeanNamesForType(Object.class);for (String beanName : beanNames) {if (!ScopedProxyUtils.isScopedTarget(beanName)) {Class<?> type = null;try {type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);}}if (type != null) {if (ScopedObject.class.isAssignableFrom(type)) {try {Class<?> targetClass = AutoProxyUtils.determineTargetClass(beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));if (targetClass != null) {type = targetClass;}}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);}}}try {processBean(beanName, type);}catch (Throwable ex) {throw new BeanInitializationException("Failed to process @EventListener " +"annotation on bean with name '" + beanName + "'", ex);}}}}}
}
processBean 方法在 nonAnnotatedClasses 属性不包含 targetType 参数或其不可能存在使用 EventListener 注解修饰的方法时直接返回;否则获取 targetType 类中所有使用 EventListener 注解修饰的方法对象,若不存在则将 targetType 参数值添加到 nonAnnotatedClasses 属性中并返回,随后将方法中存在 eventListenerFactories 属性支持的元素使用 aop 进行代理并添加到 applicationContext 属性中;
public class EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {private void processBean(final String beanName, final Class<?> targetType) {if (!this.nonAnnotatedClasses.contains(targetType) &&AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&!isSpringContainerClass(targetType)) {Map<Method, EventListener> annotatedMethods = null;try {annotatedMethods = MethodIntrospector.selectMethods(targetType,(MethodIntrospector.MetadataLookup<EventListener>) method ->AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));}catch (Throwable ex) {if (logger.isDebugEnabled()) {logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);}}if (CollectionUtils.isEmpty(annotatedMethods)) {this.nonAnnotatedClasses.add(targetType);if (logger.isTraceEnabled()) {logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());}}else {ConfigurableApplicationContext context = this.applicationContext;Assert.state(context != null, "No ApplicationContext set");List<EventListenerFactory> factories = this.eventListenerFactories;Assert.state(factories != null, "EventListenerFactory List not initialized");for (Method method : annotatedMethods.keySet()) {for (EventListenerFactory factory : factories) {if (factory.supportsMethod(method)) {Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));ApplicationListener<?> applicationListener =factory.createApplicationListener(beanName, targetType, methodToUse);if (applicationListener instanceof ApplicationListenerMethodAdapter) {((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);}context.addApplicationListener(applicationListener);break;}}}if (logger.isDebugEnabled()) {logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +beanName + "': " + annotatedMethods);}}}}
}
isSpringContainerClass 判断类是否为未使用 Component 注解修饰的 org.springframework 包中类。
public class EventListenerMethodProcessorimplements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {private static boolean isSpringContainerClass(Class<?> clazz) {return (clazz.getName().startsWith("org.springframework.") &&!AnnotatedElementUtils.isAnnotated(ClassUtils.getUserClass(clazz), Component.class));}
}
七 EventListenerFactory 对象
1 EventListenerFactory 接口
EventListenerFactory 接口向外提供了 ApplicationListener 对象的创建功能,supportsMethod 方法判断是否支持指定方法对象,createApplicationListener 方法用于创建 ApplicationListener 对象;
public interface EventListenerFactory {boolean supportsMethod(Method method);ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method);}
2 DefaultEventListenerFactory 类
2.1 类属性
DefaultEventListenerFactory 类只有一个用于排序的 order 属性,其值为 LOWEST_PRECEDENCE,表明其为最后执行的工厂对象;
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {private int order = LOWEST_PRECEDENCE;public void setOrder(int order) {this.order = order;}@Overridepublic int getOrder() {return this.order;}}
2.2 类方法
2.2.1 supportsMethod 方法
supportsMethod 方法直接返回 true,表明其支持任何 EventListener 注解修饰的方法对象;
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {@Overridepublic boolean supportsMethod(Method method) {return true;}
}
2.2.2 createApplicationListener 方法
createApplicationListener 方法直接使用所有入参值创建 ApplicationListenerMethodAdapter 对象并返回;
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {@Overridepublic ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {return new ApplicationListenerMethodAdapter(beanName, type, method);}
}
3 TransactionalEventListenerFactory 类
3.1 类属性
TransactionalEventListenerFactory 类也只有一个用于排序的 order 属性,其值为50;
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {private int order = 50;public void setOrder(int order) {this.order = order;}@Overridepublic int getOrder() {return this.order;}}
3.2 类方法
3.2.1 supportsMethod 方法
supportsMethod 方法直接返回 method 参数是否使用 TransactionalEventListener 注解进行修饰;
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {@Overridepublic boolean supportsMethod(Method method) {return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);}
}
3.2.2 createApplicationListener 方法
createApplicationListener 方法直接使用所有入参值创建 ApplicationListenerMethodTransactionalAdapter 对象并返回;
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {@Overridepublic ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method);}
}
4 ApplicationListenerMethodAdapter 类
4.1 属性与构造方法
4.1.1 常量
ApplicationListenerMethodAdapter 类只有标识当前是否拥有 org.reactivestreams.Publisher 类的 reactiveStreamsPresent 常量;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private static final boolean reactiveStreamsPresent = ClassUtils.isPresent("org.reactivestreams.Publisher", ApplicationListenerMethodAdapter.class.getClassLoader());}
4.1.2 类变量
ApplicationListenerMethodAdapter 类拥有保存对象名的 beanName 属性、保存目标非桥接方法对象的 method 属性、保存的 AOP 代理方法对象的 targetMethod 属性、使用 targetMethod 属性与目标类创建的 AnnotatedElementKey 对象的 methodKey 方法、declaredEventTypes 属性保存的是监听 ResolvableType 对象 List 集合对象、condition 属性保存的则是 EventListener 注解的 condition 属性,即激发条件、保存监听起顺序的 order 属性与分别保存上下文对象与表达式执行器对象的 applicationContext 与 evaluator 属性;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private final String beanName;private final Method method;private final Method targetMethod;private final AnnotatedElementKey methodKey;private final List<ResolvableType> declaredEventTypes;@Nullableprivate final String condition;private final int order;@Nullableprivate ApplicationContext applicationContext;@Nullableprivate EventExpressionEvaluator evaluator;@Overridepublic boolean supportsSourceType(@Nullable Class<?> sourceType) {return true;}@Overridepublic int getOrder() {return this.order;}protected Object getTargetBean() {Assert.notNull(this.applicationContext, "ApplicationContext must no be null");return this.applicationContext.getBean(this.beanName);}@Nullableprotected String getCondition() {return this.condition;}
}
4.1.3 构造方法
在 ApplicationListenerMethodAdapter 对象创建过程中,首先将 beanName 属性初始化为 beanName 参数值,随后将非桥接方法与代理方法分别保存到 method 与 targetMethod 属性中,随后使用 targetMethod 属性与 targetClass 参数创建 AnnotatedElementKey 对象为 methodKey 属性赋值,随后使用 targetMethod 的 EventListener 注解属性为 declaredEventTypes 与 condition 属性赋值,最后对 order 属性进行初始化。
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {this.beanName = beanName;this.method = BridgeMethodResolver.findBridgedMethod(method);this.targetMethod = (!Proxy.isProxyClass(targetClass) ?AopUtils.getMostSpecificMethod(method, targetClass) : this.method);this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);this.condition = (ann != null ? ann.condition() : null);this.order = resolveOrder(this.targetMethod);}}
resolveDeclaredEventTypes 方法在 method 参数拥有多于一个参数时直接抛出异常,在 ann 参数不为空且其 classes 属性值不为空时,将其所有元素转换为 ResolvableType 对象 list 集合并返回;否则在 method 参数只有一个参数时返回该参数转换的单 ResolvableType 对象 list 集合并返回,否则直接抛出异常;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private static List<ResolvableType> resolveDeclaredEventTypes(Method method, @Nullable EventListener ann) {int count = method.getParameterCount();if (count > 1) {throw new IllegalStateException("Maximum one parameter is allowed for event listener method: " + method);}if (ann != null) {Class<?>[] classes = ann.classes();if (classes.length > 0) {List<ResolvableType> types = new ArrayList<>(classes.length);for (Class<?> eventType : classes) {types.add(ResolvableType.forClass(eventType));}return types;}}if (count == 0) {throw new IllegalStateException("Event parameter is mandatory for event listener method: " + method);}return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));}}
resolveOrder 方法在 method 拥有 Order 注解时直接返回其 value 属性值,否则直接返回 0;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private static int resolveOrder(Method method) {Order ann = AnnotatedElementUtils.findMergedAnnotation(method, Order.class);return (ann != null ? ann.value() : 0);}
}
4.2 类方法
4.2.1 init 方法
init 方法直接将 applicationContext 与 evaluator 属性更新为对应参数值;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {void init(ApplicationContext applicationContext, EventExpressionEvaluator evaluator) {this.applicationContext = applicationContext;this.evaluator = evaluator;}
}
4.2.2 onApplicationEvent 方法
onApplicationEvent 方法直接使用 event 参数执行 processEvent 方法;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {@Overridepublic void onApplicationEvent(ApplicationEvent event) {processEvent(event);}
}
processEvent 方法首先使用 resolveArguments 方法获取方法入参对象;并在使用 shouldHandle 方法通过条件验证后,调用 doInvoke 方法执行当前方法并在其结果不为 null 时进一步调用 handleResult 方法对结果进行处理;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {public void processEvent(ApplicationEvent event) {Object[] args = resolveArguments(event);if (shouldHandle(event, args)) {Object result = doInvoke(args);if (result != null) {handleResult(result);}else {logger.trace("No result object given - no result to handle");}}}
}
resolveArguments 方法首先通过 getResolvableType 方法获取 declaredEventTypes 属性中与 event 参数匹配的元素对象,若不存在则直接返回 null;而在 method 属性没有任何参数时直接返回空 Object 对象数组,之后若 getResolvableType 获取到的元素不为 ApplicationEvent 对象且 event 参数为 PayloadApplicationEvent 对象时,在 event 的载荷为 getResolvableType 获取到的元素对应的对象时,则会将 event 的载荷包装为单元素 Object 对象数组并返回;否则直接将 event 参数封装为单元素 Object 对象数组并返回。
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {@Nullableprotected Object[] resolveArguments(ApplicationEvent event) {ResolvableType declaredEventType = getResolvableType(event);if (declaredEventType == null) {return null;}if (this.method.getParameterCount() == 0) {return new Object[0];}Class<?> declaredEventClass = declaredEventType.toClass();if (!ApplicationEvent.class.isAssignableFrom(declaredEventClass) &&event instanceof PayloadApplicationEvent) {Object payload = ((PayloadApplicationEvent<?>) event).getPayload();if (declaredEventClass.isInstance(payload)) {return new Object[] {payload};}}return new Object[] {event};}
}
getResolvableType 首先在 event 为 PayloadApplicationEvent 对象时,使用 payloadType 局部变量保存其泛型对象;随后查找 declaredEventTypes 属性中不为 ApplicationEvent 类但为 payloadType 对象父类或为 event 参数类型的元素并返回,未查询到时直接返回;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {@Nullableprivate ResolvableType getResolvableType(ApplicationEvent event) {ResolvableType payloadType = null;if (event instanceof PayloadApplicationEvent) {PayloadApplicationEvent<?> payloadEvent = (PayloadApplicationEvent<?>) event;ResolvableType eventType = payloadEvent.getResolvableType();if (eventType != null) {payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();}}for (ResolvableType declaredEventType : this.declaredEventTypes) {Class<?> eventClass = declaredEventType.toClass();if (!ApplicationEvent.class.isAssignableFrom(eventClass) &&payloadType != null && declaredEventType.isAssignableFrom(payloadType)) {return declaredEventType;}if (eventClass.isInstance(event)) {return declaredEventType;}}return null;}
}
shouldHandle 方法在 args 参数为 null 时直接返回 false,而在 condition 属性值为空时直接返回 true ;否则在通过对 evaluator 属性的非空验证后,返回该计算器对 condition 属性条件表达式进行判断并返回判断结果;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {if (args == null) {return false;}String condition = getCondition();if (StringUtils.hasText(condition)) {Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");return this.evaluator.condition(condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);}return true;}
}
doInvoke 方法在 beanName 对应对象为 null 时直接返回 null,否则使用 args 参数执行目标对象的 method 属性方法并返回;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {@Nullableprotected Object doInvoke(Object... args) {Object bean = getTargetBean();if (bean.equals(null)) {return null;}ReflectionUtils.makeAccessible(this.method);try {return this.method.invoke(bean, args);}catch (IllegalArgumentException ex) {assertTargetBean(this.method, bean, args);throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (IllegalAccessException ex) {throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);}catch (InvocationTargetException ex) {Throwable targetException = ex.getTargetException();if (targetException instanceof RuntimeException) {throw (RuntimeException) targetException;}else {String msg = getInvocationErrorMessage(bean, "Failed to invoke event listener method", args);throw new UndeclaredThrowableException(targetException, msg);}}}
}
handleResult 方法在 reactiveStreamsPresent 属性为 true 时,会调用 ReactiveResultHandler 对象的 subscribeToPublisher 方法进一步发布其结果,在其结果为 true 时直接返回,在 result 参数为 CompletionStage 对象时,在其异步执行完毕后,若 ex 为 null 且 event 结果不为 null 时进一步调用 publishEvent 发布事件,在 result 为 ListenableFuture 对象时,则会将 publishEvents 方法加入其回调流程中,否则直接调用 publishEvents 进一步发布事件;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {protected void handleResult(Object result) {if (reactiveStreamsPresent && new ReactiveResultHandler().subscribeToPublisher(result)) {if (logger.isTraceEnabled()) {logger.trace("Adapted to reactive result: " + result);}}else if (result instanceof CompletionStage) {((CompletionStage<?>) result).whenComplete((event, ex) -> {if (ex != null) {handleAsyncError(ex);}else if (event != null) {publishEvent(event);}});}else if (result instanceof ListenableFuture) {((ListenableFuture<?>) result).addCallback(this::publishEvents, this::handleAsyncError);}else {publishEvents(result);}}
}
publishEvents 方法在 result 参数为数组或 Collection 集合时,逐一调用 publishEvent 方法发布其中元素,否则直接调用 publishEvent 方法直接发布 result 参数对象;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private void publishEvents(Object result) {if (result.getClass().isArray()) {Object[] events = ObjectUtils.toObjectArray(result);for (Object event : events) {publishEvent(event);}}else if (result instanceof Collection<?>) {Collection<?> events = (Collection<?>) result;for (Object event : events) {publishEvent(event);}}else {publishEvent(result);}}private void publishEvent(@Nullable Object event) {if (event != null) {Assert.notNull(this.applicationContext, "ApplicationContext must not be null");this.applicationContext.publishEvent(event);}}
}
4.3 内部类
4.3.1 ReactiveResultHandler 类
ReactiveResultHandler 类只有一个 subscribeToPublisher 方法,该方法首先从 ReactiveAdapterRegistry 中获取与 result 参数类型匹配的 ReactiveAdapter 适配器对象,在其不为 null 时,调用其 toPublisher 方法将 result 参数适配到 Reactive Streams 流中来订阅 EventPublicationSubscriber 对象;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private class ReactiveResultHandler {public boolean subscribeToPublisher(Object result) {ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(result.getClass());if (adapter != null) {adapter.toPublisher(result).subscribe(new EventPublicationSubscriber());return true;}return false;}}
}
4.3.2 EventPublicationSubscriber 类
EventPublicationSubscriber 类实现了 onSubscribe、onNext、onError 及 onComplete 方法,onSubscribe 方法直接调用 s 参数的 request 方法为其设置最大整型值,onNext 方法直接调用 publishEvents 方法,onError 方法则是直接调用 handleAsyncError 方法及 onComplete 方法没有任何实现;
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {private class EventPublicationSubscriber implements Subscriber<Object> {@Overridepublic void onSubscribe(Subscription s) {s.request(Integer.MAX_VALUE);}@Overridepublic void onNext(Object o) {publishEvents(o);}@Overridepublic void onError(Throwable t) {handleAsyncError(t);}@Overridepublic void onComplete() {}}
}
相关文章:
Spring 源码学习(七)——注解后处理器-2
五 InitDestroyAnnotationBeanPostProcessor 类 1 属性 InitDestroyAnnotationBeanPostProcessor 类用于处理初始化与销毁注解;其中第一个属性为用于标识初始化方法与销毁方法注解类型的 initAnnotationType 与 destroyAnnotationType 属性、还有一个用于标识执行顺…...
即梦(Dreamina)技术浅析(一)
1.技术架构与核心组件 2.生成模型的具体实现 3.多模态融合技术 4.训练数据与模型优化 5.用户交互与创作流程 6.技术挑战与解决方案 7.未来发展方向 1. 技术架构与核心组件 即梦的技术架构可以分为以下几个核心组件: 1.1 前端用户界面(UI) 功能模块: 文字输入框:用…...
Spring MVC(二)
介绍 Cookie 与 Session Session 类似哈希表,存储了一些键值对结构,Key 就是 SessionID,Vaule 就是用户信息,客户端发起会话的时候,服务器一旦接收,就会创建会话【也就是 Session】,通过 Sessi…...
java求职学习day15
多线程 1 基本概念 1.1 程序和进程的概念 (1)程序 - 数据结构 算法,主要指存放在硬盘上的可执行文件。 (2)进程 - 主要指运行在内存中的可执行文件。 (3)目前主流的操作系统都支持多进程&a…...
Typesrcipt泛型约束详细解读
代码示例: // 如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性 (() > {// 定义一个接口,用来约束将来的某个类型中必须要有length这个属性interface ILength{// 接口中有一个属性lengthlength:number}function getLen…...
[操作系统] 进程地址空间管理
虚拟地址空间的初始化 缺页中断 缺页中断的概念 缺页中断(Page Fault Interrupt) 是指当程序访问的虚拟地址在页表中不存在有效映射(即该页未加载到内存中)时,CPU 会发出一个中断信号,请求操作系统加载所…...
【fly-iot飞凡物联】(20):2025年总体规划,把物联网整套技术方案和实现并落地,完成项目开发和课程录制。
前言 fly-iot飞凡物联专栏: https://blog.csdn.net/freewebsys/category_12219758.html 1,开源项目地址进行项目开发 https://gitee.com/fly-iot/fly-iot-platform 完成项目开发,接口开发。 把相关内容总结成文档,并录制课程。…...
14-6-1C++STL的list
(一)list容器的基本概念 list容器简介: 1.list是一个双向链表容器,可高效地进行插入删除元素 2.list不可以随机存取元素,所以不支持at.(pos)函数与[ ]操作符 (二)list容器头部和尾部的操作 list对象的默…...
vue2和vue3指令
Vue 2 和 Vue 3 的指令系统非常相似,但 Vue 3 在指令方面进行了优化和扩展。以下是 Vue 2 和 Vue 3 中指令的对比: 1. 通用指令 这些指令在 Vue 2 和 Vue 3 中都可以使用,功能一致: 指令说明v-bind绑定 HTML 属性或组件 propsv-…...
求整数的和与均值(信息学奥赛一本通-1061)
【题目描述】 读入n(1≤n≤10000)个整数,求它们的和与均值。 【输入】 输入第一行是一个整数n,表示有n个整数。 第2~n1行每行包含1个整数。每个整数的绝对值均不超过10000。 【输出】 输出一行,先输出和,再输出平均值(保留到小数点…...
CodeForces 611:New Year and Domino ← 二维前缀和
【题目来源】 https://codeforces.com/contest/611/problem/C 【题目描述】 They say "years are like dominoes, tumbling one after the other". But would a year fit into a grid? I dont think so. Limak is a little polar bear who loves to play. He has r…...
【ROS2】RViz2界面类 VisualizationFrame 详解
1、简述 VisualizationFrame 继承自 QMainWindow 和 WindowManagerInterface; 窗口顶部是常规布局:菜单栏 和 工具栏 窗口中心是 RenderPanel,用来渲染3D画面 周围是dock区域,包括:DisplaysPanel、ViewsPanel、TimePanel、SelectionPanel 和 ToolPropertiesPanel Windo…...
梯度下降法 (Gradient Descent) 算法详解及案例分析
梯度下降法 (Gradient Descent) 算法详解及案例分析 目录 梯度下降法 (Gradient Descent) 算法详解及案例分析1. 引言2. 梯度下降法 (Gradient Descent) 算法原理2.1 基本概念2.2 算法步骤2.3 梯度下降法的变种3. 梯度下降法的优势与局限性3.1 优势3.2 局限性4. 案例分析4.1 案…...
【Flutter】旋转元素(Transform、RotatedBox )
这里写自定义目录标题 Transform旋转元素可以改变宽高约束的旋转 - RotatedBox Transform旋转元素 说明:Transform旋转操作改变了元素的方向,但并没有改变它的布局约束。因此,虽然视觉上元素看起来是旋转了,但它仍然遵循原始的宽…...
大数运算之C语言实现
一、 前言 在我们代码编程过程中,我们经常需要处理各种规模的数值。从日常工作中的一些简单算术在到科学研究中的复杂计算,数字无处不在。然而,当数值变的异常庞大时,就需要用到大数运算来进行实现。本文我们将介绍大数运算的基本…...
三高“高性能、高并发、高可靠”系统架构设计系列文章
目录 高并发系统的艺术:如何在流量洪峰中游刃有余 《数据密集型应用系统设计》读后感与高并发高性能实践案例 系统稳定性与高可用保障的几种思路 软件系统限流的底层原理解析 技术解决方案调研 延迟队列调研 重试调研 异步回调调研 分库分表调研 分布式事…...
Java设计模式 十八 状态模式 (State Pattern)
状态模式 (State Pattern) 状态模式是一种行为型设计模式,它允许对象在其内部状态改变时改变其行为。状态模式让一个对象在其状态改变时,其行为也随之改变,看起来就像是改变了对象的类。通过将状态的变化封装到不同的状态对象中,…...
Django创建纯净版项目并启动
1.Django的基本目录结构 2. 创建app项目 python manage.py startapp user# python manage.py 是固定的,代表python脚本,主要用于django中的项目管理 # startapp 创建app # user 你的app名字,也就是功能模块名称3.数据库 进入settings.…...
[b01lers2020]Life on Mars1
打开题目页面如下 看了旁边的链接,也没有什么注入点,是正常的科普 利用burp suite抓包,发现传参 访问一下 http://5edaec92-dd87-4fec-b0e3-501ff24d3650.node5.buuoj.cn:81/query?searchtharsis_rise 接下来进行sql注入 方法一…...
element-plus 的table section如何实现单选
如果是单选那么全新的按钮应该隐藏或者不可编辑的状态。但是我没找到改变成不可编辑的方法,只能采取隐藏 <template><!-- 注意要包一层div根元素,否则css样式可能会不生效,原因不详 --><div><el-table ref"proTab…...
利用Qt5.15.2编写Android程序时遇到的问题及解决方法
文章目录 背景1.文件读写 背景 目前我用的是Qt5.15.2来编写Qt程序,环境的配置看我这篇文章【Qt5.15.2配置Android开发环境】 项目中的一些配置的截图: 1.文件读写 假如直接用 QFileDialog::getExistingDirectory来获取路径的话,会得到类…...
奇怪的单词(快速扩张200个单词)
这是一些非常奇怪的单词: screw n.螺丝;螺丝钉 screwdriver n.起子,螺丝刀,改锥 copulation n.连接 copulate a.配合的 bonk n.撞击;猛击 v.轻击;碰撞ebony n.黑檀couple n.夫妇blonde n.金发女郎intimacy…...
three.js+WebGL踩坑经验合集(4.1):THREE.Line2的射线检测问题(注意本篇说的是Line2,同样也不是阈值方面的问题)
上篇大家消化得如何了? 笔者说过,1级编号不同的两篇博文相对独立,所以这里笔者还是先给出完整代码,哪怕跟(3)没有太大区别。 这里我们把线的粗细调成5(排除难选中的因素)ÿ…...
postgresql根据主键ID字段分批删除表数据
生产环境针对大表的处理相对比较麻烦。 方案1、直接truncate,可能会遇到系统卡主的情况,因为truncate的过程中会对表进行加锁,会导致数据不能正常的写入 方案2、创建一个同结构的表结构,rename旧表,不停业务rename表担…...
NIO 和 Netty 在 Spring Boot 中的集成与使用
Netty到底是个啥,有啥子作用 1. Netty 的本质:对 NIO 的封装 NIO 的原生问题: Java 的 NIO 提供了非阻塞 I/O 和多路复用机制,但其使用较为复杂(如 Selector、Channel、Buffer 的配置和管理)。开发者需要自…...
【AI论文】Sigma:对查询、键和值进行差分缩放,以实现高效语言模型
摘要:我们推出了Sigma,这是一个专为系统领域设计的高效大型语言模型,其独特之处在于采用了包括DiffQKV注意力机制在内的新型架构,并在我们精心收集的系统领域数据上进行了预训练。DiffQKV注意力机制通过根据查询(Q&…...
ThinkPHP 8请求处理-获取请求对象与请求上下文
【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用Composer初始化ThinkPHP 8应用_thinkphp8 compos…...
【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等
【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 目录 【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 优势 适用场景 项目结构 关键代码 优势 消除 switch:将分支逻辑分散到独立的策略类中。 开闭原则:新增类型只需添加新的 TypeHa…...
Pyecharts之词云图、面积图与堆叠面积图
在数据可视化的精彩世界里,我们可以运用各种各样的图表来展现数据的魅力,帮助我们更好地理解和分析数据。Pyecharts 作为一款功能强大的数据可视化工具,为我们提供了丰富的图表类型,今天我们将深入探讨词云图、面积图和堆叠面积图…...
SpringBoot3+Vue3开发学生选课管理系统
功能介绍 分三个角色登录:学生登录,老师登录,教务管理员登录,不同用户功能不同! 1.学生用户功能 选课记录,查看选课记录,退选。选课管理,进行选课。通知管理,查看通知消…...
71.在 Vue 3 中使用 OpenLayers 实现按住 Shift 拖拽、旋转和缩放效果
前言 在前端开发中,地图功能是一个常见的需求。OpenLayers 是一个强大的开源地图库,支持多种地图源和交互操作。本文将介绍如何在 Vue 3 中集成 OpenLayers,并实现按住 Shift 键拖拽、旋转和缩放地图的效果。 实现效果 按住 Shift 键&#…...
Mybatis——sql映射文件中的增删查改
映射文件内的增删查改 准备工作 准备一张数据表,用于进行数据库的相关操作。新建maven工程, 导入mysql-connector-java和mybatis依赖。新建一个实体类,类的字段要和数据表的数据对应编写接口编写mybatis主配置文件 public class User {priva…...
Git进阶笔记系列(01)Git核心架构原理 | 常用命令实战集合
读书笔记:卓越强迫症强大恐惧症,在亲子家庭、职场关系里尤其是纵向关系模型里,这两种状态很容易无缝衔接。尤其父母对子女、领导对下属,都有望子成龙、强将无弱兵的期望,然而在你的面前,他们才是永远强大的…...
立创开发板入门ESP32C3第八课 修改AI大模型接口为deepseek3接口
#原代码用的AI模型是minimax的API接口,现在试着改成最热门的deepseek3接口。# 首先按理解所得,在main文件夹下,有minimax.c和minimax.h, 它们是这个API接口的头文件和实现文件,然后在main.c中被调用。所以我们一步步更改。 申请…...
【云安全】云原生-Docker(五)容器逃逸之漏洞利用
漏洞利用逃逸 通过漏洞利用实现逃逸,主要分为以下两种方式: 1、操作系统层面的内核漏洞 这是利用宿主机操作系统内核中的安全漏洞,直接突破容器的隔离机制,获得宿主机的权限。 攻击原理:容器本质上是通过 Linux 的…...
为什么IDEA提示不推荐@Autowired❓️如果使用@Resource呢❓️
前言 在使用 Spring 框架时,依赖注入(DI)是一个非常重要的概念。通过注解,我们可以方便地将类的实例注入到其他类中,提升开发效率。Autowired又是被大家最为熟知的方式,但很多开发者在使用 IntelliJ IDEA …...
PHP:动态网站开发的强大引擎
在互联网技术日新月异的今天,PHP(Hypertext Preprocessor,超文本预处理器)作为一种开源的服务器端脚本语言,凭借其灵活性和易用性,依然是构建动态网站和Web应用程序的首选之一。从简单的个人博客到复杂的企…...
Linux 目录操作详解
Linux目录操作详解 1. 获取当前工作目录1.1 getcwd()1.2 get_current_dir_name() 2. 切换工作目录2.1 chdir() 3. 创建和删除目录3.1 mkdir()3.2 rmdir() 4. 获取目录中的文件列表4.1 opendir() 打开目录4.2 readdir() 读取目录内容4.3 closedir() 关闭目录 5. dirent 结构体6.…...
IMX6ull项目环境配置
文件解压缩: .tar.gz 格式解压为 tar -zxvf .tar.bz2 格式解压为 tar -jxvf 2.4版本后的U-boot.bin移植进SD卡后,通过串口启动配置开发板和虚拟机网络。 setenv ipaddr 192.168.2.230 setenv ethaddr 00:04:9f:…...
redis实现lamp架构缓存
redis服务器环境下mysql实现lamp架构缓存 ip角色环境192.168.242.49缓存服务器Redis2.2.7192.168.242.50mysql服务器mysql192.168.242.51web端php ***默认已安装好redis,mysql 三台服务器时间同步(非常重要) # 下载ntpdate yum -y install…...
与机器学习相关的概率论重要概念的介绍和说明
概率论一些重要概念的介绍和说明 1、 试验 (1)试验是指在特定条件下,对某种方法、技术、设备或产品(即,事物)进行测试或验证的过程。 (2)易混淆的概念是,实验。实验&…...
深度学习 Pytorch 单层神经网络
神经网络是模仿人类大脑结构所构建的算法,在人脑里,我们有轴突连接神经元,在算法中,我们用圆表示神经元,用线表示神经元之间的连接,数据从神经网络的左侧输入,让神经元处理之后,从右…...
常用集合-数据结构-MySql
目录 java核心: 常用集合与数据结构: 单例集合: 双列集合: 线程安全的集合: ConcurrentHashMap集合: HashTable集合: CopyOnWriteArrayList集合: CopyOnWriteArraySet集合: ConcurrentLinkedQueue队列: ConcurrentSkipListMap和ConcurrentSkipListSet&…...
策略模式 - 策略模式的使用
引言 在软件开发中,设计模式是解决常见问题的经典解决方案。策略模式(Strategy Pattern)是行为型设计模式之一,它允许在运行时选择算法的行为。通过将算法封装在独立的类中,策略模式使得算法可以独立于使用它的客户端…...
【贪心算法】在有盾牌的情况下能通过每轮伤害的最小值(亚马逊笔试题)
思路: 采用贪心算法,先计算出来所有的伤害值,然后再计算每轮在使用盾牌的情况下能减少伤害的最大值,最后用总的伤害值减去能减少的最大值就是最少的总伤害值 public static long getMinimumValue(List<Integer> power, int…...
零基础Vue学习1——Vue学习前环境准备
目录 环境准备 创建Vue项目 项目目录说明 后续开发过程中常用命令 环境准备 安装开发工具:vscode、webstorm、idea都可以安装node:V22以上版本即可安装pnpm 不知道怎么安装的可以私信我教你方法 创建Vue项目 本地新建一个文件夹,之后在文件夹下打开…...
小游戏源码开发搭建技术栈和服务器配置流程
近些年各种场景小游戏开发搭建版本层出不穷,山东布谷科技拥有多年海内外小游戏源码开发经验,现为从事小游戏源码开发或游戏运营的朋友们详细介绍小游戏开发及服务器配置流程。 一、可以对接到app的小游戏是如何开发的 1、小游戏源码开发的需求分析: 明…...
【Rust自学】15.3. Deref trait Pt.2:隐式解引用转化与可变性
喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 15.3.1. 函数和方法的隐式解引用转化(Deref Coercion) 隐式解引用转化(Deref Coercion)是为…...
SQL-leetcode—1174. 即时食物配送 II
1174. 即时食物配送 II 配送表: Delivery ------------------------------------ | Column Name | Type | ------------------------------------ | delivery_id | int | | customer_id | int | | order_date | date | | customer_pref_delivery_date | date | -------------…...
css3 svg制作404页面动画效果HTML源码
源码介绍 css3 svg制作404页面动画效果HTML源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果 效果预览 源码如下 <!doctype html> <html> <head> <meta charse…...