java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
目前 Java 开发包中包含了对动态代理的支持, 但是其实现只支持对接口的的实现。这篇文章主要介绍了详解 java 动态代理的 2 种实现方式 ,有兴趣的可以了解一下。
java 的动态代理在接 java 的 api 上有说明,这里就不写了。我理解的代理:
对特定接口中特定方法的功能进行扩展,这就是代理。代理是通过代理实例关联的调用处理程序对象调用方法。
下面通过一个例子看一下:
接口:
- public interface Num {
- void show();
- int getNum();
- int getProduct(int x);
- }
实现类:
- public class MyNum implements Num {
- @Override
- public int getNum() {
- return 3;
- }
- @Override
- public int getProduct(int x) {
- return x;
- }
- @Override
- public void show() {
- System.out.println("底层方法打印数字99");
- }
- }
先看一下 Method 中的 invoke 方法在 api 中是怎么描述的
就是说调用处理程序对接口的实现类对象调用 Method 对象表示的底层方法。
第一种实现代理的方式:
- public class NumProxy {
- private Object num;
- //通过构造方法构造接口的实现类对象
- public NumProxy(Object num) {
- this.num = num;
- }
- public Object getNumByProxy() {
- Object numProxy = Proxy.newProxyInstance(num.getClass().getClassLoader(), new Class[] {
- Num.class
- },
- new InvocationHandler() {
- /**
- * method: 对应于在代理实例上调用的接口方法的 Method 实例。我理解的就是被代理的真实方法实例
- * args: 我理解的是真实方法的参数数组
- */
- @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Object obj = null;
- System.out.println("在方法之前开始记录");
- String methodName = method.getName();
- if ("getProduct".equals(methodName)) {
- obj = method.invoke(num, args);
- obj = (Integer) obj * 2;
- System.out.println("proxy: getProduct()结束");
- } else if ("show".equals(methodName)) {
- obj = method.invoke(num, args);
- System.out.println("proxy: show()结束");
- }
- return obj;
- }
- });
- return numProxy;
- }
- }
第二种实现代理的方式:通过实现 InvocationHandler 接口
- public class NumProxyImpl implements InvocationHandler {
- //这里我把接口类型具体化了, 没有写成Object
- private Num num;
- public NumProxyImpl(Num num){
- this.num = num;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object obj = null;
- String methodName = method.getName();
- if("getProduct".equals(methodName)){
- System.out.println("proxy: getProduct()开始");
- obj = method.invoke(num, args);
- obj = (Integer) obj * 2;
- System.out.println("proxy: getProduct()结束");
- }else if("show".equals(methodName)){
- System.out.println("proxy: show()开始");
- obj = method.invoke(num, args);
- System.out.println("proxy: show()结束");
- }
- return obj;
- }
- }
测试代码:
- public class TestNum {
- public static void main(String[] args) {
- //两种方式一起测试
- NumProxy np = new NumProxy(new MyNum());
- Num numProxy = (Num) np.getNumByProxy();
- int x = numProxy.getProduct(2);
- System.out.println(x);
- numProxy.show();
- System.out.println("----------------");
- NumProxyImpl npi = new NumProxyImpl(new MyNum());
- Num numPro = (Num) Proxy.newProxyInstance(Num.class.getClassLoader(), new Class[]{Num.class}, npi);
- int n = numPro.getProduct(3);
- System.out.println(n);
- numPro.show();
- }
- }
控制台结果:
第二种方式有点小疑惑,不知道大家有没有,那就是并没有显示的调用 NumProxyImpl 中的 invoke 方法,可是却执行了,嗯嗯,这个自己下去看一下啊
不想麻烦的只需要记住就行了。
比如编码的处理就可以用到代理,下次写个例子。
来源: http://www.phperz.com/article/17/1130/359296.html