动态代理


动态代理

代理

Java有两种代理方式,一种是静态代理,另一种是动态代理。对于静态代理,其实就是通过依赖注入,对对象进行封装,不让外部知道实现的细节。很多 API 就是通过这种形式来封装的
代理模式给某一个(目标)对象提供一个代理对象,并由代理对象持有目标对象的引用。所谓代理,就是一个对象代表另一个对象执行相应的动作程序。而代理对象可以在客户端和目标对象之间起到中介的作用。

静态代理

在程序运行之前确定代理角色,并且明确代理类和目标类的关系。

实例

目标类

class TargetObj {
    public void execute (){
        System.out.println("目标类方法执行...");
    }
}

代理类

class ProxyObj {
    private TargetObj targetObj ;
    /**
     * 持有目标对象
     */
    public ProxyObj (TargetObj targetObj){
        this.targetObj = targetObj ;
    }
    /**
     * 目标对象方法调用
     */
    public void invoke (){
        before () ;
        targetObj.execute();
        after () ;
    }
    /**
     * 前后置处理
     */
    public void before (){
        System.out.println("代理对象前置处理...");
    }
    public void after (){
        System.out.println("代理对象后置处理...");
    }
}

使用

public class Proxy01 {
    public static void main(String[] args) {
        TargetObj targetObj = new TargetObj() ;
        ProxyObj proxyObj = new ProxyObj(targetObj) ;
        proxyObj.invoke();
    }
}

缺点

在实际的开发过程中,不可能为每个目标对象都定义一个代理类,同样也不能让一个代理对象去代理多个目标对象,这两种方式的维护成本都极高。

动态代理

基于Java反射机制,在JVM运行时动态创建和生成代理对象。

实例

目标类

class Target implements User {
    @Override
    public Integer update(String name) {
        ...
    }
}

中间代理执行类

class UserHandler implements InvocationHandler {
    private Object target ;
    public UserHandler (Object target){
        this.target = target ;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before()...");
        Object result = method.invoke(target, args);
        System.out.println("after()...");
        return result;
    }
}

使用

public static void main(String[] args) {
        /*
         * 生成$Proxy0的class文件
         */
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        /*
         * 目标对象信息
         */
        Target target = new Target();
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = Target.class.getInterfaces() ;
        /*
         * 创建代理对象
         */
        InvocationHandler userHandler = new UserHandler(target);
        /*
         * 代理类对象名
         * proxyClassName=com.java.proxy.$Proxy0
         */
        String proxyClassName = Proxy.newProxyInstance(classLoader,interfaces,userHandler).getClass().getName();
        System.out.println("proxyClassName="+proxyClassName);
        /*
         * 具体业务实现模拟
         */
        User user1 = (User) Proxy.newProxyInstance(classLoader,interfaces,userHandler);
        User user2 = (User) Proxy.newProxyInstance(classLoader,interfaces,userHandler);
        user1.update("xxx") ;
        user2.update("sss") ;
    }

newProxyInstance()

三个核心参数:

  • ClassLoader:基于JVM运行过程,所以需要获取目标类UserService的类加载器;
  • Interfaces:目标类UserService实现的接口,从面向对象来考虑,接口与实现分离,代理类通过实现IUser接口,模拟目标类的需求;
  • InvocationHandler:代理类提供的功能封装即UserHandler,可以在目标方法调用前后做增强处理;

参考:https://www.jb51.net/article/216109.htm


  目录