JDK 动态代理原理

代理模式

客户端不直接访问目标对象,需要通过第三者来实现间接访问对象

代理对象在客户端和目标对象之间起中介作用,能够屏蔽目标对象不想让客户端知道的内容,或增加额外的服务

动态代理

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

JDK 动态代理例子

  • MapperInvocationHandler 实现 InvocationHandler 接口,实现 invoke 方法,该方法最终是代理类增强的目标类方法
  • JDKProxyFactory 用于生成代理对象的工厂,通过调用 Proxy.newProxyInstance 方法生成代理对象
  • UserMapper 目标类,JDK 代理的目标类必须实现某个接口
  • IUserMapper 目标类接口

MapperInvocationHandler

java 复制代码
public class MapperInvocationHandler implements InvocationHandler {
    // 动态的目标对象
    private Object target;

    public MapperInvocationHandler(Object target) {
        this.target = target;
    }
    /**
     * 增强方法
     * @param proxy 代理实例
     * @param method 目标方法
     * @param args 目标方法参数
     * @return 返回值
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("=========JDK 动态代理前置增强=========");
        method.invoke(target, args);
        System.out.println("=========JDK 动态代理后置增强=========");
        return null;
    }
}

JDKProxyFactory

java 复制代码
public class JDKProxyFactory {
    // 动态的目标对象
    private Object target;

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

    // 为目标对象生成代理对象
    public Object getTargetProxy(){
        return Proxy.newProxyInstance(
                // 目标对象使用的类加载器
                target.getClass().getClassLoader(),
                // 目标对象实现的接口
                target.getClass().getInterfaces(),
                // 事件处理器
                new MapperInvocationHandler(target)
        );
    }
}

IUserMapper

java 复制代码
public interface IUserMapper {
    void save();
}

UserMapper

java 复制代码
public class UserMapper implements IUserMapper {
    @Override
    public void save() {
        System.out.println("保存用户数据");
    }
}

Client

java 复制代码
public class Client {
    public static void main(String[] args) {
        JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(new UserMapper());
        IUserMapper userMapperProxy = (IUserMapper) jdkProxyFactory.getTargetProxy();
        userMapperProxy.save();
    }
}

运行结果

bash 复制代码
=========JDK 动态代理前置增强=========
保存用户数据
=========JDK 动态代理后置增强=========

Process finished with exit code 0

JDK 动态代理原理