zoukankan      html  css  js  c++  java
  • Spring Aop 详解: Aspect Oriented Programming

    面向切面编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    即不通过修改源代码的方式,在主干功能中添加新的功能

    1. 动态代理

    有接口时,使用 JDK 的动态代理

    public interface UserDao {
    	public void login();
    }
    
    public class UserDaoImpl implements UserDao {
        public void login() {
            // 登录逻辑
        }
    }
    

    创建 UserDao 接口实现类代理对象

    使用 Proxy 类里面的方法创建代理对象

    java.lang.Proxy 调用 newProxyInstance 方法

    方法有三个参数:

    第一参数,类加载器

    第二参数,增强方法所在的类,这个类实现的接口,支持多个接口

    第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

    被代理类的接口:

    public interface UserDao {
        int add(int a, int b);
    
        String update(String id);
    }
    

    被代理类的实现类

    public class UserDaoImpl implements UserDao {
        @Override
        public int add(int a, int b) {
    
            return a + b;
        }
    
        @Override
        public String update(String id) {
    
            return id;
        }
    }
    

    代理实现:

    public class JdkProxy {
        public static void main(String[] args) {
            Class[] interfaces = {UserDao.class};
    
            // 匿名内部类写法
    //        Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
    //            @Override
    //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //                return null;
    //            }
    //        });
    
            UserDaoImpl userDao = new UserDaoImpl();
            // 第一参数:类加载器。第二参数:增强方法所在的类,这个类实现的接口,支持多个接口。第三参数:实现这个接口 InvocationHandler,创建代理对象,写增强的部分
            // 返回代理对象
            UserDao dao = (UserDao) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            int result = dao.add(1, 2);
            System.out.println("result: " + result);
        }
    }
    
    /**
     * 创建代理对象的代码
     */
    class UserDaoProxy implements InvocationHandler {
        private Object obj;
    
        /**
         * 创建的是谁的对象,就把谁传进来(这里写 Object)
         *
         * @param obj
         */
        public UserDaoProxy(Object obj) {
            this.obj = obj;
        }
    
        /**
         * 增强逻辑
         *
         * @param proxy
         * @param method
         * @param args
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //方法之前
            System.out.println("方法之前执行...." + method.getName() + " :传递的参数..." + Arrays.toString(args));
            //被增强的方法执行
            Object res = method.invoke(obj, args);
            //方法之后
            System.out.println("方法之后执行...." + obj);
    
            return res;
        }
    }
    

    没有接口时,使用 CGLIB 动态代理

    public class User {
        public void add() {
            // ...
        }
    }
    

    原生可以使用子类增强:

    public class Person extends User {
        public void add() {
            super.add();
            // 增强 ...
        }
    }
    

    CGLIB:创建当前类子类的代理对象

    2. AOP(术语)

    连接点

    类里面哪些方法可以被增强,这些方法被称为连接点

    切入点

    实际被真正增强的方法,称为切入点

    通知(增强)

    实际增强的逻辑部分称为通知(增强)

    通知有多种类型:

    1. 前置通知
    2. 后置通知
    3. 环绕通知
    4. 异常通知
    5. 最终通知

    切面

    是一个动作,把通知应用到切入点的过程叫做切面

    3. AOP 实现方式

    Spring 框架一般都是基于 AspectJ 实现 AOP 操作

    AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使 用,进行 AOP 操作

    基于 AspectJ 实现 AOP 操作

    1. 基于 xml 配置文件实现

    2. 基于注解方式实现(使用)

    切入点表达式

    1. 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
    2. 语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]) )

    举例 1:对 cn.duniqb.dao.BookDao 类里面的 add 进行增强

    execution(* cn.duniqb.dao.BookDao.add(..))

    举例 2:对 cn.duniqb.dao.BookDao 类里面的所有的方法进行增强

    execution(* cn.duniqb.dao.BookDao.* (..))

    举例 3:对 cn.duniqb.dao 包里面所有类,类里面所有方法进行增强

    execution(* cn.duniqb.dao.*.* (..))

    4. AOP 操作步骤(AspectJ 注解)

    创建类,在类里面定义方法

    public class User {
        public void add() {
    
            System.out.println("add.......");
        }
    }
    

    创建增强类(编写增强逻辑)

    在增强类里面,创建方法,让不同方法代表不同通知类型

    public class UserProxy {
        /**
         * 前置通知
         */
        public void before() {
            System.out.println("before......");
        }
    }
    

    进行通知的配置

    1. 在 spring 配置文件中,开启注解扫描,开启生成代理对象
    @Configuration
    @ComponentScan(basePackages = {"cn.duniqb.aopAnnotation"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAop {
    }
    
    2. 使用注解创建 User 和 UserProxy 对象
    @Component
    
    3. 在增强类上面添加注解 @Aspect
    @Component
    @Aspect
    public class UserProxy {
        /**
         * 前置通知
         */
        public void before() {
            System.out.println("before......");
        }
    }
    

    配置不同类型的通知

    在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

    相同的切入点抽取

    /**
         * 相同切入点抽取
         */
    @Pointcut(value = "execution(* cn.duniqb.aopAnnotation.User.add(..))")
    public void pointCut() {
    
    }
    
    /**
         * 前置通知
         */
    @Before(value = "pointCut()")
    public void before() {
    
        System.out.println("before......");
    }
    
    /**
         * 后置通知(返回通知)
         */
    @AfterReturning(value = "pointCut()")
    public void afterReturning() {
    
        System.out.println("afterReturning......");
    }
    
    没有修不好的电脑
  • 相关阅读:
    gojs常用API-画布定义
    页面开发的标准
    iis7.5做反向代理配置方法实例图文教程
    Tomcat实现反向代理
    nodejs的package.json依赖dependencies中 ^ 和 ~ 的区别
    dependencies与devDependencies的区别
    常见的cmd命令
    解决SecureCRT中文显示乱码
    ASP防XSS代码
    Android页面之间进行数据回传
  • 原文地址:https://www.cnblogs.com/duniqb/p/13176376.html
Copyright © 2011-2022 走看看