代理是一种设计模式,JDK的代理设计模式应用有Java动态代理。
动态代理是一种思想,委托类的方法实现通过代理类来完成。代理类和委托类实现同一个接口,即让他们实现相同的方法(因为代理类是为委托类服务的,所以必须实现委托类的方法,然后再可以在委托类前后新增加一些方法)
代理设计模式有三种角色:委托类接口,委托类实现,代理类
以上模型,代码实现:
定义接口
package com.gc.impl;
public interface Subject {
public void action();
}
委托类实现接口
package com.gc.acion;
import com.gc.impl.Subject;
public class RealSubject implements Subject {
@Override
public void action() {
System.out.println("RealSubject Action Method");
}
}
代理类实现接口,代理实现委托类的方法并且可以在前后加上一些逻辑。
package com.gc.acion;
import com.gc.impl.Subject;
public class SubjectProxy implements Subject{
Subject subject;
public SubjectProxy(Subject subject){
this.subject = subject;
}
@Override
public void action() {
//before逻辑
System.out.println("before RealSubject Method");
//实现委托类的方法
subject.action();
//after逻辑
System.out.println("after RealSubject Method");
}
}
这种编程的好处在于,对于before和after方法的公共实现不必在每一个实现类里加,只需要在公共方法里加。但是还有一个缺点,因为实现的是某一个具体的接口,所以接口不同时,每一个接口都需要实现一遍,代码也是冗余的。所以在JDK的实现中用了Java动态代理机制。
JDK的Java动态代理机制:
一般是4个角色:委托类接口,委托类实现,代理类实现和调用操作者。
两个重要的类和接口:
代理类是Proxy(类):java.lang.reflect.Proxy
调用操作者InvocationHandle(接口):java.lang.reflect.InvocationHandle
将所有的触发(invoke)真实类实现方法的动作交给调用操作者,而非代理实现类亲自去实现。
看一下Proxy源码:
重点介绍几种方法:
1、这是Proxy的带参构造方法,绑定一个调用操作者。给内部的h赋值了一个InvocationHandler
protected Proxy(InvocationHandler arg0) {
Objects.requireNonNull(arg0);
this.h = arg0;
}
2、ClassLoader 是类装载器,interfaces是所有真实类锁拥有的全部接口数组,返回得到一个代理类Class
public static Class<?> getProxyClass(ClassLoader arg, Class[] interfaces)
throws IllegalArgumentException {
Class[] arg1 = (Class[]) arg0.clone();
SecurityManager arg2 = System.getSecurityManager();
if (arg2 != null) {
checkProxyAccess(Reflection.getCallerClass(), arg, arg1);
}
return getProxyClass0(arg, arg1);
}
3、传入类加载器ClassLoader, 委托类所拥有的全部接口数组Class[] interface,调用操作者InvocationHandler,返回得到一个对象,一个代理类对象,相当于上文例子中的Proxy(before、service()、after)
public static Object newProxyInstance(ClassLoader arg, Class<?>[] arg0,
InvocationHandler arg1) throws IllegalArgumentException {
Objects.requireNonNull(arg1);
Class[] arg2 = (Class[]) arg0.clone();
SecurityManager arg3 = System.getSecurityManager();
if (arg3 != null) {
checkProxyAccess(Reflection.getCallerClass(), arg, arg2);
}
Class arg4 = getProxyClass0(arg, arg2);
try {
if (arg3 != null) {
checkNewProxyPermission(Reflection.getCallerClass(), arg4);
}
final Constructor arg5 = arg4.getConstructor(constructorParams);
if (!Modifier.isPublic(arg4.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
arg5.setAccessible(true);
return null;
}
});
}
return arg5.newInstance(new Object[] { arg1 });
} catch (InstantiationException | IllegalAccessException arg7) {
throw new InternalError(arg7.toString(), arg7);
} catch (InvocationTargetException arg8) {
Throwable arg6 = arg8.getCause();
if (arg6 instanceof RuntimeException) {
throw (RuntimeException) arg6;
} else {
throw new InternalError(arg6.toString(), arg6);
}
} catch (NoSuchMethodException arg9) {
throw new InternalError(arg9.toString(), arg9);
}
}
4、传入一个代理类对象,得到一个InvocationHandler调用操作者
public static InvocationHandler getInvocationHandler(Object arg)
throws IllegalArgumentException {
if (!isProxyClass(arg.getClass())) {
throw new IllegalArgumentException("not a proxy instance");
} else {
Proxy arg0 = (Proxy) arg;
InvocationHandler arg1 = arg0.h;
if (System.getSecurityManager() != null) {
Class arg2 = arg1.getClass();
Class arg3 = Reflection.getCallerClass();
if (ReflectUtil.needsPackageAccessCheck(arg3.getClassLoader(),
arg2.getClassLoader())) {
ReflectUtil.checkPackageAccess(arg2);
}
}
return arg1;
}
}
动态代理类是class一种在运行时才生成的class,在生成它是必须提供一组interface给它,然后Dynamic Proxy就实现了这些interface。因为动态Proxy实现了这些接口,所以可以把Dynamic Proxy实例当成是这些interface中的任一一个来使用。
当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。因为在有了调用操作类之后,代理类本身就没有必要去亲自实现了。
看一下InvocationHandler的源码,该接口只定义有一个方法:
public interface InvocationHandler {
Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable;
}
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的action(),args为该方法的参数数组。
invoke中文翻译为触发,即调用操作者代替代理类统一触发真实类的实现方法。
前面说到创建Proxy实例的时候,要绑定三个参数(ClassLoader,interface数组,InvocationHandle)
就是Proxy中实现的所有真实类的接口都交给它绑定的InvacationHandle类去触发真实类的实现动作。Proxy自己只负责调用。
看一个动态代理的实例:
package com.gc.impl;
public interface Subject {
public void action();
public void hello(String s);
}
package com.gc.acion;
import com.gc.impl.Subject;
public class RealSubject implements Subject {
@Override
public void action() {
System.out.println("RealSubject Action Method");
}
@Override
public void hello(String s) {
System.out.println("RealSubject Action Method Include Args:"+s);
}
}
package com.gc.acion;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.gc.impl.Subject;
public class DynamicProxy implements InvocationHandler{
//要代理的真实对象
private Object subject;
//用构造方法给要代理的真实对象赋值
public DynamicProxy(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] arg2)
throws Throwable {
//before逻辑
System.out.println("before RealSubject Method");
//实现委托类subject的method方法,method方法中可能传有参数为arg2
method.invoke(subject, arg2);
//after逻辑
System.out.println("after RealSubject Method");
return null;
}
}
package com.gc.acion;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.gc.impl.Subject;
public class TestDynamicProxy {
public static void main(String[] args) {
//创建一个真实对象
Subject realsub = new RealSubject();
//将真实对象绑定到Dynamic Proxy上,同时也通过构造函数给DynamicProxy中的真实对象赋值
InvocationHandler handler = new DynamicProxy(realsub);
//创建代理类对象
Subject subject = (Subject)Proxy.newProxyInstance
(handler.getClass().getClassLoader(), //InvocationHandler类加载
realsub.getClass().getInterfaces(), //真实对象的类接口数组,即动态代理类实现了真实类的所有接口
handler);//绑定调用操作者,把对真实类的实现方法的触发都交给InvocationHalder
//代理类对象调用了真实类的实现方法,关于这些方法的触发都交给了InvocationHandler(即会实现DynamicProxy的invoke)
subject.action();//对应method.invoke(subject, "");真实对象,方法
subject.hello("你好");//对应method.invoke(subject, arg2);真实对象,方法和参数
//总结:Proxy.newProxyInstance代理类对象负责调用,InvocationHandler调用操作者负责触发。
}
}