大白话来讲,代理就是一个类代替另一个类去做一些事,在现实生活中好比媒婆代理你,去给你找对象,或者在你科学上网时,876服务器代理你的电脑去为你打开世界的大门。归纳起来,代理的过程无非就两点:谁需要被代理?代理他的人需要为他做些什么?
用稍微专业一些的话来说,只需要明确2点:1.目标类(被代理类) 2.增强(代理类需要做的事)。
代理又分为静态代理和动态代理,静态代理是在编译期就确定了目标类,直接编译生成代理类;而动态代理,在编译期不能确定目标类,需要在运行时根据需要进行代理。动态代理是通过java的反射技术来实现的,具体实现方式又分为JDK动态代理和CGLib动态代理,今天咱讨论的主角是JDK动态代理。
要实现jdk的动态代理,关键在于InvocationHandler
接口
简单来说,我们需要编写一个实现类,实现这个InvocationHandler
接口,并重写invoke
方法,在这个invoke
方法里实现具体的代理逻辑。其次,通过调用Proxy.newProxyInstance()
方法,传入InvocationHandler
实现类,生成代理对象,即可通过代理对象完成代理。
JDK动态代理是基于接口的,被代理类必须要实现某个接口,以这个接口作为被代理类和代理类之间的纽带。那么为什么一定要接口呢?别急,先来看一个demo
//被代理类
public interface SomeService {
void doService(String name);
}
public class SomeServiceImpl implements SomeService {
@Override
public void doService(String name) {
System.out.println("Services is being provided..Enjoy it.."+name);
}
}
//InvocationHandler实现类
public class MyJDKProxyFactory implements InvocationHandler {
private Object target; //被代理对象
private MyJDKProxyFactory(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method " + method.getName() + " is being invoked");
Object returnValue = method.invoke(target,args);
System.out.println("method " + method.getName() + " finished");
return returnValue;
}
public static Object getMyProxy(Object target){
MyJDKProxyFactory proxyFactory = new MyJDKProxyFactory(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),proxyFactory);
}
}
//测试类
public class Test {
public static void main(String[] args){
SomeService happyService = new SomeServiceImpl();
//获得一个代理类
SomeService proxy = (SomeService) MyJDKProxyFactory.getMyProxy(happyService);
//代理类开始做事
proxy.doService("yogurt");
}
}
结果:
method doService is being invoked
Services is being provided..Enjoy it..yogurt
method doService finished
可见好像确实是调用了InvocationHandler
实现类中的invoke
方法,我们将生成的代理类的class文件保存下来,反编译看看
//默认情况,jdk动态代理生成的代理类的class文件,存在内存中
//下面将生成的代理类的class文件持久化到磁盘
public static void generateProxyClassFile(String proxyName,Class clazz){
byte[] bs = ProxyGenerator.generateProxyClass(proxyName,clazz.getInterfaces());
String path = clazz.getResource(".").getPath();
FileOutputStream fileOut = null;
try{
fileOut = new FileOutputStream(path + proxyName+".class");
fileOut.write(bs);
fileOut.flush();
fileOut.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
SomeService happyService = new SomeServiceImpl();
generateProxyClassFile("$happyProxy",happyService.getClass());
}
下面是生成的$happyProxy.class
文件反编译的结果
import com.yogurt.SomeService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $happyProxy extends Proxy implements SomeService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $happyProxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void doService(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.yogurt.SomeService").getMethod("doService", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
粗略一看,生成的代理类,继承了Proxy
类,并实现了SomeService
接口,调用代理类的doService()
方法时,实际是调用了Proxy
类中的InvocationHandler
对象的invoke()
方法,故我们需要编写一个InvocationHandler
实现类,并作为入参传递给Proxy.newProxyInstance()
方法,并且,为什么被代理类必须要实现某个接口,也能找到答案了,因为生成的代理类,本身继承了Proxy
类,而出于安全考虑,java是不允许多继承的,故只能用接口来作为被代理类与代理类之间的纽带。
进一步深究,我们可以进入Proxy
的源码,看看Proxy.newProxyInstance()
究竟做了什么
public class Proxy implements java.io.Serializable {
/** parameter types of a proxy class constructor */
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
/**
* a cache of proxy classes
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
//.....
/** 省略其余源码*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
}
可以看到,newProxyInstance()
的入参有3个,一个ClassLoader
,一个interface
数组,一个InvocationHandler
。函数内部的大致流程如下:
首先对InvocationHandler
对象进行了非空检测,随后是一些安全性检测,然后调用Class c1 = getProxyClass0(loader,intfs)
,根据入参的ClassLoader
和interface
数组去生成代理类(回看前面我们手动生成代理类的class文件时的操作,这里的操作类似),随后调用final Constructor<?> cons = cl.getConstructor(constructorParams);
获取代理类的一个构造函数,这个构造函数的入参是一个InvocationHandler
(因为constructorParams变量为{InvocationHandler.class}
),最后执行cons.newInstance(new Object[]{h})
,调用(代理类的)构造方法,将入参中的InvocationHandler
对象传入,生成代理类实例,并返回该实例。
总结:
-
JDK的动态代理是以接口为纽带,通过
java.lang.reflect
包下的Proxy
,InvocationHandler
来实现的 -
实现JDK动态代理,需要满足:
-
被代理类需要实现某个接口
-
需要一个实现
InvocationHandler
的类(假设类名为MyProxyFactory
)-
需要注入一个
Object
对象target
,是目标类(被代理类)的一个实例,用于在invoke
中调用它的方法 -
重写
invoke()
方法,在invoke
方法中执行代理的逻辑(一般是执行method.invoke(target)
(调用目标类的方法),并在执行这行代码之前或之后进行一些额外操作(其实就是AOP的前置通知和后置通知)) -
一般还会提供一个静态方法,用于获取代理类,如下
public static Object getProxy(Object target){ InvocationHandler h = new MyProxyFactory(); return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),h); }
-
-
完