Spring源码系列(十七)Spring创建Bean的过程(六)

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接口,具体的如下:

在这里插入图片描述

你会发现其中只有三个类(AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorApplicationListenerDetector)三个类实现了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,一个是isFieldisField这个类判断这个是不是一个属性,而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);
}

可以发现先是调用了父类InitDestroyAnnotationBeanPostProcessorpostProcessMergedBeanDefinition方法,具体的代码如下:

@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才会被添加到集合中去。至此这个AutowiredAnnotationBeanPostProcessorpostProcessMergedBeanDefinition的方法就讲完了

2.3ApplicationListenerDetector

再来看最后一个ApplicationListenerDetectorpostProcessMergedBeanDefinition的方法,具体的代码如下:

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的区别

  1. @Resource注解是java提供的,@Autowired注解是spring提供的。
  2. @Resource注解的解析是由CommonAnnotationBeanPostProcessor类的postProcessMergedBeanDefinition方法解析的,@Autowired注解的解析是由AutowiredAnnotationBeanPostProcessorpostProcessMergedBeanDefinition的方法解析的。
  3. @Resource注解的属性或方法如果是static的,spring会抛出一个异常,而@Autowired注解的属性或方法如果是static的,spring会直接跳过。
  4. @Resource注解的方法参数个数如果不等于1,spring会抛出一个异常,而@Autowired注解的方法参数个数如果等于0,spring会直接跳过。
  5. 两者都可以加在属性或方法上,满足条件的属性会被填充进来,满足条件的方法会被调用。

4.写在最后

本篇博客主要讲了spring在创建bean的过程中,如何解析@Resource和@Autowired注解的,这些信息是为了后面做属性注入准备的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值