java动态代理

动态代理

代理比较好理解,和现实生活中意思一样。就是我要干一件事情,可以通过代理人或代理平台进行完成,不需要直接和服务方接触。
又或者计算机网络上说的代理。为什么叫动态代理?
这里回到java程序上,是因为在运行时可以动态的创建接口的实现,通过java的反射进行实现。依赖三个关键类:Proxy、Method和InvocationHandler.

创建代理实例

使用Proxy类的newProxyInstance方法

/**
    loader是类加载器
    interfaces 被代理的类,这里只支持接口
    InvocationHandler 代理处理handler
*/
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h){}

要创建代理实例,我们就要准备三个参数:第一个类加载器用来动态加载class文件。第二个参数需要动态代理的接口。第三个参数代理处理handler。创建被代理实例
都会调用该handler的invoke方法。

InvocationHandler只有一个接口方法

public interface InvocationHandler{
  Object invoke(Object proxy, Method method, Object[] args)
         throws Throwable;
}

invoke方法持有三个参数:
proxy代理实例对象,就是newProxyInstance创建的实例,目前没有发现有哪些用处
method被代理方法实例。这里就可以通过反射获取方法定义相关的信息。
args调用方法实例参数。

invoke方法体就是具体我们要对代理方法进行增强的操作逻辑。一般情况下我们在一些操作后还要执行原先method的方法逻辑,当然你也可以完全修改原逻辑。学过反射都知道
通过反射执行method.invoke(target, args)。需要target实例对象,args参数。这里参数已经有了,还差target实例。所以一般在实现InvocationHandler接口的时候
还会把target对象传进来。

完整的一个代理例子:

public class DynamicProxyTest {

    static class DyInvokeHandler implements InvocationHandler{

        public DyInvokeHandler(Object target){
            this.target = target;
        }
        //被代理实例对象
        private Object target;
        //这里proxy参数就是外面创建的代理对象proxyMap
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if("put".equals(method.getName()))
                System.out.println("invoke method:"+method.getName());
            return  method.invoke(target, args);
        }
    }

    public static void main(String[] args) {
        //创建Map接口的代理对象
        Map proxyMap = (Map) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
                new Class[]{Map.class},new DyInvokeHandler(new HashMap<>()));
        
        proxyMap.put("name","test");
        System.out.println(proxyMap.get("name"));
    }
}

使用场景

spring中的AOP切面编程还有依赖注入、事务的控制都是用的动态代理。日志记录,mock接口数据,权限控制其实都可以使用。

posted @ 2023-08-08 18:16  朋羽  阅读(17)  评论(0编辑  收藏  举报