在看这篇文章前,可以先去了解RTTI和反射机制。
1.代理模式
什么是代理模式?例如找房子,我们可以自己找,也可以找中介代理去找,如果是自己找,首先要找到房源,然后看房、买房、签协议。如果是代理模式,房源就叫给中介代理去找,我们只需负责看房、买房、签协议就好。可以省去找房源这个麻烦的事情。
代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
代理模式可以分为静态代理和动态代理。这篇文章仅仅针对动态代理进行源码的分析。
2.JDK动态代理实现
话不多说,先上代码:
public interface IDoSometing {
void doSometing();
}
public class DoSometing implements IDoSometing {
@Override
public void doSometing() {
System.out.println("做有意义的事情,买个房吧~!");
}
}
public class MyInvocationHandler implements InvocationHandler {
//被代理对象
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 被代理对象执行前
System.out.println("中介找房子~!");
// 被代理对象执行
Object result = method.invoke(target, args);
// 被代理对象执行后
System.out.println("中介处理后续的事情");
return result;
}
public IDoSometing getProxy(){
// 返回代理对象
return (IDoSometing) Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
public static void main(String[] args) {
IDoSometing doSometing = new MyInvocationHandler(new DoSometing()).getProxy();
doSometing.doSometing();
}
测试结果:

3.Proxy源码分析
通过上面的代码我们可以知道JDK动态代理怎么去实现,那么它的底层原理是怎样的呢。接下来我们对相关的源码进行分析。在上面的代码中,首先是通过Proxy.newProxyInstance()这个静态方法来生成代理对象,我们首先从这个方法开始。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 检测InvocationHandler是否为空,为空抛NullPointerException
Objects.requireNonNull(h);
// 将接口类对象数组复制一份
final Class<?>[] intfs = interfaces.clone();
// 执行权限检查
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/**
* 这里是通过查询一个WeakCache缓存,获取代理对象
* 如果代理对象不存在,则通过静态内部类ProxyClassFactory来生成代理对象
* 这个WeakCache<K , P ,V>,K是ClassLoader , P是被代理对象所有的接口,V就是生成代理对象
*/
Class<?> cl = getProxyClass0(loader, intfs);
//调用指定的构造方法生成代理对象
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
/**
* 生成的代理类会有参数为InvocationHandler的构造方法
* 这里获取参数为InvocationHandler的构造方法
*/
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) {
//...省略以下catch部分的代码
}
}
从上面的代码分析可以知道,代理类主要是通过getProxyClass0()这个方法获取的,getProxyClass0()这个方法主要是调用WeakCache的get()方法,WeakCache查询缓存的逻辑是查询缓存,如果不存在则通过valueFactory去生成一个值。这里valueFactory其实就是Proxy静态内部类ProxyClassFactory,通过apply()这个方法来生成代理类:
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 以下都是对接口的校验
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");
}
//校验是否为一个接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
//校验是否重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
//生成代理类的包名
String proxyPkg = null;
//指定代理类访问标志,默认public final
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class<?> intf : interfaces) {
// 获取接口访问标志
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
//设置代理类访问标志位final
accessFlags = Modifier.FINAL;
//获取接口的全限定名,例如:java.lang.reflect.Proxy
String name = intf.getName();
//裁剪,例如java.lang.reflect
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) {
//如果全部都是public的接口,则生成的代理类放置默认的包下:com.sun.proxy
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
// 生成代理类全限定名,包名+前缀+序号, 例如:com.sun.proxy.$Proxy0
// num就是末尾的0,是AtomicLong,保证线程安全
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) {
throw new IllegalArgumentException(e.toString());
}
}
}
其中ProxyGenerator.generateProxyClass()来生成代理类的字节码,该方法主要是通过调用generateProxyClass()来生成的,我们直接看这个方法。
private byte[] generateClassFile() {
/* ============================================================
* 第一步:将所有方法组装成ProxyMethod对象以生产代理调度代码
*/
//为代理对象生成toString, hashCode, equals等代理方法
addProxyMethod(hashCodeMethod, Object.class);
addProxyMethod(equalsMethod, Object.class);
addProxyMethod(toStringMethod, Object.class);
// 遍历每一个接口的每一个方法, 并且为其生成ProxyMethod对象
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);
}
}
// 对于具有相同签名的每组代理方法,验证方法的返回类型是否兼容
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
/* ============================================================
* 第二步:组装要生成的class文件的所有的字段信息和方法信息
*/
try {
/**
* 生成构造方法,注意,这里会生成带有InvocationHandler参数的构造方法
*/
methods.add(generateConstructor());
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// 添加静态属性
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// 添加代理类的代理方法
methods.add(pm.generateMethod());
}
}
// 添加代理类的静态字段初始化方法
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
if (methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
/* ============================================================
* 第三步:写入class文件
*/
//省略以下写入class文件代码,不过其中有一个地方可以注意下,写入的时候写入了父类索引为"java/lang/reflect/Proxy",所以所有生成的代理类都继承于Proxy
...
}
JDK动态代理的源码分析就到这里了,大概的了解了一下实现原理,以后用到JDK动态代理也能知道它是怎么实现的了,这次分析的代码中,其实还有一个很关键的东西WeakCache,没有具体分析,下次有机会可以单独写一篇文章进行分析。
4.JDK动态代理使用场景
分析了这么多东西,总得要知道学到的东西该用在哪里吧~!这次分析JDK动态代理源码,其实就是为了更好的去了解Spring框架的AOP的实现,Spring框架AOP的实现就是通过JDK动态代理或者字节码增强来实现,JDK动态代理是生产代理类来实现,必须要实现接口才行,字节码增强是生成子类,无需继承接口。Spring框架的AOP能够非常有效的解决业务类中与业务逻辑无关代码的解耦合,能让我们不用去关心与业务逻辑无关的代码,只需注重于业务逻辑的实现,提高代码质量,也为后期维护代码提供便利。
SpringAOP只是JDK动态代理的一个使用场景,当然还有其它的使用场景,我就不一一介绍了。
网友评论