zoukankan      html  css  js  c++  java
  • Spring,AOP,JDK动态代理、CGLIB代理

    关于AOP的基本介绍,参考:Spring深入浅出(十二),AOP,AspectJ,基于XML开发

    AOP的代理就是由AOP框架动态生成的一个对象,该对象可以作为目标对象使用。Spring中的AOP代理,可以是JDK动态代理,也可以是CGLIB代理(Code Generation Library)。

    一、JDK动态代理

    1. 创建接口

    package com.itheima.jdk;
    
    public interface UserDao {
        public void addUser();
    
        public void deleteUser();
    }

    2. 创建实现类

    package com.itheima.jdk;
    
    import org.springframework.stereotype.Repository;
    
    // 目标类
    @Repository("userDao")
    public class UserDaoImpl implements UserDao {
        public void addUser() {
            System.out.println("添加用户");
        }
    
        public void deleteUser() {
            System.out.println("删除用户");
        }
    }

    3. 创建切面类

    该类实现InvocationHandler接口,并实现接口中invoke()方法,所有动态代理类所调用的方法都会交由该方法处理。

    package com.itheima.jdk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import com.itheima.aspect.MyAspect;
    
    /**
     * JDK代理类
     */
    public class JdkProxy implements InvocationHandler {
        // 声明目标类接口
        private UserDao userDao;
    
        // 创建代理方法
        public Object createProxy(UserDao userDao) {
            this.userDao = userDao;
            // 1.类加载器
            ClassLoader classLoader = JdkProxy.class.getClassLoader();
            // 2.被代理对象实现的所有接口
            Class[] clazz = userDao.getClass().getInterfaces();
            // 3.使用代理类,进行增强,返回的是代理后的对象
            return Proxy.newProxyInstance(classLoader, clazz, this);
        }
    
        /*
         * 所有动态代理类的方法调用,都会交由invoke()方法去处理 proxy 被代理后的对象 method 将要被执行的方法信息(反射) args
         * 执行方法时需要的参数
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 声明切面
            MyAspect myAspect = new MyAspect();
            // 前增强
            myAspect.check_Permissions();
            // 在目标类上调用方法,并传入参数
            Object obj = method.invoke(userDao, args);
            // 后增强
            myAspect.log();
            return obj;
        }
    }

    4. 创建主程序

    package com.itheima.jdk;
    
    public class JdkTest {
        public static void main(String[] args) {
            // 创建代理对象
            JdkProxy jdkProxy = new JdkProxy();
            // 创建目标对象
            UserDao userDao = new UserDaoImpl();
            // 从代理对象中获取增强后的目标对象
            UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
            // 执行方法
            userDao1.addUser();
            userDao1.deleteUser();
        }
    }

    5. 运行结果

    模拟检查权限...
    添加用户
    模拟记录日志...
    模拟检查权限...
    删除用户
    模拟记录日志...

    二、CGLIB代理

    使用JDK动态代理的对象必须实现一个或多个接口。如果要对没有实现接口的类进行代理,那么可以使用CGLIB代理。

    1. 创建实现类

    package com.itheima.cglib;
    //目标类
    public class UserDao {
        public void addUser() {
            System.out.println("添加用户");
        }
        public void deleteUser() {
            System.out.println("删除用户");
        }
    }

    2. 创建切面类

    该代理类需要实现MethodInterceptor接口,并实现接口中的intercept方法。

    package com.itheima.cglib;
    
    import java.lang.reflect.Method;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    import com.itheima.aspect.MyAspect;
    
    // 代理类
    public class CglibProxy implements MethodInterceptor {
        // 代理方法
        public Object createProxy(Object target) {
            // 创建一个动态类对象
            Enhancer enhancer = new Enhancer();
            // 确定需要增强的类,设置其父类
            enhancer.setSuperclass(target.getClass());
            // 添加回调函数
            enhancer.setCallback(this);
            // 返回创建的代理类
            return enhancer.create();
        }
    
        /**
         * proxy CGlib根据指定父类生成的代理对象 method 拦截的方法 args 拦截方法的参数数组 methodProxy
         * 方法的代理对象,用于执行父类的方法
         */
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            // 创建切面类对象
            MyAspect myAspect = new MyAspect();
            // 前增强
            myAspect.check_Permissions();
            // 目标方法执行
            Object obj = methodProxy.invokeSuper(proxy, args);
            // 后增强
            myAspect.log();
            return obj;
        }
    }

    3.创建主程序

    package com.itheima.cglib;
    // 测试类
    public class CglibTest {
        public static void main(String[] args) {
            // 创建代理对象
            CglibProxy cglibProxy = new CglibProxy();
                 // 创建目标对象
            UserDao userDao = new UserDao();
             // 获取增强后的目标对象
            UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
            // 执行方法
            userDao1.addUser();
            userDao1.deleteUser();
        }
    }

    4.  输出结果

    模拟检查权限...
    添加用户
    模拟记录日志...
    模拟检查权限...
    删除用户
    模拟记录日志...

    本文参考:《Java EE企业级应用开发教程》

  • 相关阅读:
    Chrome 控制台console的用法[转]
    Page Visibility(页面可见性) API介绍、微拓展[转]
    移动端rem单位用法[转]
    JavaScript继承方式详解[转]
    说说React
    Flex 布局教程:语法篇[转]
    git 常用命令总结
    Supervisor 在ubuntu系统下添加自启动
    Django 通过APNS推送消息
    通过 python-xmp-toolkit 读取图片xmlp信息
  • 原文地址:https://www.cnblogs.com/nayitian/p/15048772.html
Copyright © 2011-2022 走看看