1.写在前面
笔者在前面的几篇博客已经讲spring创建的Bean的过程中的实例化的Bean的过程,同时将调用Bean的后置处理器的前两次的情况已经讲完了。笔者今天继续往下讲。今天笔者这篇博客会讲spring第三次调用Bean后置处理器的情况。
2.Spring获取一个类中加了@Resource或@Autowired注解的过程
上篇博客已经讲完了几种创建Bean实例的过程,让我们继续讲剩下的代码,具体的代码如下:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//应用合并后的BeanDefinition后后置处理器
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//省略一部分代码
return exposedObject;
}
笔者在前面已经讲完了合并的过程以及spring创建Bean实例的过程,这次主要讲第三次调用Bean的后置处理器的过程。主要调用的applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
方法,具体的代码如下:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
可以发现调用的是Bean的后置处理器中postProcessMergedBeanDefinition
方法,同时这个Bean的后置处理器是MergedBeanDefinitionPostProcessor
类型,由于前面我们看过对应的代码,可以知道这儿查出来是6个后置处理器,如果加了动态代理的话,就会有7个后置处理器,我们来看下这些后置处理器的类的关系图吧!看看那些类是实现MergedBeanDefinitionPostProcessor
接口,具体的如下:
你会发现其中只有三个类(AutowiredAnnotationBeanPostProcessor
、CommonAnnotationBeanPostProcessor
、ApplicationListenerDetector
)三个类实现了MergedBeanDefinitionPostProcessor
接口所以会调用这三个类中的postProcessMergedBeanDefinition
的方法。
2.1CommonAnnotationBeanPostProcessor
先调用的是CommonAnnotationBeanPostProcessor
中的postProcessMergedBeanDefinition
的方法,具体的代码如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
从上面的调用的方法名,可以得出是找对应的注入的元数据,那么是找那些的注入元数据呢?看到是findResourceMetadata
,于是笔者大胆的猜测是找加了@Resource
注解的元数据,笔者再带大家看下InjectionMetadata
的一些属性,具体的如下:
可以发现存的是一个类对象,一个是injectedElements
对象,笔者再带读者看下InjectedElement
这个类中的属性
主要重要的是这两个类型,一个是Member
,一个是isField
,isField
这个类判断这个是不是一个属性,而Member是对应的实现类有Filed,Method等等,所以可以几乎可以存对应类的中的加了@Resource
注解的属性和方法的元数据了。既然有了这些前置的知识,那么我们写出如下的测试类,具体的的内容如下:
package com.ys.threeBeanPostProcessor;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class A {
@Resource
public B b;
@Resource
public void printC(C d) {
System.out.println(d);
}
}
然后开始我们的debug之旅,笔者直接带大家看postProcessMergedBeanDefinition
方法,具体的代码如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//调用父类的postProcessMergedBeanDefinition
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
//查找加了@Resource注解的元数据
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
可以发现先是调用了父类InitDestroyAnnotationBeanPostProcessor
的postProcessMergedBeanDefinition
方法,具体的代码如下:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//查找生命周期的函数
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
查找的后的数据如下:
笔者带着大家来看下具体findLifecycleMetadata(beanType);
方法,具体代码如下:
//查找生命周期的方法
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
//这儿不会为空,因为配置已经解析完成了,所以这个集合中是有值的
if (this.lifecycleMetadataCache == null) {
// Happens after deserialization, during destruction...
return buildLifecycleMetadata(clazz);
}
// Quick check on the concurrent map first, with minimal locking.
//从缓存中获取,如果有就直接返回,如果没有就直接查找
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);
方法去构建生命周期的元数据。具体的代码如下:
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
//先排除PostConstruct,PreDestroy
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 -> {
//判断加了@PostConstruct注解,然后加到对应的集合中去
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);
}
}
//判断加了@PreDestroy注解,然后加到对应的集合中去
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));
}
上面的代码就是找这个类以及它的父类的所有的加了@PostConstruct
,@PreDestroy
注解的方法,同时存到指定的集合中去。最后put到lifecycleMetadataCache
集合中去,最后返回到原来代码执行的地方,就会调用findResourceMetadata(beanName, beanType, null);
方法,具体的代码如下:
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
// 获取缓存的key
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
// 先从缓存中取,如果有直接返回,没有继续查找
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//判断需不需要刷新,只要metadata等于null就需要刷新,这儿是需要刷新的
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
//双重检查
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
//开始构建加了@Resource注解的方法的元数据了
metadata = buildResourceMetadata(clazz);
//最后存到指定的缓存中
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
上面的代码经过一系列的判断后,最后调用buildResourceMetadata(clazz);
方法来构建对应的加了@Resource
注解的元数据,具体的代码如下:
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
//这儿会排除两个,一个是Resource,一个是WebServiceRef
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 -> {
//判断是否加了WebServiceRef注解
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));
}
//判断是否加@Resource注解
else if (field.isAnnotationPresent(Resource.class)) {
//如果是静态的直接报错
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
//同时要排除WebServiceRef类型的
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;
}
//判断这个方法是否加了@WebServiceRef注解
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));
}
//判断方法是否添加@Resource
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();
//如果参数的长度不等于1直接报错
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
//不是WebServiceRef类型
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
//如果这个方法是get或set开头就直接返回,如果不是就返回null
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);
}
上面遍历所有的属性和方法,判断是否加了@Resource注解,如果加了,这个方法的参数长度不等于1直接报错,如果这个方法是静态的话,也会抛出异常。如果是的话就添加到集合中去,同时如果这个方法的get或者set开头的话,pd的值就不空,最后put到缓存中去。最后调用了一下metadata.checkConfigMembers(beanDefinition);
具体的代码如下:
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);
if (logger.isTraceEnabled()) {
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
this.checkedElements = checkedElements;
}
上面的代码就是判断这些属性和方法是否已经存在在集合中,如果没有存在,就添加进去,如果有存在就直接不添加,为了防止重复注册Bean的情况发生。最后进行属性的注入的时候也会遍历这个集合checkedElements
。至此这个类情况已经讲完了。
2.2AutowiredAnnotationBeanPostProcessor
这个是时候会调用AutowiredAnnotationBeanPostProcessor
中的postProcessMergedBeanDefinition
方法,我们先写出如下的代码,具体的代码如下:
package com.ys.threeBeanPostProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class A {
@Autowired
public B b;
@Autowired
public void printC(C c) {
System.out.println(c);
}
}
笔者再来看下postProcessMergedBeanDefinition
方法,具体的代码如下:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
//这个方法和之前讲CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法中的一样,可以跳过,就是去除重复的属性和方法
metadata.checkConfigMembers(beanDefinition);
}
上面的代码,我们主要看的是findAutowiringMetadata(beanName, beanType, null);
方法,具体的代码如下:
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
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 = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
上面代码和前面的代码一样的,唯一的区别就是调用的方法不一样。我们需要查看buildAutowiringMetadata(clazz);
方法,具体的代码如下:
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
//排除不是@Autowired和@value
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//匹配属性
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//查找这个属性是否加了@Autowired注解
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
//是静态直接返回
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
//查看这个注解中require的值
boolean required = determineRequiredStatus(ann);
//最后添加到集合中去
currElements.add(new AutowiredFieldElement(field, required));
}
});
//匹配方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//获取对应的方法
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//查看方法上是否加了@Autowired注解
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//是静态的直接返回
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
//参数个数的长度等于0直接返回
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
//查看这个注解中require的值
boolean required = determineRequiredStatus(ann);
//这个值与set或get的方法有关,如果不是就返回null
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
//最后添加到集合中去
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);//遍历所有的父类
return InjectionMetadata.forElements(elements, clazz);
}
上面的代码比较简单,同样是遍历属性和方法,如果是属性的话,前提不是静态的才会添加到集合中,其次是方法,如果这个不是静态的同时参数的个数不等于0才会被添加到集合中去。至此这个AutowiredAnnotationBeanPostProcessor
的postProcessMergedBeanDefinition
的方法就讲完了
2.3ApplicationListenerDetector
再来看最后一个ApplicationListenerDetector
的postProcessMergedBeanDefinition
的方法,具体的代码如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//判断ApplicationListener可分配给A,很显然不成立,直接结束
if (ApplicationListener.class.isAssignableFrom(beanType)) {
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
至此这几个Bean后置处理器讲完了。
3.@Resource与@Autowired的区别
-
@Resource
注解是java提供的,@Autowired
注解是spring提供的。 -
@Resource
注解的解析是由CommonAnnotationBeanPostProcessor
类的postProcessMergedBeanDefinition
方法解析的,@Autowired
注解的解析是由AutowiredAnnotationBeanPostProcessor
的postProcessMergedBeanDefinition
的方法解析的。 -
@Resource
注解的属性或方法如果是static的,spring会抛出一个异常,而@Autowired
注解的属性或方法如果是static的,spring会直接跳过。 -
@Resource
注解的方法参数个数如果不等于1,spring会抛出一个异常,而@Autowired
注解的方法参数个数如果等于0,spring会直接跳过。 - 两者都可以加在属性或方法上,满足条件的属性会被填充进来,满足条件的方法会被调用。
4.写在最后
本篇博客主要讲了spring在创建bean的过程中,如何解析@Resource和@Autowired注解的,这些信息是为了后面做属性注入准备的。