• springAOP基于注解的使用方法和实现原理


     springAOP即面向切面编程,可以在方法执行过程中动态的织入增强逻辑,其使用步骤为:

    1. 导入aop模块的jar包,或在maven中添加依赖:spring-aspects

    2. 定义目标类和目标方法,即需要增强的类和方法

    3. 定义切面类和通知方法

    4. 指定通知方法何时何地织入,即在切面类中添加切点和切面注解

    5. 将目标类和切面类注册到同一个springIOC容器中

    6. 告诉容器哪个是目标类、哪个是切面类,即在切面类上添加@Aspect注解

    7. 如果容器中存在多个切面类且需要排序,可以让切面类实现Ordered接口

    8. 开启基于注解的切面功能,即在切面类上添加@EnableAspectJAutoProxy注解

    目标类

    /**
     * springAOP中的目标类
     */
    public class MathTool {
    
        /**
         * 执行除法逻辑
         * @param i 被除数
         * @param j 除数
         * @return*/
        public double divide(int i, int j) {
            System.out.println("--------目标方法开始执行--------");
            double result = i / j;
            return result;
        }
    }

    切面类

    /**
     * 打印日志的切面类
     */
    @Aspect
    @EnableAspectJAutoProxy
    public class LogAspect implements Ordered {
    
        //定义切点,即需要增强的方法
        @Pointcut(value = "execution(public double cn.monolog.entity.MathTool.*(..))")
        public void getPointcut() {}
    
        /**
         * 在目标方法之前执行的通知方法
         * @param joinPoint 切点
         */
        @Before(value = "getPointcut()")
        public void startLog(JoinPoint joinPoint) {
            Object[] args = joinPoint.getArgs();
            System.out.println("方法" + joinPoint.getSignature() + "即将执行,参数列表:" + Arrays.asList(args));
        }
    
        /**
         * 在目标方法之后执行的通知方法
         * @param joinPoint 切点
         */
        @After(value = "getPointcut()")
        public void endLog(JoinPoint joinPoint) {
            System.out.println("方法" + joinPoint.getSignature() + "执行完毕");
        }
    
        /**
         * 目标方法正常返回时的通知方法
         * @param joinPoint 切点
         * @param result 目标方法的返回值,通过@AfterReturning定义
         * 注:当通知方法存在多个参数时,JoinPoint必须放在第一位
         */
        @AfterReturning(value = "getPointcut()", returning = "result")
        public void returningLog(JoinPoint joinPoint, Object result) {
            System.out.println("方法" + joinPoint.getSignature() + "返回值为:" + result);
        }
    
        /**
         * 目标方法发生异常时的通知方法
         * @param joinPoint 切点
         * @param exception 目标方法抛出的异常,通过@AfterThrowing定义
         * 注:当通知方法存在多个参数时,JoinPoint必须放在第一位
         */
        @AfterThrowing(value = "getPointcut()", throwing = "exception")
        public void exceptionLog(JoinPoint joinPoint, Exception exception) {
            System.out.println("方法" + joinPoint.getSignature() + "抛出异常,异常信息为:" + exception);
        }
    
        //Ordered接口提供的排序方法,返回值为执行顺序,数字越小越靠前
        @Override
        public int getOrder() {
            return 1;
        }
    }

    容器配置类

    /**
     * 容器配置类
     * 用于测试springAOP
     * 需要注册目标类和切面类
     */
    @Configuration
    @Import({AopDefinitionRegistrar.class})
    public class AopBeanConfig {
    }
    /**
     * 用于向容器中导入需要的组件
     */
    public class AopDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //注册目标类
            BeanDefinition mathTool = new RootBeanDefinition(MathTool.class);
            registry.registerBeanDefinition("mathTool", mathTool);
            //注册切面类
            BeanDefinition logAspect = new RootBeanDefinition(LogAspect.class);
            registry.registerBeanDefinition("logAspect", logAspect);
        }
    }

    springAOP的实现原理

    1. @EnableAspectJAutoProxy开启注解功能,并在容器中注册一个组件——AnnotationAwareAspectJProxyCreator,这个组件实现了SmartInstantiationAwareBeanPostProcessor,是一个后置处理器;

    2.  在创建springIOC容器时,有一个步骤是refresh即刷新容器,在这个方法中,有一步是registerBeanPostProcessors,这一步会初始化所有的后置处理器,就是在这时生成了AnnotationAwareAspectJProxyCreator组件;

    3. refresh后面还有一步,finishBeanFactoryInitilization,即初始化剩下的单实例bean,这时会生成目标类组件和切面类组件;

    4. AnnotationAwareAspectJProxyCreator会对目标类组件和切面类组件进行拦截,即在这些组件创建完成并初始化之后,调用postProcessAfterInitialization方法,判断目标类组件是否需要增强,如果需要,会将切面类的通知方法包装成增强器(Advisor),然后用cglib动态代理(如果目标类实现了接口,也可以使用jdk动态代理)给目标类对象创建一个代理对象,这个代理对象中就有上述增强器;

    5. 经过2-4步,容器就创建完毕,接下来代理对象执行目标方法,首先获取目标方法的拦截器链(即MethodInterceptor,由增强器包装而来),利用拦截器的链式机制依次进入每一个拦截器进行增强;

    6. 拦截器链的执行效果

    目标方法成功:前置通知 → 目标方法 → 后置通知 → 返回通知;

    目标方法抛出异常:前置通知 → 目标方法 → 后置通知 → 异常通知。

  • 相关阅读:
    Maven3路程(一)用Maven创建第一个web项目(1)
    ECLIPSE下SVN的创建分支/合并/切换使用
    Oracle 客户端免安装数据库连接
    如何用Maven创建web项目(具体步骤)
    使用Eclipse构建Maven项目 (step-by-step)
    Maven安装配置
    动画基础(隐式动画)
    CA*Layer(CAReplicatorLayer--)
    CA*Layer(CATransformLayer--CAGradientLayer)
    CA*Layer(CAShapeLayer--CATextLayer)
  • 原文地址:https://www.cnblogs.com/dubhlinn/p/10708454.html
Copyright © 2020-2023  润新知