spring - 浅谈AOP的主要原理(动态代理JDK Proxy和cglib)

代理对象的作用:
       没有代理之前: 在原有的代码上进行事务增强!
       有了代理之后: 不动原有的代码 , 把方法进行了事务的增强.

例: 中介(代理)
      没有中介之前: 房东自己租房子 , 自己找客源.
       有了中介之后: 房东啥都不用管了 , 中介就把房子租好了.

一、JDK代理(对接口的代理)

如果目标对象是接口 , 使用JDK代理!       (JDK官方提供)
 
创建JDK代理对象的要求:被>代理类最少实现一个接口</font,如果没有则不能使用

示例如下:

接口: ProductDao.java

/**
 *   一个接口 , 用于JDK代理.
 */
public interface ProductDao {
    public void add();
    public void del();
    public void edit();
    public void find();
}

接口的实现类: ProductDaoImpl.java

public class ProductDaoImpl implements ProductDao {
    @Override
    public void add() {
        System.out.println("1.添加商品");
    }

    @Override
    public void del() {
        System.out.println("2.删除商品");
    }

    @Override
    public void edit() {
        System.out.println("3.修改商品");
    }

    @Override
    public void find() {
        System.out.println("4.查询商品");
    }
}

增强类: LogAdvice.java

/**
 *  日志增强类:
 *      advice 通知 , 增强代码!
 */
public class LogAdvice {
    public static void printLog(String className,String methodName){
        System.out.println(new Date().toLocaleString()+" : 记录日志 " + className + "类" + methodName+ "方法执行了... ...");
    }
}

测试类: 对目标代码进行增强.

public class JDKAdviceTest {
    /**
     *  2. 使用JDK代理 , 给dao中的添加和修改方法 进行增加日志类.
     */
    @Test
    public void demo03() {
        // 1.引用目标类.
        ProductDao productDao = new ProductDaoImpl();

        // 2.对原有类进行增强.
        ProductDao proxy = (ProductDao) Proxy.newProxyInstance(
                productDao.getClass().getClassLoader(),
                productDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String className = method.getDeclaringClass().getName();
                        String methodName = method.getName();

                        // 对方法名进行判断 , 对需要增强的方法进行增强.
                        if ("add".equals(methodName) || "edit".equals(methodName)) {
                            // 调用增强类.
                            LogAdvice.printLog(className, methodName);
                        }
                        
                        // 执行目标类方法.
                        Object invoke = method.invoke(productDao, args);
                        return invoke;
                    }
                }
        );

        // 执行方法.
        proxy.add();
        proxy.del();
        proxy.edit();
        proxy.find();
    }
}

二、CGLIB代理(对类的代理)

创建代理对象的要求: 被代理类不能是最终类,即用final修饰的类不能创建代理对象。

目标类:ProductDao02.java

/**
 *  添加一个类 , 用于cglib代理.
 */
public class ProductDao02 {
    public void add() {
        System.out.println("5.增加用户");
    }

    public void del() {
        System.out.println("6.删除用户");
    }

    public void edit() {
        System.out.println("7.修改用户");
    }

    public void find() {
        System.out.println("8.查询用户");
    }
}

增强类: (同上)

测试类: ( 对方法进行增强 )

/**
 *  使用cglib代理类 , 给Product02类增加日志(增强)
 */
public class CglibAdviceTest {

    @Test
    public void test01(){
        // 1.引入目标类.
        ProductDao02 userDao = new ProductDao02();

        // 2.对目标类进行增强.  建立关系.
        ProductDao02 cglib = (ProductDao02) Enhancer.create(
                userDao.getClass(),
                new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        String methodName = method.getName();
                        String className = method.getDeclaringClass().getName();
                        
                        // 对添加和修改方法进行增强.
                        if ("add".equals(methodName) || "edit".equals(methodName)) {
                            // 进行增强 ( 添加日志 )
                            LogAdvice.printLog(className, methodName);
                        }

                        // 执行目标类方法.
                        Object invoke = method.invoke(userDao, objects);
                        return invoke;
                    }
                }
        );

        cglib.add();
        cglib.edit();
        cglib.del();
        cglib.find();
    }
}

Spring正式引入代理的特点:
                  如果是对接口代理使用JDK代理;
                  如果对类代理使用Cglib代理。

    原文作者:AOP
    原文地址: https://blog.csdn.net/qq_42986107/article/details/84261908
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞