一文搞懂AOP

2019-07-05  本文已影响0人  爱撒谎的男孩

简介

添加依赖

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

通知

连接点

切点

切面

实现

@Configuration
@ComponentScan(value = {"cn.tedu.demo"})
@EnableAsync
@EnableAspectJAutoProxy
public class FirstConfig {}
/**
 * 切面,使用@Aspect标注
 */
@Component
@Aspect
public class CustomAspect {

    /**
     * 使用@PointCut定义切入点
     */
    @Pointcut(value = "execution(* cn.tedu.demo.aspect.AspectInvok.invok(..))")
    public void pointCut(){}

    /**
     * 前置通知,在指定方法之前执行
     * @param point JoinPoint对象,可以获取切点的各种属性,比如入参的参数等
     */
    @Before(value = "pointCut()")
    public void before(JoinPoint point){
        //获取入参的参数的值
        Object[] args = point.getArgs();
        System.out.println(Arrays.asList(args));
        //获取MethodSignature,其中可以获取切点的各种属性,比如方法返回类型,参数等等
        MethodSignature signature = (MethodSignature) point.getSignature();
        String[] parameterNames = signature.getParameterNames();
        System.out.println(Arrays.asList(parameterNames));
        System.out.println("在方法之前执行");
    }

    /**
     * 在切点之后执行
     * @param point JoinPoint对象
     */
    @After(value = "pointCut()",argNames = "point")
    public void after(JoinPoint point){
        System.out.println("在方法之后执行");
    }

    /**
     * 在方法前后都会执行
     * @param point
     */
    @Around(value = "pointCut()")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("前置执行");
        //执行方法,可以获取返回值,否则方法将不会执行
        Object result = point.proceed(point.getArgs());
        System.out.println("后置执行,执行的结果=="+result);
    }

    /**
     * 正常返回通知,
     * @param point Joinpoint对象
     * @param result 方法执行返回的结果,需要和@AfterReturning注解中returning中的属性值相同,否则不能自动装配
     */
    @AfterReturning(value = "pointCut()",returning = "result")
    public void afterReturning(JoinPoint point,Object result){
        System.out.println("正常返回执行,执行的结果为:"+result);
    }

    /**
     * 异常返回执行,程序出现异常了才会执行
     * @param point
     * @param ex 切入点执行抛出的异常,需要和@AfterThrowing注解的throwing值相同,否则不能完成自动装配
     */
    @AfterThrowing(value = "pointCut()",throwing = "ex")
    public void afterThrowing(JoinPoint point,Exception ex){
        System.out.println("异常返回执行,执行的异常为:"+ex);
    }
}

注解的实现

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
    String name() default "陈加兵";
    int age() default 22;
}
@Component
@Aspect
public class CustomAspect {

    /**
     * 使用@PointCut定义切入点
     */
    @Pointcut(value = "@annotation(cn.tedu.demo.aspect.MyAnnotation)")
    public void pointCut(){}

    /**
     * 前置通知,在指定方法之前执行
     * @param point JoinPoint对象,可以获取切点的各种属性,比如入参的参数等
     */
    @Before(value = "pointCut()")
    public void before(JoinPoint point){
        //获取MethodSignature,其中可以获取切点的各种属性,比如方法返回类型,参数等等
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //获取方法上指定的注解
        MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
        System.out.println("name="+myAnnotation.name());
        System.out.println("在方法之前执行");
    }
}

源码解析

@EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    /**
    * 向容器中注入AnnotationAutoProxyCreator
    */
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //调用方法注册AnnotationAutoProxyCreator
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        //获取@EnableAspectJAutoProxy注解中两个属性的值
        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        //判断注解属性的值
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

}

AnnotationAutoProxyCreator【创建代理】

概念

分析

[图片上传失败...(image-e8798a-1562336107568)]

代码跟踪

代理执行

上一篇 下一篇

猜你喜欢

热点阅读