Java设计模式之动态代理JDK版

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

代理模式UML类图

动态代理JDK版

动态代理利用了JDK标准库API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理。

静态代理与动态代理的区别主要在:

1、静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件

2、动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中

特点:
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。

JDK中生成代理对象主要涉及的类

java.lang.reflect.Proxy

/**
 * 创建代理实例
 *
 * @param loader            目标对象类加载器
 * @param interfaces        目标对象实现的接口类
 * @param invocationHandler 事件处理器
 * @return 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
 */
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler);

java.lang.reflect.InvocationHandler

/**
 * 代理实例上处理方法调用并返回结果
 *
 * @param proxy  代理对象
 * @param method 方法
 * @param args   方法参数
 * @return Object
 * @throws Throwable 异常
 */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

动态代理JDK版代码示例

AccountDao接口类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:03 下午
 */
public interface AccountDao {

    /**
     * 保存
     */
    void save();

}

AccountDaoImpl接口实现类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口实现
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:04 下午
 */
public class AccountDaoImpl implements AccountDao {

    @Override
    public void save() {
        System.out.println("保存账户数据");
    }

}

ProxyFactory代理工厂类

package com.github.xuchengen.proxy.statics;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 代理工厂类
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 3:33 下午
 */
public class ProxyFactory {

    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 为目标对象生成代理对象
     *
     * @param invocationHandler 事件处理器
     * @return Object
     */
    public Object getProxyInstance(InvocationHandler invocationHandler) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                invocationHandler);
    }
}

JDKDynamicProxyTest测试类

package com.github.xuchengen.proxy.statics;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * JDK动态代理测试
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 3:39 下午
 */
public class JDKDynamicProxyTest {

    public static void main(String[] args) {
        AccountDao accountDao = new AccountDaoImpl();

        ProxyFactory proxyFactory = new ProxyFactory(accountDao);

        AccountDao proxyInstance = (AccountDao) proxyFactory.getProxyInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                try {
                    System.out.println("开启事务");

                    method.invoke(accountDao, args);

                    System.out.println("提交事务");
                } catch (Exception e) {
                    System.out.println("事务回滚");
                }

                return null;
            }
        });

        proxyInstance.save();
    }

}

控制台输出

开启事务
保存账户数据
提交事务