关键字:InvocationHandler(接口)、Proxy(类)、reflect;
如果有N个接口需要使用代理类来完成一些辅助的操作,而这些辅助功能又很相似,此时希望有一个代理类,能满足N多不同接口的代理处理,而不是具体针对某一个接口,这样就需要使用动态代理来实现。
要实现动态代理的类,必须实现java.lang.reflect.InvocationHandler接口(其中只包含有一个invoke()方法),并需要java.lang.reflect.Proxy类中的newProxyInstance()方法来实现真实业务与代理对象的绑定。
新增了一个工厂类来完成接口的虚拟代理对象的实例化工作,客户端需要传入的是代理类和真是业务类的名称。
简单的功能(以打印为例)实现如下:
package com.java.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
interface ISubject{ //核心接口
public void eat(String food,int amount);
}
class RealSubject implements ISubject{ //真实业务
@Override
public void eat(String food,int amount) {
System.out.println("我要吃"+amount+"份量的"+food+"!");
}
public void fun() {
System.out.println("其他工作");
}
}
interface IWork{ //核心接口
public void wash();
}
class RealWork implements IWork{ //真实业务
@Override
public void wash() {
System.out.println("开始洗澡!");
}
}
class RealWorkOther implements IWork{ //真实业务
@Override
public void wash() {
System.out.println("开始洗碗!");
}
}
class ProxySubject implements InvocationHandler{//动态代理类
private Object target; //(真实业务)需要绑定任意接口对象,用Object描述
public ProxySubject() {}
public void prepare() {
System.out.println("【PoxySubject】准备工作!");
}
public void clear() {
System.out.println("【PoxySubject】清理工作!");
}
/**
* 实现真实对象的绑定处理,同时返回代理对象
* @param target 需要被绑定的真实对象
* @return 返回代理对象
*/
public Object bind(Object target) {
this.target = target; //必须手动保存真实主题对象
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),this.target.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("【proxyclass】"+proxy.getClass()); //仅作观察用
System.out.println("【method】"+method); //仅作观察用
System.out.println("【arg】"+Arrays.toString(args)); //仅作观察用
System.out.println("-------------------------------------------------------------------");
prepare();
Object result = method.invoke(this.target,args);
clear();
return result;
}
}
class Factory{ //工厂类
private Factory() {}
/**
* 产生被代理类(接口)的虚拟实例化代理对象
* @param proxySubjectName 代理类名字
* @param realObjectName 真实业务类名字
* @return 被代理接口的虚拟代理类实例化对象
*/
public static Object getInstance(String proxySubjectName,String realObjectName){
Object rInstance,pInstance,resultInstance = null;
Method bindMethod = null;
try {
rInstance = Class.forName(realObjectName).newInstance();
Class> p = Class.forName(proxySubjectName);
pInstance = p.newInstance();
bindMethod = p.getMethod("bind", Object.class);
//反射调用bind()方法,实现真实对象的绑定处理,同时返回代理对象
resultInstance = bindMethod.invoke(pInstance, rInstance);
} catch (Exception e) {
e.printStackTrace();
}
return resultInstance;
}
}
public class TestDemo {
public static void main(String[] args){
ISubject subject = (ISubject) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealSubject");
subject.eat("苹果", 21);
System.out.println("===============================分割线===============================");
IWork work = (IWork) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealWork");
work.wash();
System.out.println("===============================分割线===============================");
IWork work2 = (IWork) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealWorkOther");
work2.wash();
}
}
运行结果为:
为了观察加入如下代码:
ISubject subject = (ISubject) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealSubject");
System.out.println(subject.getClass());
输出结果:
class com.java.demo.$Proxy0
一些问题:
回答:
因为学习才入门还不够深入,看源码时有些被绕的有点懵,通过查看网络资料大概了解到:
原文链接:点击打开链接
https://blog.csdn.net/wang_1997/article/details/52450549
以下为摘要:
Proxy.newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)做了以下几件事.
根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类.
实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值。
接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()(request()代表的是在客户端调用的那个方法)方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。