spring基本使用(13)-springAOP的使用以及原理3 springAOP的自动代理创建器AbstractAutoProxyCreator
1、在前面一篇文章中我们讲了ProxyFactory、ProxyFacoryBean、AspectJProxyFactory三种用于创建代理类以及代理实例的非自动代理创建器,在Spring中其实也为我们提供了自动创建代理器。自动代理创建器的作用就是,自动解析到SpringIOC容器中的切面,根据切面的定义找到所有的Target目标类,在SpringIOC容器装载阶段为其织入切面定义中的增强。
2、非自动代理构建器 与 自动代理构建器的区别
非自动代理构建器使用繁琐,组要我们配置(目标类+配置增强)或者配置切面,在小型的项目中这样做倒是可以接受,但是大型项目中,如果需要配置的很多这种方式就比较鸡肋。而自动代理构建器我们只需要配置一个代理构建器就好,这个代理构建器就会解析SpringIOC容器中的所有切面定义,根据切面的定义找到所有的Target目标类,在SpringIOC容器装载阶段为其织入切面定义中的增强。
3、Spring中的自动代理创建器AbstractAutoProxyCreator 类图:
主要的实现有:
1、BeanNameAutoProxyCreator : 作用就是需要我们指定切面以及beanNames来生成代理类,跟非自动的比较类似,使用案例入下:这种方式相对于非自动代理构建器的却别就是目标类可以配置多个。
<bean id="dog" class="com.wzy.springstudy.aop.AutoProxyCreator.Dog"/>
<bean id="cat" class="com.wzy.springstudy.aop.AutoProxyCreator.Cat"/>
<bean id="sayHelloBeforeAdvice"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloBeforeAdvice"/>
<!--切面我们就定位目标类的run方法。-->
<bean id="sayHelloAdvisor"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloAdvisor"
p:advice-ref="sayHelloBeforeAdvice"/>
<!--配置BeanNameAutoProxyCreator 自动创建代理器-->
<bean id="beanNameAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames" value="sayHelloAdvisor"/>
<property name="proxyTargetClass" value="true"/>
<!--指定bean name-->
<property name="beanNames" value="cat,dog"/>
<property name="optimize" value="true"/>
</bean>
测试代码:
@Test
public void testBeanNameAutoProxyCreator(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context-aopAutoCreator.xml");
com.wzy.springstudy.aop.AutoProxyCreator.Cat cat = (Cat) ctx.getBean("cat");
cat.run();
}
输出:
哈喽。。。 输出此句表示增强织入成功
猫在跑。。。
2、DefaultAdvisorAutoProxyCreator : 默认的切面自动代理构造器,作用就是查找容器中所有类型为Advisor的切面,解析切面的目标类+增强然后进行代理生成。
<bean id="dog2" class="com.wzy.springstudy.aop.AutoProxyCreator.Dog"/>
<bean id="cat2" class="com.wzy.springstudy.aop.AutoProxyCreator.Cat"/>
<bean id="sayHelloDefaultAdvisorAutoProxyAdvice"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloBeforeAdvice"/>
<bean id="sayHahahaDefaultAdvisorAutoProxyAdvice"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaBeforeAdvice"/>
<bean id="regexpMethodPointcutAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="sayHelloDefaultAdvisorAutoProxyAdvice"/>
<!--RegexpMethodPointcutAdvisor 的ClassFilter 为TrueClassFilter.INSTANCE 默认匹配所有的类 此处配置patterns=.*run.* , 就表示为所有bena的以run结尾的方法进行增强。-->
<property name="patterns" value=".*run.*"/>
</bean>
<bean id="staticNamePointcutAdvisor"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaAdvisor">
<property name="advice" ref="sayHahahaDefaultAdvisorAutoProxyAdvice"/>
</bean>
<!--会容器中所有的Advisor织入到匹配的连接点中-->
<bean id="defaultAdvisorAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
测试代码:
@Test
public void testDefaultAdvisorAutoProxyCreator(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context-aopAutoCreator.xml");
com.wzy.springstudy.aop.AutoProxyCreator.Dog dog = (Dog) ctx.getBean("dog2");
dog.run();
}
输出:
哈喽。。。 织入成功
Hahaha... 织入成功
狗在跑。。。
3、AnnotationAwareAspectJAutoProxyCreator(重要指数5颗星) : AspectJ注解代理自动构建器,作用有两个:
1、完成查找容器中所有类型为Advisor的切面,解析切面的目标类+增强然后进行代理生成。没毛病AnnotationAwareAspectJAutoProxyCreator也能完成DefaultAdvisorAutoProxyCreator干的事情。
2、解析AspectJ定义的切面,然后根据切面定义将增强织入目标类中。
AnnotationAwareAspectJAutoProxyCreator是SpringAOP对AspectJ语法做支持的产物,下面介绍使用案例:
@Aspect切面定义:
@Component
@Aspect
public class AspectJTestBean {
@Before(value = "execution(* com.wzy.springstudy.aop.AutoProxyCreator.*.*())")
public void before(){
System.out.println("before");
}
}
我们还是使用之前定义的一些切面,只是将代理自动构造器修改为AnnotationAwareAspectJAutoProxyCreator
<bean id="dog2" class="com.wzy.springstudy.aop.AutoProxyCreator.Dog"/>
<bean id="cat2" class="com.wzy.springstudy.aop.AutoProxyCreator.Cat"/>
<bean id="sayHelloDefaultAdvisorAutoProxyAdvice"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHelloBeforeAdvice"/>
<bean id="sayHahahaDefaultAdvisorAutoProxyAdvice"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaBeforeAdvice"/>
<bean id="regexpMethodPointcutAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="sayHelloDefaultAdvisorAutoProxyAdvice"/>
<!--RegexpMethodPointcutAdvisor 的ClassFilter 为TrueClassFilter.INSTANCE 默认匹配所有的类此处配置patterns=.*run.* , 就表示为所有bena的以run结尾的方法进行增强。-->
<property name="patterns" value=".*run.*"/>
</bean>
<bean id="staticNamePointcutAdvisor"
class="com.wzy.springstudy.aop.AutoProxyCreator.SayHahahaAdvisor">
<property name="advice" ref="sayHahahaDefaultAdvisorAutoProxyAdvice"/>
</bean>
<!--会容器中所有的Advisor+Aspect语法定义的切面织入到匹配的连接点中-->
<bean id="annotationAwareAspectJAutoProxyCreator"
class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"
p:exposeProxy="true"/>
测试代码:
@Test
public void testDefaultAdvisorAutoProxyCreator(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context-aopAutoCreator.xml");
com.wzy.springstudy.aop.AutoProxyCreator.Dog dog = (Dog) ctx.getBean("dog2");
dog.run();
}
输出:
哈喽。。。
Hahaha...
before AspectJ定义的切面也织入成功
狗在跑。。。
使用 <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>来简化AnnotationAwareAspectJAutoProxyCreator配置。我们可以使用<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>来指定配置一个AnnotationAwareAspectJAutoProxyCreator实例。
4、AbstractAutoProxyCreator的实现原理分析:
从AbstractAutoProxyCreator的类图我们可以看出来AbstractAutoProxyCreator实现了InstantiationAwareBeanPostProcessor以及BeanPostProcessor接口,这个接口在Spring的bean生命周期中是非常重要的这个接口的方法列表如下:
4.1、InstantiationAwareBeanPostProcessor接口方法列表:
Ⅰ:Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException; 此方法在SpringIOC装载阶段执行,执行时机是bean实例化之前,也就是说在装载某个bean的时候,实例化bean之前会调用此方法,如果在此方法中生成代理并返回,那么容器中的bean对应的实例就是当前的代理实例。
Ⅱ:boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException; 此方法是在装载bean的时候执行,执行时机是bean实例化之后,返回的boolean类型,此时bean的实例已经实例化好了,我们可以在此处给bean进行装饰。
Ⅲ:PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException; 在给bean的属性进行赋值之前执行,我们可以在此处给bean的属性进行修改。
4.2、BeanPostProcessor接口方法列表:
Ⅰ:Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;此方法是在装载bean的阶段执行,执行时机是bean初始化之前执行,我们可以在此处进行bean的装饰或替换。比如根据原来的bean作为target来生成代理实例。
Ⅱ:Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;此方法也是在装载bean的阶段执行,执行时机是bean初始化之后执行,我们也可以在此处对bean实例进行装饰或替换。比如根据原来的bean作为target来生成代理实例。
4.3、那么我们的AbstractAutoProxyCreator是在那个方法里面进行代理类生成呢????
我们知道AOP的两个核心条件就是目标类target+连接点的方位信息(切点)以及需要织入的代码(Advice)。
我们代理肯定需要目标实例,这个是肯定的,但是SpringAOP提供了两个地方来进行代理实例生成,那就是InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 没看错,就是实例化之前,问题来了此时bean还没有实例化,怎么能够生成代理呢,查看其源码我们能够发现,原来SpronAOP允许我们给IOC容器中的bean配置一个TargetSource,如果配置了这个TargetSource,那么就会使用这个TargetSource来作为代理的目标类来进行代理生成。
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
if (beanName != null) {
如果给当前的bean配置了TargetSource实例,就使用当前的TargetSource作为代理目标类来进行代理生成。
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
获取到代理的拦截就是获取其切面。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
生成代理实例
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
上面的配置了TargetSource这种的方式不是很实用,因此SpringAOP还在BeanPostProcessor.postProcessAfterInitialization bean初始化之后来进行代理生成,这种方式才是最实用的,我们查看其源码:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
包装bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
包装bean的方法
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
找到切面从而得到增强,此处是一个抽象方法,其实现在之前列举的代理自动构建器中都有实现。
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
如果需要创建代理,那就创建代理类
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
AbstractAdvisorAutoProxyCreator抽象的切面代理自动构建器实现的getAdvicesAndAdvisorsForBean
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
获取到可用的切面列表
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
获取到可用的切面列表
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
获取SpringIOC容器中类型为Advisor的实例(会实例化+初始化所有的Advisor实例),
注意在AspectJAwareAdvisorAutoProxyCreator代理自动构建器中复写了
findCandidateAdvisors方法,复写的逻辑是先调用父类的此方法实现,然后在解析AspectJ的切面定义,将两者的合集作为最终的切面列表。
List<Advisor> candidateAdvisors = findCandidateAdvisors();
找出当前bean符合的切面,也就是使用切面的切点进行ClassFilter跟MethodMatcher来进行匹配,如果匹配成功,说明见当前bean需要织入当前切面的增强逻辑。
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
扩展满足条件的切面,在AspectJAwareAdvisorAutoProxyCreator中有实现,其他暂无
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
对切面进行排序(Ordered可定义切面顺序,此顺序就是切面的增强的执行顺序)
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
本文地址:https://blog.csdn.net/qq_34978129/article/details/107313274