Spring源码学习:ApplicationContextAwareProcessor和ignoredDependencyInterfaces学习


ApplicationContextAwareProcessor处理器继承自BeanPostProcessor,主要是对spring中实现自Aware接口的EnvironmentAware、ApplicationContextAware等进行后置处理,ignoredDependencyInterfaces主要是缓存需要在bean进行属性注入时需要忽略的接口

1 ApplicationContextAwareProcessor

1.1 注册时机

该后置处理器主要是在prepareBeanFactory中注册的

...
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
		//添加该后置处理器到beanPostProcessors中
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationStartup.class);
        ...

1.2 调用时机

调用时机同BeanPostProcessor,在bean初始化前后调用

...
if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			//调用是BeanNameAware、BeanClassLoaderAware和BeanFactoryAware的bean的处理器,实现名字、类加载器和工厂的设置(通过setXX)
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//执行初始化前操作postProcessBeforeInitialization,ApplicationContextAwareProcessor就是在这里调用
			wrappedBean = 			applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//执行bean初始化,如果有的话
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//初始化后操作
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
		...

1.3 执行逻辑

主要是针对实现了指定几个Aware接口的类进行统一的属性设置

@Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    	//具体的几个实现Aware接口的接口,这几个接口只有对应的setXX函数
        if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) {
            return bean;
        } else {
            AccessControlContext acc = null;
            if (System.getSecurityManager() != null) {
                acc = this.applicationContext.getBeanFactory().getAccessControlContext();
            }

            if (acc != null) {
                AccessController.doPrivileged(() -> {
                    this.invokeAwareInterfaces(bean);
                    return null;
                }, acc);
            } else {
            	//执行设置操作
                this.invokeAwareInterfaces(bean);
            }

            return bean;
        }
    }

设置操作如下

...
if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
        }

        if (bean instanceof ApplicationStartupAware) {
            ((ApplicationStartupAware)bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
        }
		//执行对应类的setXX函数实现对应的属性设置
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
        }
        ...

上述使用ApplicationContextAwareProcessor的实现了这几个特定的容器属性设置,而没有在populateBean中注入,主要是在我们prepareBeanFactory时使用了 ignoredDependencyInterfaces

2 ignoredDependencyInterfaces

2.1 作用

该缓存主要作用时忽略实现了如ApplicationContextAware接口中的setXX自动注入

public interface ApplicationContextAware extends Aware {
	//实现此接口的类在自动注入时会忽略setApplicationContext的注入也即使忽略对应参数ApplicationContext的注入
    void setApplicationContext(ApplicationContext var1) throws BeansException;
}

上述忽略之后就是由ApplicationContextAwareProcessor来实现属性感知的,应该是要确保bean对应注入的上下文,环境等确保是生成该bean的容器

2.2 添加时机

ApplicationContextAwareProcessor添加时机同都在prepareBeanFactory

... beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationStartup.class);
        ...

将对应的几个需要忽略的接口添加到缓存ignoredDependencyInterfaces中,后续进行属性填充时根据此缓存进行过滤

2.3 判断时机

populateBean时进行判断

//存在后置处理器:一个实例化后但在设置显式属性或自动装配发生之前的回调
if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
					//进行依赖属性检测,会对ignoredDependencyInterfaces和ignoredDependencyTypes进行过滤
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		//需要依赖检测,也会进行判断
		if (needsDepCheck) {
			if (filteredPds == null) {
				//过滤属性
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

filterPropertyDescriptorsForDependencyCheck核心流程(从给定的BeanWrapper中提取一组经过筛选的属性描述符,*排除被忽略的依赖类型或属性定义在被忽略的依赖接口上):

PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
		//如果之前已经存在缓存,不进行判断
		if (filtered == null) {
			//判断逻辑
			filtered = filterPropertyDescriptorsForDependencyCheck(bw);
			//是否需要缓存
			if (cache) {
				PropertyDescriptor[] existing =
						this.filteredPropertyDescriptorsCache.putIfAbsent(bw.getWrappedClass(), filtered);
				if (existing != null) {
					filtered = existing;
				}
			}
		}
		return filtered;

属性过滤判断,返回过滤后的类属性数组

protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
		//获取beanwrapper的属性数组
		List<PropertyDescriptor> pds = new ArrayList<>(Arrays.asList(bw.getPropertyDescriptors()));
		//进行判断过滤
		pds.removeIf(this::isExcludedFromDependencyCheck);
		return pds.toArray(new PropertyDescriptor[0]);
	}

isExcludedFromDependencyCheck这是java8中的语法糖,提高代码间接性,作为函数参数,这样用需要一个函数式接口来接收使用。

protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
		//主要判断逻辑
		return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||
				this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||
				AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
	}

isExcludedFromDependencyCheck判断

//排除CGLIB声明的属性
public static boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
		Method wm = pd.getWriteMethod();
		if (wm == null) {
			return false;
		}
		if (!wm.getDeclaringClass().getName().contains("$$")) {
			// Not a CGLIB method so it's OK.
			return false;
		}
		// It was declared by CGLIB, but we might still want to autowire it
		// if it was actually declared by the superclass.
		Class<?> superclass = wm.getDeclaringClass().getSuperclass();
		return !ClassUtils.hasMethod(superclass, wm);
	}

AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces)判断缓存中是否包含该类型,有的话排除。
AutowireUtils.isSetterDefinedInInterface判断

//返回给定bean属性的setter方法是否在任何给定接口中定义
public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class<?>> interfaces) {
		Method setter = pd.getWriteMethod();
		if (setter != null) {
			Class<?> targetClass = setter.getDeclaringClass();
			for (Class<?> ifc : interfaces) {
				//判断逻辑目标类是否是ignoredDependencyInterfaces接口中的实现类,并且接口中定义了该setXX方法,满足需要进行排除
				if (ifc.isAssignableFrom(targetClass) && ClassUtils.hasMethod(ifc, setter)) {
					return true;
				}
			}
		}
		return false;
	}

注意如果我们自定义了需要进行忽略的类,并不能忽略@Resource和@Autowired通过名字或者类型进行的注入,因为这两个在属性注入的时候是直接进行注入的不会考虑ignoredDependencyInterfaces,这个主要是针对在beans标签中使用default-autowire属性来注入依赖。

2.4 测试

定义A,C 和MyBeanFatoryPostProcessor

//A定义
public class A {
    C c;
    public C getC() {
        return c;
    }

    public void setC(C c) {
        this.c = c;
    }

    public void get(){
        System.out.println(c);
    }
}
//C定义
public class C {
    private String name = "123";
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//MyBeanFatoryPostProcessor定义
public class MyBeanFatoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        configurableListableBeanFactory.ignoreDependencyType(C.class);
    }
}

测试类如下:

ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("classpath:spring-1.xml");
        A bean = classPathXmlApplicationContext.getBean(A.class);
        bean.get();

其中spring-1.xml配置文件如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd"
       default-autowire="byType">
    <bean class="com.example.springboot1.ceshi.MyBeanFatoryPostProcessor"></bean>
    <bean id="a" class="com.example.springboot1.ceshi.A"></bean>
    <bean id="c" class="com.example.springboot1.ceshi.C"></bean>
</beans>

在我们注册了MyBeanFatoryPostProcess这个bean之后运行结果如下
结果为null
当我们注释掉configurableListableBeanFactory.ignoreDependencyType(C.class)运行如下


结果不为null
可以看出我们定义的MyBeanFatoryPostProcess添加了需要忽略的类型,所以后边注入属性的时候C为null,

参考文献:
打开BeanFactory ignoreDependencyInterface方法的正确姿势.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LamaxiyaFc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值