代理模式其本质是,对于需要调用的方法,在其原由逻辑上进行修改,或者说是在原有方法的基础上前后都加上log日志,或者是对原有方法的结果进行二次处理等等。
其结构图如下
目标接口,定义RealSubject和Proxy的共同接口,
具体的实现接口类,实现目标接口的功能
调用具体的实现接口类,并在具体实现类的基础上,调用其他相关方法。
静态代理的实现,我们在原来方法上,添加了前后各打印一条数据
public interface Subject {
void request();
}
具体方法调用
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("具体方法实现");
}
}
代理类方法实现
public class StaticProxy implements Subject {
private Subject subject;
public StaticProxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
System.out.println("-------start-------------");
subject.request();
System.out.println("-------end----------------");
}
}
测试代码
public class Test {
public static void main(String[] args) {
Subject subject = new RealSubject();
StaticProxy proxy = new StaticProxy(subject);
proxy.request();
}
}
执行结果
-------start-------------
具体方法实现
-------end----------------
以上就是静态代理的具体实现,接下来来看jdk提供的的动态代理实现方法
接口不发生变化
public interface Subject {
void request();
}
具体接口的实现也不变
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("hello!");
}
}
主要是代理类,这个时候继承的是jdk给我们提供的InvocationHandler
public class DynamicProxy implements InvocationHandler {
private Object target;
public Object bind(Object object){
this.target = object;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before invoke");
method.invoke(target,args);
System.out.println("after invoke");
return null;
}
}
接下来是测试类
public class TestProxy {
public static void main(String[] args) {
DynamicProxy proxy = new DynamicProxy();
Subject service =(Subject) proxy.bind(new RealSubject());
service.request();
}
}
执行结果
before invoke
hello!
after invoke
对于动态代理我们可以在调用的时候,传递进去任何一个接口的显现类,都会在具体实现类的基础上,增加上我们代理类的逻辑
关于动态代理的实现,其主要是涉及到的就是Proxy类和InvocationHandler这个接口,我们分别来看下,对于InvocationHandlerl接口
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
这个接口只提供了一个抽象发法用来实现,子类在实现的时候,需要将具体实现类对象传递进去,然后再用反射调用具体实现类的方法,同时可以增加其他的业务逻辑。
Proxy类当中提供的方法,我们这里是用到newProxyInstance来创建对象的,我们来看下源码实现,基于JDK1.8
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);
/*
* 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() {
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);
}
}
上面的代码是创建代理类对象的具体实现,我们来看下大概的流程
1、根据传递进来的ClassLoader,以及我们的代理对象的父接口数组,来动态创建二进制的class文件,然后根据创建好的Class二进制文件,获取到创建的动态类的Class对象。
2、获取到动态创建的代理的构造方法,这个构造方法的参数就是定好的,传递进去的InvocationHandler,这个是动态代理约束好的,生成的字节码中,构造方法参数就是InvocationHandler
3、判断构造方法的访问修饰符,如果不是public的,将其设置成可以访问的
4、根据传递进来的具体的Handler对象和我们上面的构造方法对象,生成一个动态代理类的对象。
上面就是整个动态代理对象的生成过程,接下来我们来看getProxyClass0方法实现
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
return proxyClassCache.get(loader, interfaces);
}
注释写的很清楚,如果当前的这个接口数组已经存在,就返回缓存当中的副本,否则的话,就会通过ProxyClassFactory去创建一个Class对象。我们来看下ProxyClassFactory是如何创建一个Class对象的吧
其实就是WeakCache这个对象当中会在get取不到值时,去生成一个值放入进去,这里不做详细分析
WeakCache<>(new KeyFactory(), new ProxyClassFactory());
ProxyClassFactory是Proxy的一个静态内部类,主要就是用来根据classLoader和接口数组来生成Class对象的。下面我就贴出其主要用来创建Class对象的代码
@Override
public Class> apply(ClassLoader loader, Class>[] interfaces) {
Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class> intf : interfaces) {
Class> interfaceClass = null;
try {
//根据接口的全限定名获取到接口的Class对象
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
// 如果两次的Class对象不一致,直接抛出异常,说明当前classloader
// 加载出来接口的Class对象和接口在项目当中的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;
//下面这个循环主要是判断非pulic的接口是不是在同一个包内
for (Class> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
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)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
//如果是公共的接口,我们就设置其全限定名为 com.sun.proxy.$Proxy0
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 这段代码就是根绝代理类的全限定名,接口数组,访问修饰符,生成代理类的字节码
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 根据生成的字节码,创建Class对象,并返回,实现方法为native
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
可以看到这段代码就是设置好需要生成的类的类名,然后调用ProxyGenerator.generateProxyClass来生成代理类的字节码,接下来我们来看下这个类的实现
public static byte[] generateProxyClass(final String var0, Class>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
//中间省略掉一部分代码
return var4;
}
这个类当中的生成代码的核心部分就是通过构建好的ProxyGenerator对象,调用其 generateClassFile()方法
private byte[] generateClassFile() {
//将object类当中的 hashcode,equals,toString方法放在了动态代理类当中
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces;
int var2 = var1.length;
int var3;
Class var4;
//遍历父接口数据
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
//获取每个接口当中的方法
Method[] var5 = var4.getMethods();
int var6 = var5.length;
//遍历接口当中的方法,将接口当中的方法都添加至动态代理类当中
for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
}
Iterator var11 = this.proxyMethods.values().iterator();
//检查代理类当中的返回类型
List var12;
while(var11.hasNext()) {
var12 = (List)var11.next();
checkReturnTypes(var12);
}
Iterator var15;
try {
// 将构造方法添加至代理类当中的方法集合中
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();
//遍历代理类当中的方法,此处使用两层循环,是因为方法签名相同的,可能有多个方法
while(var11.hasNext()) {
var12 = (List)var11.next();
var15 = var12.iterator();
while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
this.methods.add(var16.generateMethod());
}
}
// 将静态代码块添加进去
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}
if(this.methods.size() > '\uffff') {
throw new IllegalArgumentException("method limit exceeded");
} else if(this.fields.size() > '\uffff') {
throw new IllegalArgumentException("field limit exceeded");
} else {
/**
* 省略部分代码
**/
return var13.toByteArray();
} catch (IOException var9) {
throw new InternalError("unexpected I/O Exception", var9);
}
}
}
这部分就是根据父接口生成字节码,我们调用ProxyGenerator.generateProxyClass方法,然后根据我们的RealSubject对象生成一个代理类到本地。
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", RealSubject.class.getInterfaces());
String path = "C:\\Users\\Administrator\\Desktop\\com\\RealSubject.class";
try(FileOutputStream fos = new FileOutputStream(path)) {
fos.write(classFile);
fos.flush();
System.out.println("代理类class文件写入成功");
} catch (Exception e) {
System.out.println("写文件错误");
}
打开生成好的RealSubject.class文件
可以看到动态生成了一个$Proxy0的代理类,继承自Proxy类,实现了我们的Subject接口,其构造方法是传递了一个InvocationHandler参数
同时实现了equals,hashCode,toString三个方法,以及我们自己定义的接口当中的方法,我们主要看接口当中定义的request方法如何实现
这里我们可以清楚地看到,调用的InvocationHandler实现类当中的invoke方法,m3就是我们自定类当中定义的方法
到这里为止,我们就可以清楚地看到为什么在调用request方法的时候,会调用DynamicProxy当中的我们自己实现的invoke方法,因为传递过去的就是我们自己的InvokationHandler对象。动态代理类的构造方法生成之后,传递进去的就是我们调用
Proxy.newProxyInstance()这个方法传递的自己的实现类