一、AOP的配置使用
1、AOP入口
通过扫描注解@EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)注册了AOP 入口类,具体看看注解里面的@Import(AspectJAutoProxyRegistrar.class)
/*
* TODO 开启注解AOP
* 替代了:<aop:aspectj-autoproxy/>
* */
@Service
@EnableAspectJAutoProxy(proxyTargetClass = false,exposeProxy = true)
public class EnableAspectJAutoProxyBean {
}
org.springframework.context.annotation.EnableAspectJAutoProxy
在这个类中,注册了AOP入口类 AnnotationAwareAspectJAutoProxyCreator
设置了两个属性:
proxyTargetClass = true
1)目标对象实现了接口 – 使用CGLIB代理机制
2)目标对象没有接口(只有实现类) – 使用CGLIB代理机制
proxyTargetClass = false
1)目标对象实现了接口 – 使用JDK动态代理机制(代理所有实现了的接口)
2)目标对象没有接口(只有实现类) – 使用CGLIB代理机制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {
@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {
@code ThreadLocal}
* for retrieval via the {
@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {
@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
exposeProxy
该属性设置代理对象是否需要暴露,说白了就是是否需要把代理对象设置到ThreadLocal中。
AOP的其他入口类的配置是基于xml的形式
例如:
<!--开启注解aop-->
<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="true"/>
或者
<aop:config proxy-target-class="false">
<!--<aop:pointcut>在此处定义的pointcut是全局的pointcut可以供所有的aspect使用-->
<!--id:表示这个pointcut的名称,以方便使用-->
<aop:pointcut id="addpointcut" expression="execution(public * com.chj.service..*.add(..))"/>
<aop:pointcut id="delpointcut" expression="execution(public * com.chj.service..*.del*(..))"/>
<aop:pointcut id="myMethods" expression="execution(public * com.chj.service..*.*(..))"/>
<!--advisor必须在aspect之前,要不然有xml约束报错-->
<aop:advisor advice-ref="beforeAdviceBean" order="2" pointcut-ref="myMethods"/>
<aop:aspect id="aspect1" ref="aspectXml1" order="0">
<!--<aop:declare-parents types-matching="com.zhuguang.jack.service.MyServiceImpl"-->
<!--implement-interface="com.zhuguang.jack.aop.IntroductionIntf"-->
<!--delegate-ref="myintroduction"/>-->
<!--id:表示这个pointcut的名称,以方便使用-->
<aop:pointcut id="myMethod2" expression="execution(public * com.chj.service..*.*(..))
and @annotation(org.springframework.web.bind.annotation.RequestMapping)"/>
<aop:before method="before" pointcut-ref="myMethods"/>
<aop:after method="after" pointcut-ref="myMethod2"/>
<!-- 后置通知 returning="returnVal" 定义返回值 必须与类中声明的名称一样-->
<aop:after-returning method="afterReturning" returning="returnVal"
pointcut="execution(public * com.chj.service..*.*(..))"/>
<!--异常通知 throwing="throwable" 指定异常通知错误信息变量,必须与类中声明的名称一样-->
<!--<aop:after-throwing method="afterthrowing" throwing="e" pointcut-ref="myMethods"/>-->
<aop:around method="around" pointcut-ref="myMethod2"/>
</aop:aspect>
</aop:config>
2、是否生成代理
当一个bean实例化完成后,会判断该bean是否生成代理,AOP的入口如下:
2.1、Aop代理对象生产入口:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// Initialize the bean instance.
Object exposedObject = bean;
try {
//ioc di,依赖注入的核心方法,该方法必须看,重要程度:5
populateBean(beanName, mbd, instanceWrapper);
//bean 实例化+ioc依赖注入完以后的调用,非常重要,重要程度:5
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
在这个方法里面,具体是:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(String,Object, RootBeanDefinition)
if (mbd == null || !mbd.isSynthetic()) {
//这个地方可能生出代理实例,是aop的入口
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
这是一个BeanPostProcessor接口的运用,initializeBean方法我们都知道是一个bean实例化完成后做的操作,而这个代理实例生成也是在bean实例化完成后做的操作,其核心代码如下:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {