通过代码进行理解:
1.接口
public interface Subject {
public void rent();
public void hello(String str);
}
2.实现类
public class RealSubject implements Subject{
@Override
public void rent(){
System.out.println("I want to rent my House!");
}
@Override
publicvoidhello(String str){
System.out.println("Hello:"+str);
}
}
3.代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler{
private Object subject;//这是要代理的真实对象
public Dynamic Proxy(Object subject){
this.subject=subject;//给要代理的真实对象初始化
}
@Override
public Object invoke(Object proxy, Method method,Object[] args)throwsThrowable {
//第一个参数是指最终生成的代理对象,也就是所要代理的真实对象
// 第二个是代理的方法,也就是所要代理的真实对象的某个方法
// 第三个是参数,也就是真实对象调用的方法(第二个参数)所需要的参数System.out.println("before rent house");
//代理前的添加的自定义操作,此处是为了更好的看到代理效果
System.out.println("Method:"+method);
//真实对象的方法
method.invoke(subject,args);
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用//个人理解就是代理对象调用真实对象的方法,就跳转到真实对象的方法去执行
System.out.println("after rent house");//代理后的操作,此处是为了更好的看到代理效果
return null;
}
}
4.客户端
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public classClient{
public static void main(Stringargs[]){
Subject realSubject=newRealSubject();//真实对象InvocationHandler handler=newDynamicProxy(realSubject);//代理对象
//Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法
Subject subject= (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),realSubject.getClass()
.getInterfaces(),handler);
//第一个参数一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
//第二个参数,一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,
// 那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了。
// 为什么能定义这个类型的对象,因为我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,可以转化为接口中的任意一个类型并且必须使用接口类型//第三个参数,一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
System.out.println(subject.getClass().getName();
/**
* 可能我以为返回的这个代理对象会是Subject类型的对象,或者是InvocationHandler的对象,结果却不是,
* 首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,
* 我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,
* 这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。
* 同时我们一定要记住,通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,
* 也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。
*/
subject.rent();
subject.hello(" world!");
/**
*正好就是我们的Subject接口中的两个方法,这也就证明了当我通过代理对象来调用方法的时候,
* 起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。
*/
}
}
5.newProxyInstance源码
public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) throws IllegalArgumentException{
Objects.requireNonNull(h);
finalClass[] intfs = interfaces.clone();
SecurityManager sm = System.getSecurityManager();
if(sm !=null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
}
网友评论