关键字: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
一些问题:
- 同一核心接口,不同真实业务子类,所生成的虚拟代理对象属于同一个类(如:ISubject的为$Proxy0,IWork的为$Proxy1),虚拟代理类命名规则:$+Proxy+数字,此类存在于JVM中,可用代码写入到磁盘中观察;
- 实现的InvocationHandler接口的invoke()方法中接收的Object Proxy,是Proxy类newProxyInstance()自动生成的虚拟代理类对象(???),那么invoke()方法又是何时被接收参数并被调用的呢?
回答:
因为学习才入门还不够深入,看源码时有些被绕的有点懵,通过查看网络资料大概了解到:
原文链接:点击打开链接
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赋值。
- class Proxy{
- InvocationHandler h=null;
- protected Proxy(InvocationHandler h) {
- this.h = h;
- }
- ...
- }
接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()(request()代表的是在客户端调用的那个方法)方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。
- public final class $Proxy0 extends Proxy implements Subject {
- private static Method m1;
- private static Method m0;
- private static Method m3;
- private static Method m2;
- static {
- try {
- m1 = Class.forName("java.lang.Object").getMethod("equals",
- new Class[] { Class.forName("java.lang.Object") });
- m0 = Class.forName("java.lang.Object").getMethod("hashCode",
- new Class[0]);
- m3 = Class.forName("***.RealSubject").getMethod("request",
- new Class[0]);
- m2 = Class.forName("java.lang.Object").getMethod("toString",
- new Class[0]);
- } catch (NoSuchMethodException nosuchmethodexception) {
- throw new NoSuchMethodError(nosuchmethodexception.getMessage());
- } catch (ClassNotFoundException classnotfoundexception) {
- throw new NoClassDefFoundError(classnotfoundexception.getMessage());
- }
- } //static
- public $Proxy0(InvocationHandler invocationhandler) {
- super(invocationhandler);
- }
- @Override
- public final boolean equals(Object obj) {
- try {
- return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- @Override
- public final int hashCode() {
- try {
- return ((Integer) super.h.invoke(this, m0, null)).intValue();
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- public final void request() {
- try {
- super.h.invoke(this, m3, null);
- return;
- } catch (Error e) {
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- @Override
- public final String toString() {
- try {
- return (String) super.h.invoke(this, m2, null);
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- }