动态代理:在程序运行时,通过反射机制动态的创建一个代理类
先来一个小Demo,逐步理解动态代理
1.声明一个接口,里面有一个move的方法
public interface Moveable {
void move();
}
2.创建一个Tank类,实现上面的接口,重写方法:
public class Tank implements Moveable{
@Override
public void move() {
System.out.println("Tank Moving");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
问题1:想知道这个方法运行了多少时间?
简单啊,在方法前后加个currentTimeMills()就行了。
@Override
public void move() {
long start = System.currentTimeMillis();
//中间代码略过
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
问题2:假如无法更改move方法,我们没法在原来的源码上进行修改,而这时我们想知道这个方法运行了多长时间,该怎么做?
方法一:新建一个类继承Tank,既然能继承就能重写Tank的方法:也就是用继承来实现把原来的方法前后添加一些逻辑:
public class Tank2 extends Tank {
@Override
public void move() {
long start = System.currentTimeMillis();
super.move();
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
方法二:新建一个Tank3类,类中添加一个Tank的引用,这种方式是用聚合的方式实现的:
public class Tank3 implements Moveable{
private Tank t;
public Tank getT() {
return t;
}
public void setT(Tank t) {
this.t = t;
}
public Tank3(Tank t){
this.t = t;
}
@Override
public void move() {
long start = System.currentTimeMillis();
t.move();
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
上面两种方式:聚合的实现方式是比继承方式好的,为什么呢?
先对代码进行修改:
记录时间的代理类:
public class TankTimeProxy implements Moveable{
private Tank t;
public Tank getT() {
return t;
}
public void setT(Tank t) {
this.t = t;
}
public TankTimeProxy(Tank t){
this.t = t;
}
@Override
public void move() {
long start = System.currentTimeMillis();
t.move();
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
记录日志的代理类:
public class TankLogProxy implements Moveable{
private Tank t;
public Tank getT() {
return t;
}
public void setT(Tank t) {
this.t = t;
}
public TankLogProxy(Tank t){
this.t = t;
}
@Override
public void move() {
System.out.println("Tank start");
t.move();
System.out.println("tank end");
}
}
如果现在要实现记录时间和记录日志功能的叠加,应该怎么做?
现在如果使用继承的方式实现代理,就会变得十分笨重,类会无限的增加下去,而且各种各样的代理的功能要实现叠加的话,这个类的继承的层次会变得非常复杂。
如果用聚合的方式来实现:
public class TankLogProxy implements Moveable{
Moveable t;
public TankLogProxy(Moveable t){
this.t = t;
}
@Override
public void move() {
System.out.println("Tank start");
t.move();
System.out.println("tank end");
}
}
public class TankTimeProxy implements Moveable{
Moveable t;
public TankTimeProxy(Tank t){
this.t = t;
}
@Override
public void move() {
long start = System.currentTimeMillis();
t.move();
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
测试:
public class Client {
public static void main(String[] args) {
Tank t = new Tank();
TankTimeProxy ttp = new TankTimeProxy(t);
TankLogProxy tlp = new TankLogProxy(ttp);
Moveable m = tlp;
m.move();
}
}
上面是日志里面包裹着时间,那么我们想让时间包着日志呢?
public class Client {
public static void main(String[] args) {
Tank t = new Tank();
TankLogProxy tlp = new TankLogProxy(t);
TankTimeProxy ttp = new TankTimeProxy(tlp);
Moveable m = ttp;
m.move();
}
}
这种聚合方式可以让代理类之间灵活的组合,只要实现统一接口。
上面只是介绍了静态代理。
现在:如果Movable中增加了一个方法,那么他的实现类也要增加相应的方法。而在TankTimeProxy中想要知道新的方法的执行时间,还要将currentTimeMills()重新写一遍,如下所示
public interface Moveable {
void move();
void stop();
}
public class TankTimeProxy implements Moveable{
Moveable t;
public TankTimeProxy(Moveable t){
this.t = t;
}
@Override
public void move() {
long start = System.currentTimeMillis();
t.move();
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
@Override
public void stop() {
long start = System.currentTimeMillis();
t.stop();
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
public class Tank implements Moveable{
@Override
public void move() {
long start = System.currentTimeMillis();
System.out.println("Tank Moving");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
/* long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));*/
}
@Override
public void stop() {
System.out.println("Tank Stoping..");
}
}
当在写代码的时候,发现有些代码总是反复的写,这时候就要考虑将他们封装起来。
现在,如果想再加一个Car类上的时间的代理,如果用上的方式,还需要新建一个CarTimeProxy。如果有很多类,就需要新建很多代理类。这时,如果搞一个通用的时间代理类,可以代理任意的对象就好了。
新建一个Proxy类:
public class Proxy {
//用来产生新的代理类
public static Object newProxyInstance(){
return null;
}
}
现在我们假设上面类已经能产生代理了,客户端就可以这样写:
public class Client {
public static void main(String[] args) {
Tank t = new Tank();
Moveable m = (Moveable)Proxy.newProxyInstance();
m.move();
}
}
但是Proxy类是如何代理的呢?
这就是动态代理了。动态代理的意思就是:我们不需要知道TankTimeProxy这个类的名字,我们需要的那个代理对象直接产生,
public class Proxy {
//用来产生新的代理类
public static Object newProxyInstance(){
String src = "package com.yuanben.msbproxy;"+
"public class TankTimeProxy implements Moveable{"+
"public TankTimeProxy(Moveable t){"+
"super();"+
"this.t = t;"+
"}"+
"Moveable t;"+
"@Override"+
"public void move() {"+
"long start = System.currentTimeMillis();"+
"t.move();"+
"long end = System.currentTimeMillis();"+
"System.out.println(\"Time:\"+(end-start));"+
"}"+
"}";
return null;
}
}
在Proxy的newProxyInstance方法内部会自动的返回一个具体的代理,而这个代理是怎么实现的呢?实际上是内部自己生成一段代码,这段代码编译完成之后生成一个具体的对象。现在的问题是如果我们能动态编译这段代码的话,就能生成动态的代理类。
实现动态代理的方式:JDK、CGlib、ASM。
如何编译:
public class Test1 {
public static void main(String[] args) throws Exception{
String rt = "\r\n";
String src = "package com.yuanben.msbproxy;"+rt+
"public class TankTimeProxy implements Moveable{"+rt+
"public TankTimeProxy(Moveable t){"+rt+
"super();"+rt+
"this.t = t;"+rt+
"}"+rt+
"Moveable t;"+rt+
"@Override"+rt+
"public void move() {"+rt+
"long start = System.currentTimeMillis();"+rt+
"t.move();"+rt+
"long end = System.currentTimeMillis();"+rt+
"System.out.println(\"Time:\"+(end-start));"+rt+
"}"+rt+
"}";
String fileName = System.getProperty("user.dir")+
"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
}
}
运行代码:发现生生成了TankTimeProxy类:
Test1类中加如下代码:
//得到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
t.call();
fileManager.close();
运行:编译成功
生成代理类:
public class Test1 {
public static void main(String[] args) throws Exception{
String rt = "\r\n";
String src = "package com.yuanben.msbproxy;"+rt+
" public class TankTimeProxy implements Moveable{"+rt+
" public TankTimeProxy(Moveable t){"+rt+
" super();"+rt+
" this.t = t;"+rt+
" }"+rt+
" Moveable t;"+rt+
" @Override"+rt+
" public void move() {"+rt+
" long start = System.currentTimeMillis();"+rt+
" t.move();"+rt+
" long end = System.currentTimeMillis();"+rt+
" System.out.println(\"Time:\"+(end-start));"+rt+
" }"+rt+
"}";
String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";
// File f = new File(fileName);
// FileWriter fw = new FileWriter(f);
// fw.write(src);
// fw.flush();
// fw.close();
//得到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
t.call();
fileManager.close();
//将编译好的class文件加载进内存并生成一个对象
URL[] urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
System.out.println(c);
//生成一个对象:反射
Constructor constructor = c.getConstructor(Moveable.class);
Moveable m = (Moveable)constructor.newInstance(new Tank());
m.move();
}
}
运行:
到此为止,Proxy只能产生实现了Moveable接口的类的代理,如果现在要实现别的类的动态代理,应该怎么做?
方案:把接口传进去,对Proxy进行改造:
public class Proxy {
//用来产生新的代理类
public static Object newProxyInstance(Class infce) throws Exception{
String rt = "\r\n";
String src = "package com.yuanben.msbproxy;"+rt+
" public class TankTimeProxy implements "+infce.getName()+"{"+rt+
" public TankTimeProxy(Moveable t){"+rt+
" super();"+rt+
" this.t = t;"+rt+
" }"+rt+
" Moveable t;"+rt+
" @Override"+rt+
" public void move() {"+rt+
" long start = System.currentTimeMillis();"+rt+
" t.move();"+rt+
" long end = System.currentTimeMillis();"+rt+
" System.out.println(\"Time:\"+(end-start));"+rt+
" }"+rt+
"}";
String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//得到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
t.call();
fileManager.close();
//将编译好的class文件加载进内存并生成一个对象
URL[] urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
System.out.println(c);
//生成一个对象:反射
Constructor constructor = c.getConstructor(Moveable.class);
Moveable m = (Moveable)constructor.newInstance(new Tank());
m.move();
return null;
}
}
直接传递接口即可:
现在要获取传进入的接口中有多少方法:还是用反射的知识:
public class Test2 {
public static void main(String[] args) {
Method[] methods = com.yuanben.msbproxy.Moveable.class.getMethods();
Arrays.stream(methods).forEach(method -> System.out.println(method));
}
}
再做改进:生成实现方法:
public class Proxy {
//用来产生新的代理类
public static Object newProxyInstance(Class infce) throws Exception{
String rt = "\r\n";
String methodStr = "";
Method[] methods = infce.getMethods();
for (Method m:methods
) {
methodStr += "@Override" + rt +
"public void "+m.getName()+"() {"+rt+
" long start = System.currentTimeMillis();"+rt+
" t."+m.getName()+"();"+rt+
" long end = System.currentTimeMillis();"+rt+
" System.out.println(\"Time:\"+(end-start));"+rt+
"}";
}
String src = "package com.yuanben.msbproxy;"+rt+
" public class TankTimeProxy implements "+infce.getName()+"{"+rt+
" public TankTimeProxy(Moveable t){"+rt+
" super();"+rt+
" this.t = t;"+rt+
" }"+rt+
" Moveable t;"+rt+
methodStr+
"}";
String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//得到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
t.call();
fileManager.close();
//将编译好的class文件加载进内存并生成一个对象
URL[] urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
System.out.println(c);
//生成一个对象:反射
Constructor constructor = c.getConstructor(Moveable.class);
/* Moveable m = (Moveable)constructor.newInstance(new Tank());
m.move();*/
return null;
}
}
测试:已经帮我们成功生成
如果换成别的接口:
public class Client {
public static void main(String[] args) throws Exception{
Tank t = new Tank();
Moveable m = (Moveable)Proxy.newProxyInstance(Comparable.class);
}
}
会帮我们生成Comparable接口中的方法
那好,现在又有新的问题了。现在我们生成的代理的中间逻辑是固定的,只能生成运行时间的代理功能,如果要生成日志代理,这个方法就不行了,我们就需要写一个新的方法newProxyInstence2用来生成日志代理。。。。这时候我们应该怎么办?让中间的业务逻辑让用户来指定。也就是我们需要对一个任意的方法进行自定义的处理。思路如下:
声明一个接口,含一个方法:
public interface InvocationHandler {
void invoke(Method method);
}
写一个实现类,加上自己想要的处理逻辑:
public class TimeHandler implements InvocationHandler {
//将想要调用的方法传入进来
@Override
public void invoke(Method m) {
long start = System.currentTimeMillis();
System.out.println("startTime:"+start);
m.getName();
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
现在,对方法的处理就变得更灵活了。那里面的方法是如何调用的呢?往下看:
在接口方法中添加一个Object参数,表示那个对象去调用这个方法:
public interface InvocationHandler {
void invoke(Object o,Method method);
}
实现类做如下修改:
public class TimeHandler implements InvocationHandler {
//将想要调用的方法传入进来
@Override
public void invoke(Object o,Method m) {
long start = System.currentTimeMillis();
System.out.println("startTime:"+start);
try {
m.invoke(o,new Object[]{ });
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
Proxy类:
public class Proxy {
//用来产生新的代理类
public static Object newProxyInstance(Class infce,InvocationHandler h) throws Exception{
String rt = "\r\n";
String methodStr = "";
Method[] methods = infce.getMethods();
for (Method m:methods) {
methodStr += "@Override" + rt +
"public void "+m.getName()+"() {"+rt+
" try{"+rt+
" Method md = "+infce.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+
" h.invoke(this,md);"+rt+
" }catch(Exception e){"+rt+
" e.printStackTrace(); }"+rt+
"}";
}
String src = "package com.yuanben.msbproxy;"+rt+
" import java.lang.reflect.Method;"+rt+
" public class TankTimeProxy implements "+infce.getName()+"{"+rt+
" public TankTimeProxy(InvocationHandler h){"+rt+
" super();"+rt+
" this.h = h;"+rt+
" }"+rt+
" com.yuanben.msbproxy.InvocationHandler h;"+rt+
methodStr+
"}";
String fileName = System.getProperty("user.dir")+"/spring_aop/src/com/yuanben/msbproxy/TankTimeProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//得到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
t.call();
fileManager.close();
//将编译好的class文件加载进内存并生成一个对象
URL[] urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/spring_aop/src")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.yuanben.msbproxy.TankTimeProxy");
System.out.println(c);
//生成一个对象:反射
Constructor constructor = c.getConstructor(InvocationHandler.class);
Object m = constructor.newInstance(h);
//将对象返回出去
return m;
}
}
运行,生成需要的代理类:
TimeHandler:
public class TimeHandler implements InvocationHandler {
//被代理的对象
private Object target;
public Object getT() {
return target;
}
public void setT(Object t) {
this.target = t;
}
public TimeHandler(Object target){
super();
this.target = target;
}
//将想要调用的方法传入进来
@Override
public void invoke(Object o,Method m) {
long start = System.currentTimeMillis();
System.out.println("startTime:"+start);
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("Time:"+(end-start));
}
}
Client类:
public class Client {
public static void main(String[] args) throws Exception{
Tank t = new Tank();
InvocationHandler h = new TimeHandler(t);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
m.move();
}
}
结果:
其实JDK实现的动态代理的思路也和上面的步骤类似。下面分析一下JDK实现动态代理的源码:解析都在代码注释中:
/**
* {@code Proxy}代理类:为创建动态代理类和实例提供静态方法,同样也是所有通过那些方法创建动态代理的超类
*/
public class Proxy implements java.io.Serializable {
private static final long serialVersionUID = -2222568056686623797L;
/** 代理构造函数的参数类型 */
private static final Class>[] constructorParams =
{ InvocationHandler.class };
/**
*代理类缓存
*/
private static final WeakCache[], Class>>
proxyClassCache = new WeakCache<>(new java.lang.reflect.Proxy.KeyFactory(), new java.lang.reflect.Proxy.ProxyClassFactory());
/**
* 此代理实例的调用处理程序。
* @serial
*/
protected InvocationHandler h;
/**
* Prohibits instantiation.
*/
private Proxy() {
}
/**
构造器,
*/
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
//获取目标代理类的Class对象,需传入类加载器对象和被代理类实现接口数组
@CallerSensitive
public static Class> getProxyClass(ClassLoader loader,
Class>... interfaces)
throws IllegalArgumentException
{
//克隆接口数组
final Class>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
//校验代理类的访问权限
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//获取代理类的Class对象
return getProxyClass0(loader, intfs);
}
/*
校验代理类的访问权限
*/
private static void checkProxyAccess(Class> caller,
ClassLoader loader,
Class>... interfaces)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
//获取调用者的类加载器
ClassLoader ccl = caller.getClassLoader();
if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
}
}
/**
* 生成一个代理类. 在调用此方法之前,必须调用checkProxyAccess方法来执行权限检查。
*/
private static Class> getProxyClass0(ClassLoader loader,
Class>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
/*
如果当前这个接口数组已经存在就返回缓存中的副本,否则的话,就会通过ProxyClassFactory去创建一个Class对象
*/
return proxyClassCache.get(loader, interfaces);
}
/*
* 用于带有0个实现接口的代理类的key值
*/
private static final Object key0 = new Object();
/*
* Key1 and Key2 are optimized for the common use of dynamic proxies
* that implement 1 or 2 interfaces.
*/
/*
* 用于带有1个实现接口的代理类的key值
*/
private static final class Key1 extends WeakReference> {
private final int hash;
Key1(Class> intf) {
super(intf);
this.hash = intf.hashCode();
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
Class> intf;
return this == obj ||
obj != null &&
obj.getClass() == java.lang.reflect.Proxy.Key1.class &&
(intf = get()) != null &&
intf == ((java.lang.reflect.Proxy.Key1) obj).get();
}
}
/*
*用于带有2个实现接口的代理类的key值
*/
private static final class Key2 extends WeakReference> {
private final int hash;
//弱引用对象:存放第二个接口类对象
private final WeakReference> ref2;
Key2(Class> intf1, Class> intf2) {
super(intf1);
hash = 31 * intf1.hashCode() + intf2.hashCode();
ref2 = new WeakReference>(intf2);
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
Class> intf1, intf2;
return this == obj ||
obj != null &&
obj.getClass() == java.lang.reflect.Proxy.Key2.class &&
(intf1 = get()) != null &&
intf1 == ((java.lang.reflect.Proxy.Key2) obj).get() &&
(intf2 = ref2.get()) != null &&
intf2 == ((java.lang.reflect.Proxy.Key2) obj).ref2.get();
}
}
/*
这里用于带有>=3个接口的代理类的key键值
*/
private static final class KeyX {
//接口数组对象的hash值
private final int hash;
//弱引用对象数组:存放表示接口的类对象数组
private final WeakReference>[] refs;
@SuppressWarnings("unchecked")
KeyX(Class>[] interfaces) {
hash = Arrays.hashCode(interfaces);
//构造一个弱引用对象数组
refs = (WeakReference>[])new WeakReference>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
refs[i] = new WeakReference<>(interfaces[i]);
}
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
return this == obj ||
obj != null &&
obj.getClass() == java.lang.reflect.Proxy.KeyX.class &&
equals(refs, ((java.lang.reflect.Proxy.KeyX) obj).refs);
}
private static boolean equals(WeakReference>[] refs1,
WeakReference>[] refs2) {
//长度是否相等
if (refs1.length != refs2.length) {
return false;
}
//弱引用对象数组内接类是否相同
for (int i = 0; i < refs1.length; i++) {
Class> intf = refs1[i].get();
if (intf == null || intf != refs2[i].get()) {
return false;
}
}
return true;
}
}
/**
* 将接口数组映射到一个最佳键的函数,其中表示接口的类对象为弱引用
*/
private static final class KeyFactory
implements BiFunction[], Object>
{
@Override
public Object apply(ClassLoader classLoader, Class>[] interfaces) {
switch (interfaces.length) {
case 1: return new java.lang.reflect.Proxy.Key1(interfaces[0]); // the most frequent
case 2: return new java.lang.reflect.Proxy.Key2(interfaces[0], interfaces[1]);
case 0: return key0;
default: return new java.lang.reflect.Proxy.KeyX(interfaces);
}
}
}
/**
是Proxy中的一个静态内部类:主要用来根据ClassLoader和接口数组来生成Class对象的
*/
private static final class ProxyClassFactory
implements BiFunction[], Class>>
{
// 所有代理类名称的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 用于生成唯一代理类名称的下一个数字
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class> apply(ClassLoader loader, Class>[] interfaces) {
Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class> intf : interfaces) {
/*
验证Intf接口类Class对象是否为给定的ClassLoader解析的
*/
Class> interfaceClass = null;
try {
//根据接口的全限定名获取接口Class对象
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
//验证是否为同一个接口类对象,如果两次的Class对象不一致,直接抛出异常,
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
判断父接口是否为接口类型,如果不是则抛出异常
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* 判断我们的set集合中是否已经有重复的接口
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
判断非public接口是都在同一个包内
*/
for (Class> intf : interfaces) {
//获取修饰符
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) { //不是public修饰符
//则定义代理类的修饰符:final
accessFlags = Modifier.FINAL;
//获取接口类名称:
String name = intf.getName();
int n = name.lastIndexOf('.');
//获取包名
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {//interface含有来自不同包的非公共接口
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果没有非公共代理接口,请使用com.sun.proxy作为包名称
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* 选择要生成的代理类的名称
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 真正生成指定代理类字节码的地方
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//生成Class对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
/**
该方法流程:
1.根据传进来的ClassLoader,以及我们的代理对象的父接口数组,来动态的出那个键二进制的Class文件,
然后根据创建好的Class二进制文件,获取到创建的动态类的Class对象
2.获取到动态创建的代理的构造方法,这个构造方法的参数是定好的,传进去的InvocationHandler,
这个是动态代理约束好的,生成的字节码中,构造方法的参就是InvocationHandler
3.判断构造方法的访问修饰符,如果不是Public,将其设置成可以访问的
4.根据传递进来的具体的Handler对象和我们上面的构造方法对象,生成一个动态代理类的对象
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//handler的非空判断
Objects.requireNonNull(h);
//将代理类的接口复制出来一份
final Class>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 根据classLoader和接口数组生成Class对象
*/
Class> cl = getProxyClass0(loader, intfs);
/*
使用指定的调用处理程序调用其构造函数。
*/
try {
if (sm != null) {
//校验新代理类的权限
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获取到动态生成的代理类的构造方法,参数类型必须为InvocationHandler
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
//判断构造方法的访问修饰符,如果不是Public,将其设置成可以访问的
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
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);
}
}
private static void checkNewProxyPermission(Class> caller, Class> proxyClass) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
//调用类加载器
ClassLoader ccl = caller.getClassLoader();
//代理类的类加载器
ClassLoader pcl = proxyClass.getClassLoader();
// do permission check if the caller is in a different runtime package
// of the proxy class
//获取代理类的包名
int n = proxyClass.getName().lastIndexOf('.');
String pkg = (n == -1) ? "" : proxyClass.getName().substring(0, n);
//获取调用者包名
n = caller.getName().lastIndexOf('.');
String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
//类加载器不相同或包名不相同,校验权限
if (pcl != ccl || !pkg.equals(callerPkg)) {
sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
}
}
}
}
//用于判断指定类对象是否是一个动态代理类
public static boolean isProxyClass(Class> cl) {
return java.lang.reflect.Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
}
//该方法用于获取指定代理对象所关联的调用处理器
@CallerSensitive
public static InvocationHandler getInvocationHandler(Object proxy)
throws IllegalArgumentException
{
/*
* 验证该随心实际上是否为上一个代理实例
*/
if (!isProxyClass(proxy.getClass())) {
throw new IllegalArgumentException("not a proxy instance");
}
final java.lang.reflect.Proxy p = (java.lang.reflect.Proxy) proxy;
final InvocationHandler ih = p.h;
if (System.getSecurityManager() != null) {
Class> ihClass = ih.getClass();
Class> caller = Reflection.getCallerClass();
if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
ihClass.getClassLoader()))
{
ReflectUtil.checkPackageAccess(ihClass);
}
}
return ih;
}
private static native Class> defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
}
到这里,应该对JDK实现动态代理的理解又深入一点了。