Loading

Spring系列-3.4 CommonAnnotationBeanPostProcessor

Spring版本:Spring 5.2.9.BUILD-SNAPSHOT

修改过部分源码,但不影响主体流程

概述

CommonAnnotationBeanPostProcessor负责解析@Resource@WebServiceRef@EJB@PostConstruct@PreDestroy注解,这几个注解都是定义在javax.*包下的注解,属于java中的注解。

类图

  • InstantiationAwareBeanPostProcessor

提供了bean实例化前后对bean的操作以及在属性赋值前,传递属性值的postProcessProperties方法。

  • InitDestroyAnnotationBeanPostProcessor

继承了DestructionAwareBeanPostProcessorMergedBeanDefinitionPostProcessor接口。

主要实现的方法有:postProcessMergedBeanDefinitionpostProcessBeforeInitializationpostProcessBeforeDestructionrequiresDestruction

  • MergedBeanDefinitionPostProcessor

用于处理合并后的BeanDefinition,在bean实例化后、属性赋值前回调。

  • DestructionAwareBeanPostProcessor

用于bean销毁前的回调。

注册时机

AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry, Object)

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		// 注册内部管理的用于处理JSR-250注解,例如@Resource,@PostConstruct,@PreDestroy的后置处理器bean
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

源码解析

postProcessMergedBeanDefinition

  1. 处理@PostConstruct@PreDestroy注解。

  2. 找出beanType所有被@Resource@WebServiceRef@EJB标记的字段和方法封装到InjectionMetadata中。

调用时机

doCreateBean -> applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName) -> bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName)

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		// 处理@PostConstruct和@PreDestroy注解
		super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
		//找出beanType所有被@Resource标记的字段和方法封装到InjectionMetadata中
		InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
		metadata.checkConfigMembers(beanDefinition);
	}

postProcessMergedBeanDefinition

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		// 调用方法获取生命周期元数据并保存
		LifecycleMetadata metadata = findLifecycleMetadata(beanType);
		// 验证相关方法
		metadata.checkConfigMembers(beanDefinition);
	}
  • 找到该类型的LifecycleMetadata数据,如果没有则会新增一份放到lifecycleMetadataCache中。

  • 从找到的LifecycleMetadata,执行其checkConfigMembers进行类型检查,将上一步找到的符合条件的方法,冗余一份到BeanDefinition中。

findLifecycleMetadata

	private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
		if (this.lifecycleMetadataCache == null) {
			// Happens after deserialization, during destruction...
			// 在bean销毁过程中,反序列化后调用
			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

	/**
	 * 构造生命周期元数据(解析带@PostConstruct和@PreDestroy注解的方法),当其构造完成后会将元数据缓存到lifecycleMetadataCache集合中并返回
	 * 此时就完成了相关方法(初始化方法和销毁方法)的扫描解析和缓存工作
	 *
	 * @param clazz
	 * @return
	 */
	private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
			return this.emptyLifecycleMetadata;
		}

		// 实例化后的回调方法(@PostConstruct)
		List<LifecycleElement> initMethods = new ArrayList<>();
		// 销毁前的回调方法(@PreDestroy)
		List<LifecycleElement> destroyMethods = new ArrayList<>();
		// 获取正在处理的目标类
		Class<?> targetClass = clazz;

		do {
			// 保存每一轮循环搜索到的相关方法
			final List<LifecycleElement> currInitMethods = new ArrayList<>();
			final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
			// 反射获取当前类中的所有方法并依次对其调用第二个参数的lambda表达式
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				// 当前方法的注解中包含initAnnotationType注解时(@PostConstruct)
				if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
					// 如果有,把它封装成LifecycleElement对象,存储起来
					LifecycleElement element = new LifecycleElement(method);
					// 将创建好的元素添加到集合中
					currInitMethods.add(element);
					if (logger.isTraceEnabled()) {
						logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
					}
				}
				// 当前方法的注解中包含destroyAnnotationType注解(PreDestroy)
				if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
					// 如果有,把它封装成LifecycleElement对象,存储起来
					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();
		}
		// 如果当前类存在父类且父类不为object基类则循环对父类进行处理
		while (targetClass != null && targetClass != Object.class);

		// 有一个不为空就封装一个LifecycleMetadata对象,否则就返回空的emptyLifecycleMetadata
		return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
				new LifecycleMetadata(clazz, initMethods, destroyMethods));
	}
  • 遍历该bean的所有方法。

  • 找到所有本类及父类的@PostConstruct注解@PreDestroy,并用他们构造LifecycleMetadata`并返回。

findResourceMetadata

	/**
	 * 解析@Resource注解
	 * @param beanName
	 * @param clazz
	 * @param pvs
	 * @return
	 */
	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.
		// 获取对应的bean名称作为缓存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);
		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对象放入injectionMetadataCache缓存中,缓存key为beanName,供后续方法从缓存中取出
					metadata = buildResourceMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}
  • injectionMetadataCache获取缓存的对象,如果没找到走下面的方法并缓存到injectionMetadataCache

buildResourceMetadata

	private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
		// 判断当前clazz是否是候选class
		if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		// 创建InjectedElement集合对象
		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			// 查询是否有webService,ejb,Resource的属性注解,但是不支持静态属性
			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");
					}
					//如果不想注入某一类型对象 可以将其加入ignoredResourceTypes中
					if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
						//字段会封装到ResourceElement
						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);
	}
  • 找到所有被@WebServiceRef@EJB@Resource注解修饰的字段(非静态)。

  • 找到所有被@WebServiceRef@EJB@Resource注解修饰的方法(非静态)。

  • 将上面两步找到的metadata数据,构造一个InjectionMetadata返回并最终存到injectionMetadataCache中。

@PostConstruct

调用时机

doCreateBean -> initializeBean -> applyBeanPostProcessorsBeforeInitialization -> postProcessBeforeInitialization -> invokeInitMethods -> invoke

  • 获取LifecycleMetadata缓存的方法数据。

  • 反射调用方法。

@PreDestroy

调用时机

ac.close() -> destroyBeans -> processor.postProcessBeforeDestruction(this.bean, this.beanName); -> invokeDestroyMethods -> invoke

调用方式与@PostConstruct差不多,都是通过BeanPostProcessor后置处理器前置、后置方法调用实现的。

@Resource

@Resource调用方式和@Autowired差不多。

@Autowired详细流程可参考Spring系列-3.3 AutowiredAnnotationBeanPostProcessor

调用时机

doCreateBean->populateBean->postProcessProperties

postProcessProperties

	/**
	 * 处理注入注解元数据
	 * @param pvs the property values that the factory is about to apply (never {@code null})
	 * @param bean the bean instance created, but whose properties have not yet been set
	 * @param beanName the name of the bean
	 * @return
	 */
	@Override
	public 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;
	}

findResourceMetadata

	/**
	 * 解析@Resource注解
	 * @param beanName
	 * @param clazz
	 * @param pvs
	 * @return
	 */
	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.
		// 获取对应的bean名称作为缓存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);
		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对象放入injectionMetadataCache缓存中,缓存key为beanName,供后续方法从缓存中取出
					metadata = buildResourceMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

buildResourceMetadata

	private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
		// 判断当前clazz是否是候选class
		if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		// 创建InjectedElement集合对象
		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

			// 查询是否有webService,ejb,Resource的属性注解,但是不支持静态属性
			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");
					}
					//如果不想注入某一类型对象 可以将其加入ignoredResourceTypes中
					if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
						//字段会封装到ResourceElement
						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);
	}

metadata.inject(bean, beanName, pvs);

	/**
	 * 遍历前面注册的InjectedElement,然后进行注入
	 * @param target
	 * @param beanName
	 * @param pvs
	 * @throws Throwable
	 */
	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) {
				if (logger.isTraceEnabled()) {
					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);
			}
		}
	}

element.inject(target, beanName, pvs);

		/**
		 * 进行属性或者方法注入,但是方法注入前会判断是否已经有设置值了,有设置就不会注入,直接返回
		 *
		 * Either this or {@link #getResourceToInject} needs to be overridden.
		 */
		protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
				throws Throwable {

			// 属性注入
			if (this.isField) {
				Field field = (Field) this.member;
				ReflectionUtils.makeAccessible(field);
				// 如果是使用字段形式的注入,getResourceToInject由子类@ResourceElement实现
				field.set(target, getResourceToInject(target, requestingBeanName));
			}
			else {
				// 此步骤检测如果bean已经显示的设置一个对象依赖引用则跳过使用setter方法再次赋值
				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();
				}
			}
		}
  • 这里判断是属性注入还是方法注入

getResourceToInject

		/**
		 * 首先判断注释元数据有没有@Lazy注解,有的话就创建一个代理类,内部是用AOP代理工厂做的
		 * @param target
		 * @param requestingBeanName
		 * @return
		 */
		@Override
		protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
			// 如果懒加载则使用一个代理对象
			return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
					getResource(this, requestingBeanName));
		}
  • 这里处理了@Lazy注解,判断注释元数据有没有@Lazy注解,有的话就创建一个代理类,内部是用AOP代理工厂做的
posted @ 2022-02-17 16:38  xmz_pc  阅读(79)  评论(0编辑  收藏  举报