动态代理使用反射的功能,是动态自动创建一个代理类的实例。(这个代理类就可以意义上看做的被代理的类。操作和被代理类一样的方法)。在动态创建这个代理类的时候首先需要一个类加载器,第二个参数告诉代理的这个代理实例被代理的这个类的接口中有哪些方法可以被代理:其实也就是被代理的那些方法可以被代理。上面的这个例子中realSubject.getClass().getInterfaces()就是告诉动态代理的实例有哪些你可以代理的,这样动态指定是不是在代理类中写死要好的多,以后还需要代理其他的直接改接口就可以了。然后得到一个动态的代理实例subject转化为一个公共接口类型(被代理类实现的接口,方便知道带了了哪些方法)。那么就知道有哪些那方法可以被代理。被代理的方法都在被代理类的接口中。
所以是一个被代理类的接口类型的动态代理对象,这个时候去调用report这个方法,意思是动态去调用这个report这个方法,当然是通过反射去调用。这个时候参数handler这个参数就起作用了,这个参数就会去调用实现了InvocationHandler这个接口的那个代理类的invoker方法。第一个参数是代理实例。
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
private Object sub;
public DynamicSubject(Object obj)//真正需要调用哪个类的方法,就把那个引用传进来
{
this.sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("before calling report"+method);
method.invoke(sub,args);//sub就是传进来的realSubject
System.out.println(args == null);
System.out.println("after calling report"+ method);
return null;
}
realSubject就是这个被代理的对象。动态的调用被代理对象的方法。通过这个被代理对象实现的接口。
第二个参数就会传这个report的Method对象。然后调用method对象的invoke方法,第一个参数是这个被代理的
对象的,第二个参数是参数。这样一来就动态的调用这个被代理类的report这个方法。
代码实现:
抽象被代理角色:(目的知道被代理哪些方法):
public interface Subject
{
public void report();
public void add();
}
具体被代理角色:(实现抽象被代理角色)
public class RealSubject implements Subject
{
public void report()
{
System.out.println("this is my relly");
}
public void add()
{
System.out.println("这个是我这个接口里面的第二个方法");
}
}
动态代理角色:(动态生成这个类的实例)
public class DynamicSubject implements InvocationHandler
{
private Object sub;
public DynamicSubject(Object obj)//真正需要调用哪个类的方法,就把那个引用传进来
{
this.sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("before calling report"+method);
method.invoke(sub,args);
System.out.println(args == null);
System.out.println("after calling report"+ method);
return null;
}
}
客户端测试:
public class Client
{
public static void main(String[] args)
{
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
//代理谁传谁
Class<?> classType = handler.getClass();
//获得一个handler实例的一个Class对象
Subject subject = (Subject)Proxy.newProxyInstance(classType.getClassLoader(),realSubject.getClass().getInterfaces(),handler);
//获得一个代理类的一个实例,这个实例就能代表被代理的类,这里面必须传进去被代理类(真实类)实现的接口,这个代理类的实例就能访问这些接口中被代理类在其中声明的方法,传进去的handler才是真正进行处理
//classLoder只能由一个Class对象生成
//classLoder需要用Class对象去生成获取,classType.getClassLoader()是一个类的转载器
subject.report();
subject.add();
//获得一个handler实例的一个Class对象
//这个就是那个代理而且也就只是一个代理,但是实际的操作都是在那个实现接口InvocationHandler这个接口的类中去处理
//总结上面这个会在运行期间动态生成一个类Proxy,在获得生成一个实例的同时,并且实现了真实类所有接口,,就相当于这个实例就是那些接口引用,就是当做接口来使用这些生成的实例(¥Proxy0 implements Subject)也就是invoke方法的第一个参数
//最后就转换成那个接口,然后就可以使用那个接口里面的方法,就是转换成哪个接口就可以去使用那个接口里面的方法,(这时候就相当于得到了需要调用的方法)然后handler这个对象去调用Invoke方法,并且得到调用的这个方法的Method这个对象,
//method.invoke(sub,args);因为咱们重写了这个方法,所以会去执行在实现了InvocatiionHandler接口的类中的那个invoke()方法,方法有了传进来的那个方法对象(告诉那个方法)(也就是那个Method对象),又知道在哪个真实类中去调用这个方法,自然就可以了。
//所以这个客户端不需要知道具体代理类,只需要知道接口,然后代理类里面去使用接口调用被代理类里面的方法。
System.out.println(subject.getClass());
//subject虽然可以使用接口里面的的方法,但是这个就是一个代理的实例
// 动态代理和静态代理的区别在于,静态代理是在运行前就只要被代理类,然后在这个代理类中写死了被代理的这个类的那个方法,这个时候如果使用的动态代理的话,并不需要在代理类中写死被代理的那个类中调用哪些方法。
// 动态代理使用反射的功能,是动态自动创建一个代理类的实例。(这个代理类就可以意义上看做的被代理的类。操作和被代理类一样的方法)。在动态创建这个代理类的时候首先需要一个类加载器,第二个参数告诉代理的这个
// 实例被代理的这个类的接口中有哪些方法可以被代理:其实也就是被代理的那些方法可以被代理。上面的这个例子中realSubject.getClass().getInterfaces()就是告诉动态代理的实例有哪些你可以代理的
// 这样动态指定是不是在代理类中写死要好的多,以后还需要代理其他的直接改接口就可以了。然后得到一个动态的代理实例subject转化为一个公共接口类型。那么就知道有哪些那方法可以被代理。被代理的方法都在被代理类的接口中
// 所以是一个被代理类的接口类型的动态代理对象,这个时候去调用report这个方法,意思是动态去调用这个report这个方法,然后可以通过反射去调用。这个时候参数handler这个参数就起作用了,这个参数就会去调用实现了
// InvocationHandler这个接口的那个代理类的invoker方法。第一个参数就会传被代理的类这个是在告诉具体被代理的那个类的时候就传进去了,RealSubject realSubject = new RealSubject();
// InvocationHandler handler = new DynamicSubject(realSubject);第二个参数就会传这个report的Method对象。然后调用method对象的invoke方法,第一个参数是这个被代理的
// 对象的,第二个参数是参数。这样一来就动态的调用这个被代理类的report这个方法。
}