温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JAVA的动态代理机制

发布时间:2020-07-04 06:42:40 来源:网络 阅读:706 作者:sun2shadows 栏目:软件技术

前文讲解了代理的基本概念和静态代理机制:       设计模式之代理模式               

现在来谈谈JAVA的动态代理机制

在java的动态代理机制中有一个重要的接口invocationhandler和一个重要的类Proxy,让我们查看一下官方文档:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance.

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, 
the method invocation is encoded and dispatched to the invoke method of its invocation handler.

代理实例的调用处理程序需要实现InvocationHandler接口.

每个代理实例都关联了一个调用处理程序.当一个方法被代理实例调用时,这个方法的调用就会被加密并分发到调用程序的调用方法上.

翻译的很拗口,没关系,代会看代码的执行流程就明白了.

这个调用处理程序有一个调用方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

处理代理对象的调用方法并返回结果 .当代理对象绑定的调用程序被调用时,这个方法就会被调用程序调用.

proxy 被调用方法的代理对象

method 代理对象调用接口方法的相应方法.

args 通过代理对象接口调用方法传入的对象数组.接口方法没有参数则为空.

下面来看看proxy的文档描述:

public class Proxy extends Object implements Serializable
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

Proxy 提供静态方法创建动态代理了类和对象,同时也是这些方法创建代理对象的超类.

动态代理类是一个在运行时实现了一系列指定接口的方法的类.代理方法实现代理接口,代理类创建代理对象,每个代理类都关联了一个实现了InvocationcationHandler接口的调用程序.代理对象的调用方法通过他的代理接口,被分发到实例调用程序的invoke方法上.通过反射机制,这个指定的方法就被调用了,并且传入一个对象数组.

  • Proxy的一些properties:

  • Proxy类是public,final,和非抽象的

  • 代理类无需指定合法的名称,类名会以"$Proxy"开头

  • 代理类需要继承Proxy

  • 代理类需要按顺序实现创建时指定的各个接口

  • 如果代理类实现的是非公共接口,那么它需要被定义在接口的同名包下.

  • 由于代理类在创建时实现了指定的所有接口,所以在类对象上调用getInterfaces,将会返回一个接口列表的数组,调用getMetjods,将会返回实现所有接口方法的数组.调用getMethod将会返回proxy预期的方法.

  • Proxy.isProxyClass 判断是不是代理方法

  • 代理类的java.security.ProtectionDomain,和系统类一样在被启动类加载

  • 每一个代理类都有一个带惨构造方法,实现InvocationHandler接口,并绑定调用程序到代理对象上.相比通过反射机制去获取构造方法,代理对象可以通过调用Proxy.newProxyInstance方法来构造代理对象.

代理接口的properties

  • 代理类实现代理接口

  • 每一个代理实例都通过构造方法关联了一个调用程序.静态方法Proxy.getInvocationHandler将会返回一个由代理对象指定的调用程序

  • 代理对象的接口方法调用将会被加密和分发到调用处理程序的invoke方法上.

  • hasCode,equals,toString等方法的调用都会被加密和分发到调用程序的invoke方法,接口方法也被同样的加密和分发.

话不多说,代码奉上:

首先定义一个接口:

package com.shadow.proxy.dynamicproxy;

/**
 *
 * @author sunny
 */
public interface ITask {
    public void setData(String data);
    public int getCalData(int x);
}

定义一个实现接口业务的真实主题:

package com.shadow.proxy.dynamicproxy;

/**
 *
 * @author sunny
 */
public class TaskImpl implements ITask {

    @Override
    public void setData(String data) {
        System.out.println(data + "data is saved");
    }

    @Override
    public int getCalData(int x) {
        return x * 10;
    }
    
}

最关键的最核心的定义代理类:

package com.shadow.proxy.dynamicproxy;

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

/**
 *
 * @author sunny
 */
public class DynamicProxy implements InvocationHandler {

    private Object obj;

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }
    
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        System.out.println("开始执行方法:" + method);
        result = method.invoke(obj, args);
        System.out.println(method + "方法执行结束");
        return result;
    }
    
}

编写测试文件:

package com.shadow.proxy.dynamicproxy;

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

/**
 *
 * @author sunny
 */
public class TestProxy {
    public static void main(String[] args){
        ITask realTask = new TaskImpl();
        InvocationHandler handler = new DynamicProxy(realTask);
        ITask proxyTask = (ITask) Proxy.newProxyInstance(realTask.getClass().getClassLoader(), realTask.getClass().getInterfaces(), handler);
        proxyTask.setData("来一个汉堡");
        System.out.println(proxyTask.getCalData(10));
    }
}


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI