• Spring AOP


    Spring AOP

    官方文档

    一、引述

      与OOP(面向对象)相比,传统的的OOP开发的代码逻辑是自上而下的,但是在这些自上而下的过程中会产生横切性的问题(例如日志、权限、事务),而这些横切性的问题由于我们的主业务逻辑关系不大,会散落在代码的各个地方,造成难以维护的问题。

      AOP的编程思想就是把这些横切性的问题和主业务逻辑进行分离,从而达到解耦的目的。主要用于事务管理、性能监视、安全检查、缓存、日志等应用。

      AspectJ是一个基于Java语言的AOP框架。

    二、实现原理(代理)

      AOP底层采用代理机制进行实现。如果接口+实现类,那么spring采用jdk动态代理Proxy。如果实体类没有实现接口,那么spring采用chlib字节码增强。

      JDK代理利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

      Cglib利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口。

      【为什么JDK代理需要实现接口】

        1、JDK代理生成的代理类继承了Proxy,由于java是单继承,所以只能实现接口,通过接口实现 

        2、从代理模式的设计来说,充分利用了java的多态特性,也符合基于接口编码的规范 

    1. AOP术语

    ① target:目标类,需要被代理的类。——Userservice

    ② jionPoint:连接点:可能被拦截到的方法。——addUser()、delUser()、updateUser()

    ③ pointCut:切入点,已经被增强的连接点。—— addUser()

    ④ advice:通知,增强代码。—— after() 、before()

    ⑤ weaving:织入,指把增强advice应用到target来创建新的代理对象proxy的过程。——可以看成工厂类

    ⑥ proxy:代理类—— 生成之后的代理类

    ⑦ aspect:切面,是指切入点pointCut和通知advice的结合。—— MyAspect与切入点结合

     2. JDK代理

    ① 接口 IUserService

    public interface IUserService {
        public void addUser();
        public void delUser();
        public void updateUser();
    }

    ② 目标类UserService

    //target目标类
    public class UserService implements IUserService {
        //三个方法都是连接点,可能被拦截的方法
        @Override
        public void addUser() {
            System.out.println("增加用户");
        }
    
        @Override
        public void delUser() {
            System.out.println("删除用户");
        }
    
        @Override
        public void updateUser() {
            System.out.println("更新用户");
        }
    }

    ④ 切面类

    //切面类aspect
    public class MyAspect {
        //通知advice
        public void before(){
            System.out.println("开启事务");
        }
        public void after(){
            System.out.println("提交事务");
        }
    }

    ④ 工厂类--提供一个创建代理类的方法

    public class MyBeanFactory {
        public static IUserService createUserService(){
            //target目标类
            final IUserService userService = new UserService();
            System.out.println(userService);
            //aspect切面类
            final MyAspect aspect = new MyAspect();
            //proxy 代理类
            IUserService proxyService = (IUserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),userService.getClass().getInterfaces(),new InvocationHandler(){
    
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //执行前
                    aspect.before();;
                    //放行
                    Object obj = method.invoke(userService,args);
                    //执行后
                    aspect.after();
                    return  obj;
                }
            });
            return proxyService;
        }
    }

    ⑤ 测试

    public static void main(String[] args) {
        IUserService userService = MyBeanFactory.createUserService();
        //切入点,已经被增强的方法
        userService.addUser();
    }

     3. Cglib代理

    ① 目标类 UserService(不实现接口)

    //target目标类,不实现接口
    public class Userervice {
        //三个方法都是连接点,可能被拦截的方法
        public void addUser() {
            System.out.println("增加用户");
        }
    
        public void delUser() {
            System.out.println("删除用户");
        }
    
        public void updateUser() {
            System.out.println("更新用户");
        }
    }

    ② 切面类(与jdk代理相同)

    //切面类
    public class MyAspect {
        //通知
        public void before(){
            System.out.println("开启事务");
        }
        public void after(){
            System.out.println("提交事务");
        }
    }

    ③ 工厂类(与JDK不同,使用了enhancer,字节码增强)

    public class MyFactory {
        public static Userervice createUserService(){
            //1. 目标类
            final Userervice userervice = new Userervice();
            //2. 切面类
            final MyAspect aspect = new MyAspect();
            //3. cglib核心类
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(userervice.getClass());
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    aspect.before();
                    //执行代理类的方法,目标类和代理类是父子关系
                    Object obj = methodProxy.invokeSuper(o,objects);
                    aspect.after();
                    return obj;
                }
            });
            Userervice proxy = (Userervice) enhancer.create();
            return proxy;
        }
    }

    ④ 测试(效果相同)

    public static void main(String[] args) {
            Userervice userervice = MyFactory.createUserService();
            userervice.addUser();
        }

    4. Aop通知类型

    前置通知 before:在目标方法执行前实施增强
    
    后置通知 afterReturning:在目标方法执行后实施增强,如果出现异常无法执行
    
    环绕通知 around:在目标方法执行前后实施增强
    
    异常抛出通知 afterThrowing:方法抛出异常后实施增强
    
    引介通知 declare-parents:在目标类中添加一些新的方法和属性

    最终通知 after :
    在目标方法执行后实施增强,无论是否出现异常

    三、AspectJ

      AspectJ是一个基于Java语言的AOP框架,使用注解开发。

    常用注解:

    1.  通知注解

      @Before 前置

      @AfterReturning 后置

      @Around 环绕

      @AfterThrowing 抛出异常

      @After 最终

    2. 切入点 @PointCur

    3. 声明切面 @Aspect

    4. 切入表达式

      最重要的一个表达式——execution():用于描述方法,execution(* com.crm.*.service..*.*(..))

      

  • 相关阅读:
    字符串函数之strncat
    1的数目_扩展问题
    关于虚函数(多态)与继承的一道搜狗笔试题
    给定两个正整数(二进制形式表示)A和B,问把A变为B需要改变多少位(bit)?也就是说,整数A和B的二进制表示中有多少位是不同的?
    字符串函数之strcmp
    字符串函数之strchr
    1的数目
    linux scp 远程获取文件
    scala之helloworld
    scala0011
  • 原文地址:https://www.cnblogs.com/qmillet/p/12541116.html
Copyright © 2020-2023  润新知