JDK动态代理与Cglib动态代理

一、前言

AOP(Aspect Oriented Programming),即面向切面编程,最主要的思想就是纵向重复,横向抽取。要想实现AOP,其底层实现是使用了动态代理技术,在Spring中,动态代理技术分为传统的JDK动态代理Cglib动态代理。这两种代理机制区别是:

  • JDK动态代理:针对实现了接口的类进行代理

  • Cglib动态代理:针对没有实现接口的类进行代理,底层是字节码增强技术,生成当前类的子类对象

源码地址:https://github.com/jitwxs/blog_sample

假设我们有一个UserService接口,其中具有CRUD方法:

public interface UserService {
    void save();
    void delete();
    void update();
    void query();
}

它有一个实现类,只是简单的输出了信息:

public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("save");
    }

    @Override
    public void delete() {
        System.out.println("delete");
    }

    @Override
    public void update() {
        System.out.println("update");
    }

    @Override
    public void query() {
        System.out.println("query");
    }
}

如果我们想要对这四个方法进行增强,例如在每个方法开头和结尾开启和提交事务,例如:

public void delete() {
    System.out.println("开启事务");
    System.out.println("delete");
    System.out.println("提交事务");
}

如果不使用AOP思想或动态代理技术,要写很多的冗余代码。

二、JDK动态代理

Step1: 要有一个实现InvocationHandler接口的类,编写MyInvocationHandler类:

/**
 * 基于 JDK 的动态代理
 * @author jitwxs
 * @since 2018/12/6 15:18
 */
public class MyInvocationHandler implements InvocationHandler {
    /**
     * 要代理类的对象
     */
    private Object targetObj;

    /**
     * 在创建对象时将要代理类的对象传进来
     */
    public MyInvocationHandler(Object targetObj) {
        this.targetObj = targetObj;
    }

    /**
     * @param proxy  方法对象(没有实际作用)
     * @param method 该方法对象所在的类对象实例
     * @param args   方法参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开启事务");
        /*
         * obj:调用谁的方法用谁的对象
         * args 方法调用时的参数
         */
        Object invoke = method.invoke(targetObj, args);
        System.out.println("提交事务");

        return invoke;
    }
}

Step2: 编写UserService的动态代理类:

/**
 * UserService的动态代理类
 * @author jitwxs
 * @since 2018/12/6 15:19
 */
public class UserServiceProxy {
    private UserService userService;

    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }

    public UserService getUserServiceProxy() {
        // 创建实现InvocationHandler类的对象,将要代理类的对象传进去
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);

        /*
         * public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
         * loader : 类加载器(指定当前类即可)
         * interfaces 要代理的类实现的接口列表
         * h:实现具体代理操作的类(要实现InvocationHandler接口)
         */
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(UserServiceProxy.class.getClassLoader(),
                UserServiceImpl.class.getInterfaces(),
                myInvocationHandler);
        return userServiceProxy;
    }
}

Step3: 编写测试方法

/**
 * JDK动态代理测试类
 * @author jitwxs
 * @since 2018/12/6 15:21
 */
public class JdkProxyTest {
    public static void main(String[] args) {
        //创建UserService实例
        UserService us = new UserServiceImpl();
        // 创建UserService代理类实例
        UserServiceProxy userServiceProxy = new UserServiceProxy(us);
        // 返回代理后增强过的UserService实例
        UserService usProxy = userServiceProxy.getUserServiceProxy();

        usProxy.delete();
    }
}

JDK动态代理与Cglib动态代理_第1张图片

三、Cglib动态代理

Step0: 导入 Cglib 依赖包:

<dependency>
    <groupId>cglibgroupId>
    <artifactId>cglibartifactId>
    <version>3.2.4version>
dependency>

Step1: 编写 userService 实现 MethodInterceptor 接口的 Cglib 动态代理类:

/**
 * UserService的动态代理类
 * @author jitwxs
 * @since 2018/12/6 15:22
 */
public class UserServiceProxy2 implements MethodInterceptor {
    public UserService getUserServiceProxy() {
        // 生成代理对象
        Enhancer enhancer = new Enhancer();
        // 设置对谁进行代理
        enhancer.setSuperclass(UserServiceImpl.class);
        // 代理要做什么
        enhancer.setCallback(this);
        // 创建代理对象
        UserService us = (UserService) enhancer.create();

        return us;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("开启事务");
        Object invoke = methodProxy.invokeSuper(o, args);
        System.out.println("提交事务");
        return invoke;
    }
}

Step2: 编写测试方法

/**
 * Cglib 动态代理测试类
 * @author jitwxs
 * @since 2018/12/6 15:34
 */
public class CglibProxyTest {
    public static void main(String[] args) {
        // 创建UserService代理类实例
        UserServiceProxy2 userServiceProxy2 = new UserServiceProxy2();
        // 返回代理后增强过的UserService实例
        UserService usProxy = userServiceProxy2.getUserServiceProxy();

        usProxy.query();
        usProxy.save();
        usProxy.update();
        usProxy.delete();
    }
}

JDK动态代理与Cglib动态代理_第2张图片

四、总结

(1)JDK的动态代理

  • 代理对象和目标对象实现了共同的接口
  • 拦截器必须实现InvocationHanlder接口

(2)cglib的动态代理

  • 代理对象是目标对象的子类
  • 拦截器必须实现MethodInterceptor接口

你可能感兴趣的:(#,Java,#,Java,Web)