spring 和 mybatis 都用到了代理,在学习之前先扒一下jdk动态代理。
静态代理
可以简单理解为中介。
场景:中介在消费者和厂家之间赚取差价。
public interface IManufacture {
/**
* 制造
*
* @return {@link Object}
*/
Object manufacture();
}
public class ManufactureFactory implements IManufacture{
/**
* 制造
*
* @return {@link Object}
*/
@Override
public Object manufacture() {
return "制造工厂";
}
}
public class StaticProxy implements IManufacture {
private ManufactureFactory factory;
StaticProxy() {
}
public StaticProxy(ManufactureFactory factory) {
this.factory = factory;
}
/**
* 制造
*
* @return {@link Object}
*/
@Override
public Object manufacture() {
factory.manufacture();
return getSpread();
}
private String getSpread() {
return "静态代理增强";
}
}
// 厂家直销
@Test
public void proxyTest01() {
IManufacture manufacture = new ManufactureFactory();
System.out.println(manufacture.manufacture());
}
// 中介
@Test
public void proxyTest02() {
IManufacture manufacture = new StaticProxy(new ManufactureFactory());
System.out.println(manufacture.manufacture());
}
测试结果:
可以看到,静态代理做的事情就是在原有逻辑上添加自己的逻辑。
问题: 中介现在只对一家工厂做代理销售,如果格局大一点,承包更多的厂家。
如果用静态代理的方式,需要定义更多的静态代理类实现厂家接口,这么做可以实现,但是类有点多,主要是不太优雅。。。看看动态代理又是如何实现的。
动态代理
上面把静态代理当做是中介,如果对N个厂家做代理,需要创建N个代理类。
这N个代理各自做各自的业务,突然有一天,云朵姐要去割双眼皮,但是下午要和客户签合同,于是就让优雅哥帮忙,优雅哥动了一下脑子:“我们何不成立一个中介公司嘞?”,于是优雅中介成立了。
优雅中介就可以看做是 动态代理 ,消费者需要某厂家的产品时,优雅中介就会派出对应的中介进行服务(这个过程就是创建动态代理的过程),优雅中介也是一个 代理工厂 。
public class DynamicProxy implements InvocationHandler {
private Object o;
DynamicProxy() {
}
public DynamicProxy(Object o) {
this.o = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(o, args);
return getSpread();
}
// 创建代理
public Object createProxy() {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
}
private String getSpread() {
return "动态代理增强";
}
}
测试结果:
@Test
public void proxyTest03() {
DynamicProxy dynamicProxy = new DynamicProxy(new ManufactureFactory());
IManufacture manufacture = (IManufacture) dynamicProxy.createProxy();
System.out.println(manufacture.manufacture());
}
JDK动态代理源码解析
其实原理上面已经说了,无非就是创建代理类,然后调用代理类的方法,体现到代码里面又是如何实现的?
生成代理类
// 创建代理
public Object createProxy() {
return Proxy.newProxyInstance(o.getClass().getClassLoader(),
o.getClass().getInterfaces(),
this);
}
@CallerSensitive
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信息
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
...
final Constructor<?> cons = cl.getConstructor(constructorParams);
...
// 通过反射生成代理类
return cons.newInstance(new Object[]{h});
} ...
}
入参:
- ClassLoader loader 厂家类的 类加载器
- Class<?>[] interfaces 厂家类实现的接口
- InvocationHandler h 厂家对象
18 行:生成代理类的Class
26 行:拿到代理类的Class的构造方法
31 行:反射生成代理对象
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);
}
3~5 行:一个小知识点,
一个类最多只能实现65535个接口
public V get(K key, P parameter) {
...
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(
subKeyFactory.apply(key, parameter)
);
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
...
}
先从缓存获取,主要看创建的过程。
8 行:创建代理
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
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;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
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");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
// proxyClassNamePrefix = "$Proxy"
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
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());
}
}
这个apply()就是具体生成代理类Class的地方。
62 行:设置类路径
69 行:设置类名:"$Proxy" + long数字
75 行:把代理类Class信息写入byte数组中, defineClass0()是个native方法,这就走到头了,可以把byte数组输出看一下
@Test
public void proxyTest03() {
// 目标类
IManufacture manufactureFactory = new ManufactureFactory();
// 代理工厂
DynamicProxy dynamicProxy = new DynamicProxy(manufactureFactory);
// 代理
IManufacture proxy = (IManufacture) dynamicProxy.createProxy();
System.out.println(proxy.manufacture());
// 输出代理类信息
getProxyClassInfo(IManufacture.class, proxy.getClass().getSimpleName());
}
private void getProxyClassInfo(Class clazz, String proxyName) {
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, new Class[]{clazz});
// 输出到和厂家对象相同的路径
String path = clazz.getResource(".").getPath();
FileOutputStream out = null;
try {
out = new FileOutputStream(path + proxyName + ".class");
out.write(proxyClassFile);
out.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.springframework.nineq.jdk8.proxy.IManufacture;
public final class $Proxy12 extends Proxy implements IManufacture {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy12(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 Object manufacture() throws {
try {
return (Object)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 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"));
m3 = Class.forName("org.springframework.nineq.jdk8.proxy.IManufacture").getMethod("manufacture");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
和静态代理一样,动态代理和目标类(厂家类)实现了相同的接口,也就有了同样的实现方法 manufacture()
调用代理类方法
代理类对象已经有了,再看一下调用。
调用肯定是调用代理对象的 manufacture()方法,看代理类的manufacture()方法:
// 制造方法
public final Object manufacture() throws {
try {
return (Object)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
4 行:super.h.invoke(),那就是Proxy类的 h 属性的 invoke(),h 又是什么?
还记得上面创建代理最开始的地方么,传了三个参数,第三个参数就是 h,也就是我们的代理工厂 DynamicProxy(InvocationHandler 的实现类)
最终会调用到 DynamicProxy#invoke(Object proxy, Method method, Object[] args)
public class DynamicProxy implements InvocationHandler {
private Object o;
DynamicProxy() {
}
public DynamicProxy(Object o) {
this.o = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(o, args);
return getSpread();
}
public Object createProxy() {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
}
private String getSpread() {
return "动态代理增强";
}
}
15 行:也就是我们自己写的这个方法,逻辑就很清楚了吧。
JDK动态代理的使用方法
- 首先确认目标类,也就是需要被代理的类
- 创建InvocationHandler实现类,在invoke方法写自己逻辑即可。
总结
代理就是在不改变原有代码的前提下,加上我们自己的功能。
JDK动态代理,需要实现InvocationHandler接口,重写invoke方法。
注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。