java动态代理

动态代理,依然还是在反射的基础上.

特点:
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。所以,跟平常我们编写类文件有些不同.

动机:
在静态代理中, 一个被代理类就需要一个代理类,而且被代理类里面的方法如果需要被代理,就需要在代理类里指定.100个方法你就得在代理类里面写100个. 这样类的增长很大,而且不灵活.
Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。
另外,如果事先并不知道真实角色(委托类),该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

代理模式(包含静态代理)一般涉及到的角色有:
(参考最后的代理模式的类图)

抽象角色:声明真实对象和代理对象的共同接口,对应代理接口(Subject);

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象,对应委托类(RealSubject);

代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装,对应代理类(ProxySubject)

动态代理依然离不开这些角色,但是不同的是:
1. 代理角色变成了动态生成的
也就是
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

函数返回的对象,就是下图的$ProxyN

2.代理类方法执行的地方不是在代理类的接口方法中,而是在InvocationHandler里的invoke方法

由图可见,Proxy 类是它的父类,这个规则适用于所有由 Proxy 创建的动态代理类。而且该类还实现了其所代理的一组接口,这就是为什么它能够被安全地类型转换到其所代理的某接口的根本原因。

接口和委托类不变:

public interface Subject {

    public void request();
}

public interface MyInterface {

    public void callSubject();
}

//委托类1
public class RealSubject implements Subject{
    @Override
    public void request() {
        System.out.println("RealSubject real object called");
    }
}
//委托类2
public class RealSubject2 implements MyInterface, Subject{
@Override
public void callSubject() {
    System.out.println("RealSubject2 call MyInterface Object");
}

@Override
public void request() {
     System.out.println("RealSubject2 call Subject Object");
   }
}

代理类:

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

public class DynamicSubject implements InvocationHandler {
    private Object subject;

    public DynamicSubject(Object subject) {
        this.subject=subject;
    }
    //被代理的类的方法以及方法的参数可以动态生成;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before call"+method);
        method.invoke(subject,args);
        System.out.println("after call"+method);
        return null;
    }

    public static Object factory(Object object){
        Class classType = object.getClass();

        return Proxy.newProxyInstance(classType.getClassLoader(),classType.getInterfaces(),new DynamicSubject(object));
    }


}

测试类:

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

public class Client {
    public static void main(String[] args) {
        //被代理的对象
        RealSubject realSubject = new RealSubject();
        Class classType = Subject.class;
        System.out.println(classType); //interface com.main.DynamicProxy.Subject

        InvocationHandler handler = new DynamicSubject(realSubject);
        Subject subject = (Subject)Proxy.newProxyInstance(classType.getClassLoader(), new Class[]{Subject.class}, handler);

        //方法的真正的执行是在代理类的invoke方法,并将参数分别传送过去
        subject.request();

        System.out.println(classType.getClassLoader());  
        System.out.println(subject.getClass());  //class com.sun.proxy.$Proxy0   subject是一个新的生成的对象实例,叫$Proxy0


        //测试part2

        //RealSubject2实现的是callSubject方法,和上个Subject里面的方法不一样,被代理的类的方法以及方法的参数可以动态生成;如果是静态代理,必须要知道被代理类里面有那些具体的方法.

        RealSubject2 realSubject2 = new RealSubject2();
        InvocationHandler handler2 = new DynamicSubject(realSubject2);
        Class classType2 =handler2.getClass();
        System.out.println(handler2.getClass()); //class com.main.DynamicProxy.DynamicSubject

        //转换为接口类型
        MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(classType2.getClassLoader(),realSubject2.getClass().getInterfaces(),handler2);
        myInterface.callSubject();//call the method of interface
        //假如 DynamicSubject implement Interface1 ,Interface2
        //那么下面的写法就不会有错:
        // Interface1 inter1= new DynamicSubject();
        //Interface2 inter2= new DynamicSubject();

        System.out.println(myInterface.getClass()); //class com.sun.proxy.$Proxy1



        //测试factory方法
        RealSubject2 realSubject3 = new RealSubject2();
        Subject subject3 = (Subject)DynamicSubject.factory(realSubject3);
        subject3.request();
        System.out.println(subject3.getClass());
    }

}

参考:
https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/
http://blog.csdn.net/giserstone/article/details/17199755

你可能感兴趣的:(动态代理)