JAVA代理源码详解,手动撸一个属于自己的代理
一:常用的java代理模式
一般经常做java开发的知道java的代理模式一共有三种,第一种也就是静态代理,这种用法比较简单,没有什么魔法棒,比较好理解,另外两种分别是JDK代理和cglib代理,他们分别是对接口代理和对class类本身进行代理,jdk代理要求类必须实现有一个或者多个接口,对接口进行字节码增强在内存中实现新的class类去反射调用用户target的实现类,这里需要说明的是不管是cglic代理也好还是jdk代理他们在内存中都要占据方法区资源(jdk8 叫原空间),从而达到代理目的,而cglib代理是对class类本身进行字节码增强配合fastclass来实现代理,关于更多的cglib和jdk代理相关的内容大家可以google搜索一下,网上有很多这里不做再多的说明。下面我们摒弃jdk,和cglib的复杂源码来自己实现一个代理模式,来更深刻的了解一下代理究竟是怎么形成的。
二:JDK代理源码分析
②被代理类实现业务接口;
③定义代理类并实现业务接口;
④最后便可通过客户端进行调用。(这里可以理解成程序的main方法里的内容)
我们按照这个步骤去实现静态代理。需求:在向数据库添加一个用户时前后打印日志。
public interface IUserService {
void add(String name);
}
UserServiceImpl.java
public class UserServiceImpl implements IUserService{
@Override
public void add(String name) {
System.out.println("数据库中插入: "+name+" 的用户");
}
}
MyInvocationHandler.java
public class MyInvocationHandler implements InvocationHandler {
//被代理对象,Object类型
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 returnvalue = method.invoke(target, args);
System.out.println("插入数据库成功");
return returnvalue;
}
}
测试类
public static void main(String[] args) {
IUserService target = new UserServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(target);
IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
target.getClass().getInterfaces(), handler);
proxyObject.add("张玉龙");
}
使用上非常简单、网上demo也很多,不做充分讲解,对jdk代理用法的小伙伴如果还不熟悉这块代码,就先了解一下jdk代理的使用方式,然后在回来继续看下面的源码分析
JDK代理源码深度分析
Proxy.newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)
产生了代理对象,所以我们进到
newProxyInstance
的实现:
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);
}
}
getProxyClass0(loader, intfs)
得到代理类的Class对象,然后通过Class对象得到构造方法,进而创建代理对象。下一步看
getProxyClass0
这个方法。
//此方法也是Proxy类下的方法
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
//意思是:如果代理类被指定的类加载器loader定义了,并实现了给定的接口interfaces,
//那么就返回缓存的代理类对象,否则使用ProxyClassFactory创建代理类。
return proxyClassCache.get(loader, interfaces);
}
这里看到proxyClassCache,有Cache便知道是缓存的意思,正好呼应了前面Look up or generate the designated proxy class。查询(在缓存中已经有)或生成指定的代理类的class对象这段注释。
proxyClassCache
是个WeakCache类的对象,调用proxyClassCache.get(loader, interfaces); 可以得到缓存的代理类或创建代理类(没有缓存的情况)。说明WeakCache中有
get
这个方法。先看下WeakCache类的定义(这里先只给出变量的定义和构造函数):
//K代表key的类型,P代表参数的类型,V代表value的类型。
// WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache 说明proxyClassCache存的值是Class<?>对象,正是我们需要的代理类对象。
final class WeakCache<K, P, V> {
private final ReferenceQueue<K> refQueue
= new ReferenceQueue<>();
// the key type is Object for supporting null key
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
= new ConcurrentHashMap<>();
private final BiFunction<K, P, ?> subKeyFactory;
private final BiFunction<K, P, V> valueFactory;
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
(key, sub-key) -> value
。其中key是传进来的Classloader进行包装后的对象,sub-key是由WeakCache构造函数传人的
KeyFactory()
生成的。value就是产生代理类的对象,是由WeakCache构造函数传人的
ProxyClassFactory()
生成的
好,大体上说完WeakCache这个类的作用,我们回到刚才
proxyClassCache.get(loader, interfaces);
这句代码。get是WeakCache里的方法。源码如下
//K和P就是WeakCache定义中的泛型,key是类加载器,parameter是接口类数组
public V get(K key, P parameter) {
//检查parameter不为空
Objects.requireNonNull(parameter);
//清除无效的缓存
expungeStaleEntries();
// cacheKey就是(key, sub-key) -> value里的一级key,
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
//根据一级key得到 ConcurrentMap<Object, Supplier<V>>对象。如果之前不存在,则新建一个ConcurrentMap<Object, Supplier<V>>和cacheKey(一级key)一起放到map中。
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
//这部分就是调用生成sub-key的代码,上面我们已经看过怎么生成的了
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
//通过sub-key得到supplier
Supplier<V> supplier = valuesMap.get(subKey);
//supplier实际上就是这个factory
Factory factory = null;
while (true) {
//如果缓存里有supplier ,那就直接通过get方法,得到代理类对象,返回,就结束了,一会儿分析get方法。
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
//下面的所有代码目的就是:如果缓存中没有supplier,则创建一个Factory对象,把factory对象在多线程的环境下安全的赋给supplier。
//因为是在while(true)中,赋值成功后又回到上面去调get方法,返回才结束。
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
所以接下来我们看Factory类中的get方法。
public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
//重新检查得到的supplier是不是当前对象
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
//代理类就是在这个位置调用valueFactory生成的
//valueFactory就是我们传入的 new ProxyClassFactory()
//一会我们分析ProxyClassFactory()的apply方法
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;
// wrap value with CacheValue (WeakReference)
//把value包装成弱引用
CacheValue<V> cacheValue = new CacheValue<>(value);
// put into reverseMap
// reverseMap是用来实现缓存的有效性
reverseMap.put(cacheValue, Boolean.TRUE);
// try replacing us with CacheValue (this should always succeed)
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
}
拨云见日,来到ProxyClassFactory的apply方法,代理类就是在这里生成的。
//这里的BiFunction<T, U, R>是个函数式接口,可以理解为用T,U两种类型做参数,得到R类型的返回值
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
//所有代理类名字的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
//用于生成代理类名字的计数器
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@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
//代理类访问控制符: public ,final
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.
*/
//验证所有非公共的接口在同一个包内;公共的就无需处理
//生成包名和类名的逻辑,包名默认是com.sun.proxy,类名默认是$Proxy 加上一个自增的整数值
//如果被代理类是 non-public proxy interface ,则用和被代理类接口一样的包名
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.
*/
long num = nextUniqueNumber.getAndIncrement();
//代理类的完全限定名,如com.sun.proxy.$Proxy0.calss
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
//核心部分,生成代理类的字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//把代理类加载到JVM中,至此动态代理过程基本结束了
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());
}
}
}
到这里其实已经分析完了,但是本着深究的态度,决定看看JDK生成的动态代理字节码是什么,于是我们将字节码保存到磁盘上的class文件中。代码如下:
public static void main(String[] args) {
IUserService target = new UserServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(target);
//第一个参数是指定代理类的类加载器(我们传入当前测试类的类加载器)
//第二个参数是代理类需要实现的接口(我们传入被代理类实现的接口,这样生成的代理类和被代理类就实现了相同的接口)
//第三个参数是invocation handler,用来处理方法的调用。这里传入我们自己实现的handler
IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
target.getClass().getInterfaces(), handler);
proxyObject.add("张玉龙");
String path = "D:/$Proxy0.class";
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", HelloworldImpl.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行这段代码,会在D盘生成一个名为$Proxy0.class的文件。通过反编译工具,得到JDK为我们生成的代理类是这样的:
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space
import com.zhb.jdk.proxy.IUserService;
import java.lang.reflect.*;
public final class $Proxy0 extends Proxy
implements IUserService
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
//代理类的构造函数,其参数正是是InvocationHandler实例,
//Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
// Object类中的三个方法,equals,toString, hashCode
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
//接口代理方法
public final void add(String s)
{
try
{
// invocation handler的 invoke方法在这里被调用
super.h.invoke(this, m3, new Object[] {
s
});
return;
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
// 在这里调用了invoke方法。
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch (Error ) { }
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
// 静态代码块对变量进行一些初始化工作
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.zhb.jdk.proxy.IUserService").getMethod("add", new Class[] {
Class.forName("java.lang.String")
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch (NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch (ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
生成了Object类的三个方法:toString,hashCode,equals。还有我们需要被代理的方法。
JDK代理类的cache clear机制
大家都知道、在项目中被代理的class越来越多,所以jdk会搞一个cache的方式来防止相同的代理接口重复生成class,影响性能不说,实现也不是很优雅,那么现在就会有一个问题了,当classloader已经在内存中没有依赖的时候,被代理的proxy class其实也没有什么意义了,这样就需要清空无用的cache,java Proxy采用了非常巧妙的“弱引用机制”,我们来看下面的代码
我们还是继续看get方法的源码
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
.......
}
其中源码中有一个方法expungeStaleEntries、我们进去这个方法一窥究竟
private void expungeStaleEntries() {
CacheKey<K> cacheKey;
while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) {
cacheKey.expungeFrom(map, reverseMap);
}
}
在看看expungeFrom方法源码干了些什么
void expungeFrom(ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> map,
ConcurrentMap<?, Boolean> reverseMap) {
// removing just by key is always safe here because after a CacheKey
// is cleared and enqueue-ed it is only equal to itself
// (see equals method)...
ConcurrentMap<?, ?> valuesMap = map.remove(this);
// remove also from reverseMap if needed
if (valuesMap != null) {
for (Object cacheValue : valuesMap.values()) {
reverseMap.remove(cacheValue);
}
}
}
代码很清晰了,清空被代理的对象。现在的关键就是refQueue对象是怎么来的。我们继续找一下跟refQueue相关的源码、在get中还有一段代码是这样的
Object cacheKey = CacheKey.valueOf(key, refQueue);
private static final class CacheKey<K> extends WeakReference<K> {
// a replacement for null keys
private static final Object NULL_KEY = new Object();
static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) {
return key == null
// null key means we can't weakly reference it,
// so we use a NULL_KEY singleton as cache key
? NULL_KEY
// non-null key requires wrapping with a WeakReference
: new CacheKey<>(key, refQueue);
}
private final int hash;
private CacheKey(K key, ReferenceQueue<K> refQueue) {
super(key, refQueue);
this.hash = System.identityHashCode(key); // compare by identity
}
.....
}
这样看就非常清晰了、原来是CacheKey继承了WeakReference弱引用机制,当弱引用依赖的key没有引用的时候,当前失效的对象就会进入ReferenceQueue中来实现清空cache的功能、这种实现思路和ThreadLocal的实现原理是一样的、大家有兴趣可以去阅读以下相关源码。
三:cglib代理源码分析
有了上面的源码分析经验,聪明的小伙伴一定知道cglib代理实际上也差不多,只不过是基于Class类生成的,可以对类进行代理,无需接口,但是内部的实验逻辑也比较复杂,先上一个简单的demo
package cglib;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibTest implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println ("我被代理了");
return proxy.invokeSuper ( obj,args );
}
public String hello(String name){
return "你好" + name;
}
public static void main(String[] args) {
System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" );
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass (CglibTest.class);
enhancer.setCallback(new CglibTest());
CglibTest cglibTest = (CglibTest) enhancer.create ();
String result = cglibTest.hello ( "张玉龙" );
System.out.println (result);
}
}
执行结果
CGLIB debugging enabled, writing to '/Users/zhangyulong/Downloads'
我被代理了
你好张玉龙
”耳熟能详“的生成结果,那么接下来我们看看它到底是怎么生成的,实现原理和Jdk代理有什么不同?
我们一层一层的翻源码来看看
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
classOnly代码是否只生成class,不生成代理对象,默认是false,说明要生成对象。argumentType是构造器参数类型,由于我们使用无参构造器,这些参数暂时可以忽略掉。
private Object createHelper() {
preValidate();
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
return result;
}
preValidate 首先验证一下参数类型以及基础校验,cglib支持CallbackFilter,由于我们callBack只有一个,enhancer.setCallback(new CglibTest()); 所以这里默认没有filter,看下cglib的处理
private void preValidate() {
if (callbackTypes == null) {
callbackTypes = CallbackInfo.determineTypes(callbacks, false);
validateCallbackTypes = true;
}
if (filter == null) {
if (callbackTypes.length > 1) {
throw new IllegalStateException("Multiple callback types possible but no filter specified");
}
filter = ALL_ZERO;
}
}
private static final CallbackFilter ALL_ZERO = new CallbackFilter(){
public int accept(Method method) {
return 0;
}
};
默认返回0,就是我们传入的new CglibTest()。重新返回主流程,我们看一下
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
首先根据代理类生成了一个key。这个key的主要作用就是对生成的代理类进行缓存,生成代码在KeyFactory.create方法。这里不是主线流程,感兴趣的小伙伴自己深入一下即可
public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer,
List<KeyFactoryCustomizer> next) {
Generator gen = new Generator();
gen.setInterface(keyInterface);
if (customizer != null) {
gen.addCustomizer(customizer);
}
if (next != null && !next.isEmpty()) {
for (KeyFactoryCustomizer keyFactoryCustomizer : next) {
gen.addCustomizer(keyFactoryCustomizer);
}
}
gen.setClassLoader(loader);
return gen.create();
}
我们主要看一下AbstractClassGenerator.create方法,这里也是我们生成代理代码的主流程
protected Object create(Object key) {
try {
ClassLoader loader = getClassLoader();
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = cache.get(loader);
if (data == null) {
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
if (data == null) {
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
聪明的小伙伴已经发现了,cglib代理以及jdk代理的缓存结构大同小异。
private static volatile Map<ClassLoader, ClassLoaderData> CACHE = new WeakHashMap<ClassLoader, ClassLoaderData>();
1级缓存, ClassLoader以及我们cglib的代理缓存对象ClassLoaderData,在ClassLoaderData里维护了一个弱引用的classloader对象,以及代理类的缓存对偶性 LoadingCache。这和JDK代理弱引用classloader几乎是完全一样的
public ClassLoaderData(ClassLoader classLoader) {
if (classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
}
this.classLoader = new WeakReference<ClassLoader>(classLoader);
Function<AbstractClassGenerator, Object> load =
new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this);
return gen.wrapCachedClass(klass);
}
};
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);
}
public ClassLoader getClassLoader() {
return classLoader.get();
}
上面我们讲了JDK代理的缓存清空的逻辑,那么我们看下cglib代理对象时,classloader失效后如何处理的,毕竟是弱引用classloader,那么一定要做缓存清空处理的。
ClassLoader classLoader = data.getClassLoader();
if (classLoader == null) {
throw new IllegalStateException("ClassLoader is null while trying to define class " +
getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
"Please file an issue at cglib's issue tracker.");
}
cglib的处理还是比较暴力的,直接抛出异常。接下来我们看下二级缓存以及生成字节码的处理
public Object get(AbstractClassGenerator gen, boolean useCache) {
if (!useCache) {
return gen.generate(ClassLoaderData.this);
} else {
Object cachedValue = generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
useCache来决定是否生成字节码后,每次都缓存。 我们手动设置就可以了。
/**
* Whether use and update the static cache of generated classes
* for a class with the same properties. Default is <code>true</code>.
*/
public void setUseCache(boolean useCache) {
this.useCache = useCache;
}
/**
* @see #setUseCache
*/
public boolean getUseCache() {
return useCache;
}
Object cachedValue = generatedClasses.get(gen); 缓存的逻辑分支,我们接着跟下去。
public V get(K key) {
final KK cacheKey = keyMapper.apply(key);
Object v = map.get(cacheKey);
if (v != null && !(v instanceof FutureTask)) {
return (V) v;
}
return createEntry(key, cacheKey, v);
}
逻辑非常清晰了,先看map中是否有cache对象。有直接拿出来,没有通过createEntry(key, cacheKey, v)来生成即可。keyMapper.apply(key)是什么呢,我们看看
private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() {
public Object apply(AbstractClassGenerator gen) {
return gen.key;
}
};
gen.key就是我们上面提到的KeyFactory生成的key。生成代理对象,并且缓存下来
protected V createEntry(final K key, KK cacheKey, Object v) {
FutureTask<V> task;
boolean creator = false;
if (v != null) {
// Another thread is already loading an instance
task = (FutureTask<V>) v;
} else {
task = new FutureTask<V>(new Callable<V>() {
public V call() throws Exception {
return loader.apply(key);
}
});
Object prevTask = map.putIfAbsent(cacheKey, task);
if (prevTask == null) {
// creator does the load
creator = true;
task.run();
} else if (prevTask instanceof FutureTask) {
task = (FutureTask<V>) prevTask;
} else {
return (V) prevTask;
}
}
V result;
try {
result = task.get();
} catch (InterruptedException e) {
throw new IllegalStateException("Interrupted while loading cache item", e);
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw ((RuntimeException) cause);
}
throw new IllegalStateException("Unable to load cache item", cause);
}
if (creator) {
map.put(cacheKey, result);
}
return result;
}
到目前为止,我们缓存相关的逻辑都已经讲解完毕了,我们把精力放到生成字节码部分,最终生成字节码的方法如下
protected Class generate(ClassLoaderData data) {
Class gen;
Object save = CURRENT.get();
CURRENT.set(this);
try {
ClassLoader classLoader = data.getClassLoader();
if (classLoader == null) {
throw new IllegalStateException("ClassLoader is null while trying to define class " +
getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
"Please file an issue at cglib's issue tracker.");
}
synchronized (classLoader) {
String name = generateClassName(data.getUniqueNamePredicate());
data.reserveName(name);
this.setClassName(name);
}
if (attemptLoad) {
try {
gen = classLoader.loadClass(getClassName());
return gen;
} catch (ClassNotFoundException e) {
// ignore
}
}
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
return gen;
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
} finally {
CURRENT.set(save);
}
}
先使用generateClassName生成代理类的名字,这里就是我们debug Spring Aop源码以及其他源码中 带$符号以及cglib很长的名称。
private String generateClassName(Predicate nameTestPredicate) {
return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate);
}
最关键的生成字节码的部分
byte[] b = strategy.generate(this);
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = getClassVisitor();
transform(cg).generateClass(cw);
return transform(cw.toByteArray());
}
protected DebuggingClassWriter getClassVisitor() throws Exception {
return new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES);
}
public byte[] toByteArray() {
return (byte[]) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray();
if (debugLocation != null) {
String dirs = className.replace('.', File.separatorChar);
try {
new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
File file = new File(new File(debugLocation), dirs + ".class");
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
try {
out.write(b);
} finally {
out.close();
}
if (traceCtor != null) {
file = new File(new File(debugLocation), dirs + ".asm");
out = new BufferedOutputStream(new FileOutputStream(file));
try {
ClassReader cr = new ClassReader(b);
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
ClassVisitor tcv = (ClassVisitor)traceCtor.newInstance(new Object[]{null, pw});
cr.accept(tcv, 0);
pw.flush();
} finally {
out.close();
}
}
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
return b;
}
});
}
}
我们看到这里可以将生成的代码放到指定的位置来方便查看。这也就是我们demo中设置代码生成位置的原因,我们要看看它到底生成了什么。
System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" );
生成字节码的方法在Enhancer中
public void generateClass(ClassVisitor v)
底层是通过asm工具来生成的字节码,然后通过构造器反射来生成的代码逻辑。由于代码生成部分比较复杂,我们忽略这一部分,只关注一下和CallBackFilter相关的内容。
private void emitMethods(final ClassEmitter ce, List methods, List actualMethods) {
...........
MethodInfo method = (MethodInfo)it1.next();
Method actualMethod = (it2 != null) ? (Method)it2.next() : null;
int index = filter.accept(actualMethod);
if (index >= callbackTypes.length) {
throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index);
}
originalModifiers.put(method, new Integer((actualMethod != null) ? actualMethod.getModifiers() : method.getModifiers()));
indexes.put(method, new Integer(index));
List group = (List)groups.get(generators[index]);
if (group == null) {
groups.put(generators[index], group = new ArrayList(methods.size()));
}
group.add(method);
................
}
这里我们可以看到生成代理类字节码时,根据我们传入的CallbackFilter来决定使用哪个Callback。
看一下到底生成了哪些文件。
CglibTest$$EnhancerByCGLIB$$fc037646.class
CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181.class
CglibTest$$FastClassByCGLIB$$ef5535a6.class
在目录中我们发现生成了三个文件。首先第一个是根据CglibTest原生类来生成的代理类,第二个是原生类的FastClass,第三个是代理类的FastClass
代理类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package cglib;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibTest$$EnhancerByCGLIB$$fc037646 extends CglibTest implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$hello$0$Method;
private static final MethodProxy CGLIB$hello$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$intercept$1$Method;
private static final MethodProxy CGLIB$intercept$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("cglib.CglibTest$$EnhancerByCGLIB$$fc037646");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$2$Method = var10000[0];
CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
CGLIB$toString$3$Method = var10000[1];
CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
CGLIB$hashCode$4$Method = var10000[2];
CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = var10000[3];
CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
var10000 = ReflectUtils.findMethods(new String[]{"hello", "(Ljava/lang/String;)Ljava/lang/String;", "intercept", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;"}, (var1 = Class.forName("cglib.CglibTest")).getDeclaredMethods());
CGLIB$hello$0$Method = var10000[0];
CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
CGLIB$intercept$1$Method = var10000[1];
CGLIB$intercept$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;", "intercept", "CGLIB$intercept$1");
}
final String CGLIB$hello$0(String var1) {
return super.hello(var1);
}
public final String hello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy) : super.hello(var1);
}
final Object CGLIB$intercept$1(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable {
return super.intercept(var1, var2, var3, var4);
}
public final Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$intercept$1$Method, new Object[]{var1, var2, var3, var4}, CGLIB$intercept$1$Proxy) : super.intercept(var1, var2, var3, var4);
}
final boolean CGLIB$equals$2(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$3() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
}
final int CGLIB$hashCode$4() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$5() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1249666147:
if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
return CGLIB$intercept$1$Proxy;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$5$Proxy;
}
break;
case 848333779:
if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
return CGLIB$hello$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$2$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$3$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$4$Proxy;
}
}
return null;
}
public CglibTest$$EnhancerByCGLIB$$fc037646() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
CglibTest$$EnhancerByCGLIB$$fc037646 var1 = (CglibTest$$EnhancerByCGLIB$$fc037646)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
CglibTest$$EnhancerByCGLIB$$fc037646 var10000 = new CglibTest$$EnhancerByCGLIB$$fc037646;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
代理类的FastClass
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package cglib;
import cglib.CglibTest..EnhancerByCGLIB..fc037646;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.reflect.FastClass;
public class CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181 extends FastClass {
public CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2055565910:
if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 3;
}
break;
case -1457535688:
if (var10000.equals("CGLIB$STATICHOOK1()V")) {
return 16;
}
break;
case -1411812934:
if (var10000.equals("CGLIB$hashCode$4()I")) {
return 21;
}
break;
case -1249666147:
if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
return 14;
}
break;
case -894172689:
if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 11;
}
break;
case -879968516:
if (var10000.equals("CGLIB$hello$0(Ljava/lang/String;)Ljava/lang/String;")) {
return 17;
}
break;
case -623122092:
if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
return 0;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return 9;
}
break;
case -419626537:
if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
return 1;
}
break;
case 374345669:
if (var10000.equals("CGLIB$equals$2(Ljava/lang/Object;)Z")) {
return 19;
}
break;
case 560567118:
if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
return 15;
}
break;
case 811063227:
if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 12;
}
break;
case 848333779:
if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
return 13;
}
break;
case 973717575:
if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
return 5;
}
break;
case 1115619315:
if (var10000.equals("CGLIB$intercept$1(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
return 18;
}
break;
case 1221173700:
if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 10;
}
break;
case 1230699260:
if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
return 4;
}
break;
case 1341835395:
if (var10000.equals("main([Ljava/lang/String;)V")) {
return 23;
}
break;
case 1517819849:
if (var10000.equals("CGLIB$toString$3()Ljava/lang/String;")) {
return 20;
}
break;
case 1584330438:
if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 2;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 6;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 7;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 8;
}
break;
case 2011844968:
if (var10000.equals("CGLIB$clone$5()Ljava/lang/Object;")) {
return 22;
}
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -1776922004:
if (var1.equals("toString")) {
switch(var2.length) {
case 0:
return 7;
}
}
break;
case -1295482945:
if (var1.equals("equals")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 6;
}
}
}
break;
case -1053468136:
if (var1.equals("getCallbacks")) {
switch(var2.length) {
case 0:
return 5;
}
}
break;
case -981624788:
if (var1.equals("CGLIB$intercept$1")) {
switch(var2.length) {
case 4:
if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) {
return 18;
}
}
}
break;
case -124978608:
if (var1.equals("CGLIB$equals$2")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 19;
}
}
}
break;
case -60403779:
if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 2;
}
}
}
break;
case -29025554:
if (var1.equals("CGLIB$hashCode$4")) {
switch(var2.length) {
case 0:
return 21;
}
}
break;
case 3343801:
if (var1.equals("main")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Ljava.lang.String;")) {
return 23;
}
}
}
break;
case 85179481:
if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 3;
}
}
}
break;
case 94756189:
if (var1.equals("clone")) {
switch(var2.length) {
case 0:
return 9;
}
}
break;
case 99162322:
if (var1.equals("hello")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 13;
}
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 8;
}
}
break;
case 161998109:
if (var1.equals("CGLIB$STATICHOOK1")) {
switch(var2.length) {
case 0:
return 16;
}
}
break;
case 495524492:
if (var1.equals("setCallbacks")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 1;
}
}
}
break;
case 502538434:
if (var1.equals("intercept")) {
switch(var2.length) {
case 4:
if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) {
return 14;
}
}
}
break;
case 1154623345:
if (var1.equals("CGLIB$findMethodProxy")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
return 0;
}
}
}
break;
case 1543336190:
if (var1.equals("CGLIB$toString$3")) {
switch(var2.length) {
case 0:
return 20;
}
}
break;
case 1811874389:
if (var1.equals("newInstance")) {
switch(var2.length) {
case 1:
String var10001 = var2[0].getName();
switch(var10001.hashCode()) {
case -845341380:
if (var10001.equals("net.sf.cglib.proxy.Callback")) {
return 11;
}
break;
case 1730110032:
if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 10;
}
}
case 2:
default:
break;
case 3:
if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 12;
}
}
}
break;
case 1817099975:
if (var1.equals("setCallback")) {
switch(var2.length) {
case 2:
if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
return 15;
}
}
}
break;
case 1891304123:
if (var1.equals("CGLIB$hello$0")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 17;
}
}
}
break;
case 1905679803:
if (var1.equals("getCallback")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("int")) {
return 4;
}
}
}
break;
case 1951977611:
if (var1.equals("CGLIB$clone$5")) {
switch(var2.length) {
case 0:
return 22;
}
}
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
fc037646 var10000 = (fc037646)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return fc037646.CGLIB$findMethodProxy((Signature)var3[0]);
case 1:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 2:
fc037646.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 3:
fc037646.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 4:
return var10000.getCallback(((Number)var3[0]).intValue());
case 5:
return var10000.getCallbacks();
case 6:
return new Boolean(var10000.equals(var3[0]));
case 7:
return var10000.toString();
case 8:
return new Integer(var10000.hashCode());
case 9:
return var10000.clone();
case 10:
return var10000.newInstance((Callback[])var3[0]);
case 11:
return var10000.newInstance((Callback)var3[0]);
case 12:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 13:
return var10000.hello((String)var3[0]);
case 14:
return var10000.intercept(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]);
case 15:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 16:
fc037646.CGLIB$STATICHOOK1();
return null;
case 17:
return var10000.CGLIB$hello$0((String)var3[0]);
case 18:
return var10000.CGLIB$intercept$1(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]);
case 19:
return new Boolean(var10000.CGLIB$equals$2(var3[0]));
case 20:
return var10000.CGLIB$toString$3();
case 21:
return new Integer(var10000.CGLIB$hashCode$4());
case 22:
return var10000.CGLIB$clone$5();
case 23:
CglibTest.main((String[])var3[0]);
return null;
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
fc037646 var10000 = new fc037646;
fc037646 var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 23;
}
}
原生类的FastClass
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package cglib;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.reflect.FastClass;
public class CglibTest$$FastClassByCGLIB$$ef5535a6 extends FastClass {
public CglibTest$$FastClassByCGLIB$$ef5535a6(Class var1) {
super(var1);
}
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -1249666147:
if (var10000.equals("intercept(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;")) {
return 2;
}
break;
case 848333779:
if (var10000.equals("hello(Ljava/lang/String;)Ljava/lang/String;")) {
return 1;
}
break;
case 1341835395:
if (var10000.equals("main([Ljava/lang/String;)V")) {
return 0;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 3;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 4;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 5;
}
}
return -1;
}
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -1776922004:
if (var1.equals("toString")) {
switch(var2.length) {
case 0:
return 4;
}
}
break;
case -1295482945:
if (var1.equals("equals")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 3;
}
}
}
break;
case 3343801:
if (var1.equals("main")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Ljava.lang.String;")) {
return 0;
}
}
}
break;
case 99162322:
if (var1.equals("hello")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 1;
}
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 5;
}
}
break;
case 502538434:
if (var1.equals("intercept")) {
switch(var2.length) {
case 4:
if (var2[0].getName().equals("java.lang.Object") && var2[1].getName().equals("java.lang.reflect.Method") && var2[2].getName().equals("[Ljava.lang.Object;") && var2[3].getName().equals("net.sf.cglib.proxy.MethodProxy")) {
return 2;
}
}
}
}
return -1;
}
public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
CglibTest var10000 = (CglibTest)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
CglibTest.main((String[])var3[0]);
return null;
case 1:
return var10000.hello((String)var3[0]);
case 2:
return var10000.intercept(var3[0], (Method)var3[1], (Object[])var3[2], (MethodProxy)var3[3]);
case 3:
return new Boolean(var10000.equals(var3[0]));
case 4:
return var10000.toString();
case 5:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
CglibTest var10000 = new CglibTest;
CglibTest var10001 = var10000;
int var10002 = var1;
try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
public int getMaxIndex() {
return 5;
}
}
我们看下代理类的hello方法
public final String hello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy) : super.hello(var1);
}
最终调用了 var10000.intercept(this, CGLIB$hello$0$Method, new Object[]{var1}, CGLIB$hello$0$Proxy)方法,也就是我们的
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println ("我被代理了");
return proxy.invokeSuper ( obj,args );
}
proxy.invokeSuper ( obj,args ) 是怎么实现的呢,接下来我们重点看看 CGLIB$hello$0$Proxy的生成逻辑。
CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
这里根据代理类以及原生类的hello方法生成了方法签名 Signature。
5个参数分别是 Class c1 目标类Class,Class c2 代理类Class,String desc 代理方法的描述,String name1 被代理方法名,String name2 代理方法名
接下来
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
private void init()
{
/*
* Using a volatile invariant allows us to initialize the FastClass and
* method index pairs atomically.
*
* Double-checked locking is safe with volatile in Java 5. Before 1.5 this
* code could allow fastClassInfo to be instantiated more than once, which
* appears to be benign.
*/
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
}
}
}
}
private static class FastClassInfo
{
FastClass f1;
FastClass f2;
int i1;
int i2;
}
private static class CreateInfo
{
Class c1;
Class c2;
NamingPolicy namingPolicy;
GeneratorStrategy strategy;
boolean attemptLoad;
public CreateInfo(Class c1, Class c2)
{
this.c1 = c1;
this.c2 = c2;
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
if (fromEnhancer != null) {
namingPolicy = fromEnhancer.getNamingPolicy();
strategy = fromEnhancer.getStrategy();
attemptLoad = fromEnhancer.getAttemptLoad();
}
}
}
private static FastClass helper(CreateInfo ci, Class type) {
FastClass.Generator g = new FastClass.Generator();
g.setType(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
其实这里最主要的就是生成代理类和普通类的FastClass,以及hello方法的index,然后去调用,我们看一下简单的例子来看看FastClass底层倒底是什么
public class FastClass1 {
public void hello(String name) {
System.out.println("hello, " + name);
}
public void hi(String msg) {
System.out.println("hi, " + msg);
}
}
public class FastClass2 {
public Object invoke(Object obj, int methodIndex, Object[] parameters) {
FastClass1 target = (FastClass1)obj;
Object result = null;
switch (methodIndex) {
case 1:
target.hello((String)parameters[0]);
break;
case 2:
target.hi((String)parameters[0]);
break;
}
return result;
}
public int getIndex(String methodDescriptor) {
switch (methodDescriptor.hashCode()) {
case -2084786067:
return 1;
case -70025314:
return 2;
}
return -1;
}
}
public class FastClassTest {
public static void main(String[] args) {
FastClass1 fastClass1 = new FastClass1();
FastClass2 fastClass2 = new FastClass2();
int helloIndex = fastClass2.getIndex("hello(Ljava/lang/String;)V");//方法名(参数类型;...)返回类型
fastClass2.invoke(fastClass1, helloIndex, new Object[]{"张三"});
int hiIndex = fastClass2.getIndex("hi(Ljava/lang/String;)V");
fastClass2.invoke(fastClass1, hiIndex, new Object[]{"cglib动态代理"});
}
}
上例中,FastClass2是FastClass1的Fastclass,在FastClass2中有两个方法getIndex和invoke。在getIndex方法中对FastClass1的每个方法建立索引,并根据入参(方法名+方法的描述符)来返回相应的索引。invoke根据指定的索引,以parameters为入参调用对象obj的方法。这样就避免了反射调用,提高了效率。我们生成的CglibTest$$EnhancerByCGLIB$$fc037646$$FastClassByCGLIB$$ec49b181.class以及CglibTest$$FastClassByCGLIB$$ef5535a6.class 原理也是类似。
MethodProxy中invokeSuper 和MethodProxy中invoke的区别是什么 我们来看看
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
fci.f1.invoke(fci.i1, obj, args);执行原生类Fastclass的hello方法
fci.f2.invoke(fci.i2, obj, args);执行代理类FastClass的hello方法
经常有小伙伴不小心用错的逻辑,导致死循环。
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println ("我被代理了");
return proxy.invoke ( obj,args );
}
.........
我被代理了
我被代理了
我被代理了
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)
at sun.nio.cs.UTF_8.access$200(UTF_8.java:57)
at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:636)
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at cglib.CglibTest.intercept(CglibTest.java:13)
at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at cglib.CglibTest.intercept(CglibTest.java:14)
at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at cglib.CglibTest.intercept(CglibTest.java:14)
at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at cglib.CglibTest.intercept(CglibTest.java:14)
at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at cglib.CglibTest.intercept(CglibTest.java:14)
at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at cglib.CglibTest.intercept(CglibTest.java:14)
at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at cglib.CglibTest.intercept(CglibTest.java:14)
at cglib.CglibTest$$EnhancerByCGLIB$$fc037646.hello(<generated>)
at cglib.CglibTest$$FastClassByCGLIB$$ef5535a6.invoke(<generated>)
.........
为什么会这样,因为invokeSuper执行的是代理类的FastClass的方法,invoke是执行的原生类的FastClass的方法,
CGLIB$hello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "hello", "CGLIB$hello$0");
最终执行的方法不一样,分别是hello以及CGLIB$hello$0
final String CGLIB$hello$1(String var1) {
return super.hello(var1);
}
public final String hello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello$1$Method, new Object[]{var1}, CGLIB$hello$1$Proxy) : super.hello(var1);
}
执行CGLIB$hello$1方法最终调用原生方法,执行hello方法会一直执行MethodInterceptor的intercept方法导致死循环,最后还有一点拦截器在cglib中可以实现很多类型,这个也是在字节码生成代码中来实现的,Spring等框架常用的就MethodInterceptor
class CallbackInfo
{
private static final CallbackInfo[] CALLBACKS = {
new CallbackInfo(NoOp.class, NoOpGenerator.INSTANCE),
new CallbackInfo(MethodInterceptor.class, MethodInterceptorGenerator.INSTANCE),
new CallbackInfo(InvocationHandler.class, InvocationHandlerGenerator.INSTANCE),
new CallbackInfo(LazyLoader.class, LazyLoaderGenerator.INSTANCE),
new CallbackInfo(Dispatcher.class, DispatcherGenerator.INSTANCE),
new CallbackInfo(FixedValue.class, FixedValueGenerator.INSTANCE),
new CallbackInfo(ProxyRefDispatcher.class, DispatcherGenerator.PROXY_REF_INSTANCE),
};
}
我们常用的callBack就是MethodInterceptor,但是其他的可能不太常用,他们的区别是什么呢,来看下面的代码
package cglib.callback;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
public class CglibTestCallBack {
public String hello0(String name){
return "你好0" + name;
}
public String hello1(String name){
return "你好1" + name;
}
public String hello2(String name){
return "你好2" + name;
}
public String hello3(String name){
return "你好3" + name;
}
public String hello4(String name){
return "你好4" + name;
}
public String hello5(String name){
return "你好5" + name;
}
public String hello6(String name){
return "你好6" + name;
}
public static void main(String[] args) {
System.setProperty ( DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/zhangyulong/Downloads" );
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass ( CglibTestCallBack.class);
enhancer.setCallbacks(
new Callback[]{
new DispatcherCallBack(),
new FixedValueCallBack(),
new InvocationHandlerCallback(),
new LazyLoaderCallBack(),
new MethodInterceptorCallBack(),
new NoOpCallBack(),
new ProxyRefDispatcherCallBack()
}
);
enhancer.setCallbackFilter ( new CallbackFilter () {
@Override
public int accept(Method method) {
String name = method.getName ();
if(!name.startsWith ( "hello" )) return 0;
String num = name.substring ( "hello".length () );
return Integer.parseInt ( num );
}
} );
CglibTestCallBack cglibTest = (CglibTestCallBack) enhancer.create ();
String result = cglibTest.hello1 ( "张玉龙" );
System.out.println (result);
}
}
public class DispatcherCallBack implements Dispatcher {
@Override
public Object loadObject() throws Exception {
return null;
}
}
public class FixedValueCallBack implements FixedValue {
@Override
public Object loadObject() throws Exception {
return null;
}
}
public class InvocationHandlerCallback implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
public class LazyLoaderCallBack implements LazyLoader {
@Override
public Object loadObject() throws Exception {
return null;
}
}
public class NoOpCallBack implements NoOp {
}
public class ProxyRefDispatcherCallBack implements ProxyRefDispatcher {
@Override
public Object loadObject(Object proxy) throws Exception {
return null;
}
}
我们设置了六个callBack,对应了六个方法 hello0-6, 我们来看看他们生成的代理类的方法是什么样的,下面是代理类的部分代码
public final String hello0(String var1) {
Dispatcher var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return ((CglibTestCallBack)var10000.loadObject()).hello0(var1);
}
public final String hello1(String var1) {
FixedValue var10000 = this.CGLIB$CALLBACK_1;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_1;
}
return (String)var10000.loadObject();
}
public final String hello2(String var1) {
try {
InvocationHandler var10000 = this.CGLIB$CALLBACK_2;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_2;
}
return (String)var10000.invoke(this, CGLIB$hello2$1, new Object[]{var1});
} catch (Error | RuntimeException var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String hello3(String var1) {
return ((CglibTestCallBack)this.CGLIB$LOAD_PRIVATE_3()).hello3(var1);
}
private final synchronized Object CGLIB$LOAD_PRIVATE_3() {
Object var10000 = this.CGLIB$LAZY_LOADER_3;
if (var10000 == null) {
LazyLoader var10001 = this.CGLIB$CALLBACK_3;
if (var10001 == null) {
CGLIB$BIND_CALLBACKS(this);
var10001 = this.CGLIB$CALLBACK_3;
}
var10000 = this.CGLIB$LAZY_LOADER_3 = var10001.loadObject();
}
return var10000;
}
public final String hello4(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_4;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_4;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$hello4$3$Method, new Object[]{var1}, CGLIB$hello4$3$Proxy) : super.hello4(var1);
}
public final String hello6(String var1) {
ProxyRefDispatcher var10000 = this.CGLIB$CALLBACK_6;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_6;
}
return ((CglibTestCallBack)var10000.loadObject(this)).hello6(var1);
}
无需多解释,生成的代码非常清晰了,由于hello5是实现了NoOp,代理类忽略这个方法,直接调用原生类的hello5。值得注意的是CGLIB$BIND_CALLBACKS(this);这个方法是这些代理方法中统一的设置callback的方法,我们看看它到底干了些什么。
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
CglibTestCallBack$$EnhancerByCGLIB$$58712cb6 var1 = (CglibTestCallBack$$EnhancerByCGLIB$$58712cb6)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
Callback[] var10001 = (Callback[])var10000;
var1.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)((Callback[])var10000)[6];
var1.CGLIB$CALLBACK_5 = (NoOp)var10001[5];
var1.CGLIB$CALLBACK_4 = (MethodInterceptor)var10001[4];
var1.CGLIB$CALLBACK_3 = (LazyLoader)var10001[3];
var1.CGLIB$CALLBACK_2 = (InvocationHandler)var10001[2];
var1.CGLIB$CALLBACK_1 = (FixedValue)var10001[1];
var1.CGLIB$CALLBACK_0 = (Dispatcher)var10001[0];
}
}
代码非常简单,就是从CGLIB$THREAD_CALLBACKS 或者CGLIB$STATIC_CALLBACKS中获取callBack数组,那么这个数组我们什么时候设置的呢?看下面代码 net.sf.cglib.proxy.Enhancer#firstInstance
protected Object firstInstance(Class type) throws Exception {
if (classOnly) {
return type;
} else {
return createUsingReflection(type);
}
}
private Object createUsingReflection(Class type) {
setThreadCallbacks(type, callbacks);
try{
if (argumentTypes != null) {
return ReflectUtils.newInstance(type, argumentTypes, arguments);
} else {
return ReflectUtils.newInstance(type);
}
}finally{
// clear thread callbacks to allow them to be gc'd
setThreadCallbacks(type, null);
}
}
private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS";
private static void setThreadCallbacks(Class type, Callback[] callbacks) {
setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME);
}
特别明显在初始化时,将我们设置的callBack数组设置到代理类中,并且在代理类生成实例之后,再清空,方便gc回收,到此cglib的源码解析就已经完成了。这里有一个细节就是上面的代码 只有hello4方法才会生成FastClass,所以我们生成的代理类只有1个,没有生成原生类和代理的FsstClass,这是因为fastclass的生成只有首次调用方法的时候,才会去触发。
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
所以当我们调用hello4方法时,首次调用就会生成代理类了。这也就是为什么cglib代理首次调用的时候速度会慢一些,因为要先生成字节码。
四:手把手写基于接口的java代理
上面我们分析了jdk动态代理源码、cglib代理源码、那我们是不是可以自己用自己的方式去写一个属于自己的jdk代理呢,答案是可以的
首先我们写一个基类,当然我并没有在基类里面写什么东西,只是模拟java中的proxy类而已,当然我们也可以丰富的去拓展一下这个类的方法,来实现更多的功能,读者可以通过读完这篇文章之后自己去考虑一下如何来拓展。
1 package meituan.zylproxy.handlder;
2 public class ZylProxy {
3 public ZylProxy(){
4 }
5 }
代理的核心接口,我们去做代理的时候一定是通过反射去调用的,不管jdk也好还是cglib也好,永远也无法脱离反射,我们照猫画虎,自己写一个代理接口核心类,这并不是什么难题,看起来和jdk的核心类接口也没有什么区别。
1 package meituan.zylproxy.handlder;
2
3 import java.lang.reflect.Method;
4
5 public interface ZYLInvocationHandler {
6
7 public Object invoke(Object proxy, Method method, Object[] args)
8 throws Exception;
9 }
说明一下 第一个参数proxy是代表代理类,而不是用户自己写的原生类实现。参数Method是接口的方法,args是运行时参数列表,在运行时传递过来的实际上就是实现类的参数,好了,下面让我们去深入核心。
我们自定义两个接口和接口的实现Idto,Idto2,和Dtoimpl如下:
1 package meituan.zylproxy.test.i;
2
3 public interface Idto {
4
5 public void add();
6
7 public String get();
8
9 }
package meituan.zylproxy.test.i;
public interface Idto2 {
public void adda();
public String geta();
}
package meituan.zylproxy.test.i.impl;
import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.Idto2;
public class DtoImpl implements Idto,Idto2{
@Override
public void add() {
System.out.println("add");
}
@Override
public String get() {
System.out.println("get");
return "return get";
}
@Override
public void adda() {
System.out.println("adda");
}
@Override
public String geta() {
System.out.println("geta");
return "return geta";
}
}
这是几个再简单不过的接口和实现类了,也没有什么可说的。接下来我们想对接口进行代理,无非是我们动态将接口进行实现,从而达到对使用者进行自定义handle接口暴露而已,下面看一下我们需要生成一个什么样的代理类。
import java.lang.reflect.Method;
import meituan.zylproxy.handlder.ZylProxy;
import meituan.zylproxy.handlder.ZYLInvocationHandler;
import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.Idto2;
public class IdtoPorxy extends ZylProxy implements Idto, Idto2 {
public ZYLInvocationHandler zYLInvocationHandler;
public static Method add1;
public static Method get2;
public static Method adda3;
public static Method geta4;
static {
try {
add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] );
get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] );
adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] );
geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] );
} catch (Exception e) {
}
}
public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) {
this.zYLInvocationHandler = zYLInvocationHandler;
}
public void add() {
Object[] o = {};
try {
this.zYLInvocationHandler.invoke ( this, add1, o );
return;
} catch (Throwable e) {
e.printStackTrace ();
}
}
public java.lang.String get() {
Object[] o = {};
try {
return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o );
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}
public void adda() {
Object[] o = {};
try {
this.zYLInvocationHandler.invoke ( this, adda3, o );
return;
} catch (Throwable e) {
e.printStackTrace ();
}
}
public java.lang.String geta() {
Object[] o = {};
try {
return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o );
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}
}
这个类不是由用户写的,而是我们动态生成的,对于jdk来说是生成了字节码,对cglib来说是通过字节码增强,其实实现的方式有多种,后面为了更方便大家理解我用字符串的形式来动态生成这么一个"家伙",先看看这个类干了些什么吧,也很简单。
public class IdtoPorxy extends ZylProxy implements Idto, Idto2
首先是继承了刚才我们所说的ZylProxy,留着今后拓展,可以参照java的Proxy,然后并且动态的实现了这两个接口。很简单
public ZYLInvocationHandler zYLInvocationHandler;
public IdtoPorxy(ZYLInvocationHandler zYLInvocationHandler) {
this.zYLInvocationHandler = zYLInvocationHandler;
}
这个是通过构造函数传进来一个handler对象,对实现类的操作都靠它了。
public static Method add1;
public static Method get2;
public static Method adda3;
public static Method geta4;
static {
try {
add1 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "add", new Class[0] );
get2 = Class.forName ( "meituan.zylproxy.test.i.Idto" ).getMethod ( "get", new Class[0] );
adda3 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "adda", new Class[0] );
geta4 = Class.forName ( "meituan.zylproxy.test.i.Idto2" ).getMethod ( "geta", new Class[0] );
} catch (Exception e) {
}
}
枚举出来所有的接口的方法,通过class.forname来获取到Method元数据。备用
public void add() {
Object[] o = {};
try {
this.zYLInvocationHandler.invoke ( this, add1, o );
return;
} catch (Throwable e) {
e.printStackTrace ();
}
}
public java.lang.String get() {
Object[] o = {};
try {
return (java.lang.String) this.zYLInvocationHandler.invoke ( this, get2, o );
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}
public void adda() {
Object[] o = {};
try {
this.zYLInvocationHandler.invoke ( this, adda3, o );
return;
} catch (Throwable e) {
e.printStackTrace ();
}
}
public java.lang.String geta() {
Object[] o = {};
try {
return (java.lang.String) this.zYLInvocationHandler.invoke ( this, geta4, o );
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}
上面是要枚举出来所有的方法的实现,很简单都一个模样,把实现交给handler去做就可以了。至于怎么实现靠handler,我们动态生成的这个类只负责委托,不做任何事情。看到这里大家一定急不可待的想知道这个类怎么生成的了,我把我写的源码给大家贴出来看一下。
package meituan.zylproxy.util;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.Idto2;
public class ClassUtil {
public static String mackProxyClass(Class<?> c) throws Exception{
if(!c.isInterface()){
throw new Exception("代理的类必须是接口");
}
StringBuffer importsp = new StringBuffer();
importsp.append("import java.lang.reflect.Method;\n");
importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n");
importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n");
importsp.append("import " +c.getName() + ";\n");
StringBuilder publicStaticMethods = new StringBuilder();
//public static Method add;
StringBuilder publicMethods = new StringBuilder();
publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n");
StringBuilder constructorsp = new StringBuilder();
String interFaceName = c.getName().substring(c.getName().lastIndexOf(".")+1);
constructorsp.append("public ").append("" + interFaceName + "Porxy").
append("(ZYLInvocationHandler zYLInvocationHandler) { "
+ "this.zYLInvocationHandler = zYLInvocationHandler;"
+ "}");
publicStaticMethods.append(" static { try { ");
StringBuilder classsp = new StringBuilder();
classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements ").append(interFaceName).append("{");
StringBuilder allMethods = new StringBuilder();
Method[] Methods = c.getMethods();
int curr=0;
for (Method m_:Methods) {
curr++;
publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n");
publicStaticMethods.append("").append(m_.getName() + String.valueOf(curr)).append("=");
publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", ");
StringBuilder sp =new StringBuilder();
StringBuilder spArgs = new StringBuilder();
spArgs.append("Object[] o ={");
//public
sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" ");
//void | java.lang.String
sp.append(m_.getReturnType().getName()).append(" ");
//add()|get()
sp.append(m_.getName().concat("("));
StringBuilder methodCLass = new StringBuilder();
if(m_.getParameterTypes().length>0){
Class<?>[] claszz = m_.getParameterTypes();
int methodOffset = 0;
methodCLass.append("new Class[] { ");
for (Class<?> c_ : claszz) {
String paramStr = "obj" + String.valueOf(++methodOffset);
spArgs.append(paramStr.concat(","));
sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(",");
methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),");
}
sp = new StringBuilder(sp.substring(0, sp.length()-1));
spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1));
methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1));
}
if(methodCLass.length()>0){
methodCLass.append("}");
} else{
methodCLass.append("new Class[0]");
}
sp.append("){\n");
spArgs.append("}");
sp.append(spArgs+";\n");
if(sp.toString().contains("void")){
sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n");
sp.append("} catch (Throwable e) {e.printStackTrace();}}");
} else{
sp.append("try {return "
+ "("
+ m_.getReturnType().getName()
+ ")"
+ "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n");
sp.append("} catch (Exception e) {e.printStackTrace();} return null;");
}
publicStaticMethods.append(methodCLass).append(");\n");
allMethods.append(sp);
}
publicStaticMethods.append("} catch(Exception e){}}");
classsp.append(publicMethods)
.append(publicStaticMethods)
.append(constructorsp).append(allMethods).append("}");
classsp.append("}");
importsp.append(classsp);
return importsp.toString();
}
public static String mackMultiProxyClass(Class<?>[] cs) throws Exception{
StringBuffer importsp = new StringBuffer();
importsp.append("import java.lang.reflect.Method;\n");
importsp.append("import meituan.zylproxy.handlder.ZylProxy;\n");
importsp.append("import meituan.zylproxy.handlder.ZYLInvocationHandler;\n");
StringBuilder publicStaticMethods = new StringBuilder();
publicStaticMethods.append(" static { try { ");
//public static Method add;
StringBuilder publicMethods = new StringBuilder();
publicMethods.append("public ZYLInvocationHandler zYLInvocationHandler;\n");
int curr=0;
StringBuilder constructorsp = new StringBuilder();
String interFaceName = cs[0].getName().substring(cs[0].getName().lastIndexOf(".")+1);
constructorsp.append("public ").append("" + interFaceName + "Porxy").
append("(ZYLInvocationHandler zYLInvocationHandler) { "
+ "this.zYLInvocationHandler = zYLInvocationHandler;"
+ "}");
StringBuilder allMethods = new StringBuilder();
StringBuilder classsp = new StringBuilder();
classsp.append("public class").append(" " + interFaceName + "Porxy").append(" extends ZylProxy implements ");
for (Class<?> c:cs) {
if(!c.isInterface()){
throw new Exception("代理的类必须是接口");
}
classsp.append(c.getName().substring(c.getName().lastIndexOf(".")+1)).append(",");
importsp.append("import " +c.getName() + ";\n");
Method[] Methods = c.getMethods();
for (Method m_:Methods) {
curr++;
publicMethods.append("public static Method ").append(m_.getName() + String.valueOf(curr)).append(";\n");
publicStaticMethods.append("").append(m_.getName() + String.valueOf(curr)).append("=");
publicStaticMethods.append("Class.forName(\"" + c.getName() + "\")" + ".getMethod(\""+ m_.getName() +"\", ");
StringBuilder sp =new StringBuilder();
StringBuilder spArgs = new StringBuilder();
spArgs.append("Object[] o ={");
//public
sp.append(Modifier.toString(m_.getModifiers()).replace("abstract", "")).append(" ");
//void | java.lang.String
sp.append(m_.getReturnType().getName()).append(" ");
//add()|get()
sp.append(m_.getName().concat("("));
StringBuilder methodCLass = new StringBuilder();
if(m_.getParameterTypes().length>0){
Class<?>[] claszz = m_.getParameterTypes();
int methodOffset = 0;
methodCLass.append("new Class[] { ");
for (Class<?> c_ : claszz) {
String paramStr = "obj" + String.valueOf(++methodOffset);
spArgs.append(paramStr.concat(","));
sp.append(c_.getName().toString().concat(" ").concat(paramStr)).append(",");
methodCLass.append("Class.forName(\"" + c_.getName()).append("\"),");
}
sp = new StringBuilder(sp.substring(0, sp.length()-1));
spArgs = new StringBuilder(spArgs.substring(0, spArgs.length()-1));
methodCLass = new StringBuilder(methodCLass.substring(0, methodCLass.length()-1));
}
if(methodCLass.length()>0){
methodCLass.append("}");
} else{
methodCLass.append("new Class[0]");
}
sp.append("){\n");
spArgs.append("}");
sp.append(spArgs+";\n");
if(sp.toString().contains("void")){
sp.append("try {\n this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n return;\n");
sp.append("} catch (Throwable e) {e.printStackTrace();}}");
} else{
sp.append("try {return "
+ "("
+ m_.getReturnType().getName()
+ ")"
+ "this.zYLInvocationHandler.invoke(this,").append(m_.getName() + String.valueOf(curr)).append(",").append("o);\n");
sp.append("} catch (Exception e) {e.printStackTrace();} return null;}");
}
publicStaticMethods.append(methodCLass).append(");\n");
allMethods.append(sp);
}
}
classsp = new StringBuilder(classsp.substring(0, classsp.length()-1)).append("{");
publicStaticMethods.append("} catch(Exception e){}}");
classsp.append(publicMethods)
.append(publicStaticMethods)
.append(constructorsp).append(allMethods).append("");
classsp.append("}");
importsp.append(classsp);
return importsp.toString();
}
public static void main(String[] args) throws Exception {
System.out.println(mackMultiProxyClass(new Class<?>[]{Idto.class}));
}
}
看起来很复杂,仔细看一下就看了那么几个事情,把一个接口class或者多个接口class变成纯字符串的过程,一共两个方法,一个是单接口的实现,很早之前写的,第二个方法是多接口的实现支持多接口,只需要传一个class对象就会生成代理类的字符串,这里仅仅是字符串,需要编译成class使用。那么如何编译成class呢。通过java中的工具类 JavaCompiler很简单的就可以生成了。我们来看两个工具类实现
package meituan.zylproxy;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.nio.CharBuffer;
import java.nio.file.WatchEvent.Kind;
import java.util.HashMap;
import java.util.Map;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
@SuppressWarnings("unchecked")
final class MemoryJavaFileManager extends ForwardingJavaFileManager {
private final static String EXT = ".java";
private Map<String, byte[]> classBytes;
public MemoryJavaFileManager(JavaFileManager fileManager) {
super(fileManager);
classBytes = new HashMap<String, byte[]>();
}
public Map<String, byte[]> getClassBytes() {
return classBytes;
}
public void close() throws IOException {
classBytes = new HashMap<String, byte[]>();
}
public void flush() throws IOException {
}
private static class StringInputBuffer extends SimpleJavaFileObject {
final String code;
StringInputBuffer(String name, String code) {
super(toURI(name), Kind.SOURCE);
this.code = code;
}
public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
return CharBuffer.wrap(code);
}
public Reader openReader() {
return new StringReader(code);
}
}
private class ClassOutputBuffer extends SimpleJavaFileObject {
private String name;
ClassOutputBuffer(String name) {
super(toURI(name), Kind.CLASS);
this.name = name;
}
public OutputStream openOutputStream() {
return new FilterOutputStream(new ByteArrayOutputStream()) {
public void close() throws IOException {
out.close();
ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
classBytes.put(name, bos.toByteArray());
}
};
}
}
public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location,
String className,
JavaFileObject.Kind kind,
FileObject sibling) throws IOException {
if (kind == JavaFileObject.Kind.CLASS) {
return new ClassOutputBuffer(className);
} else {
return super.getJavaFileForOutput(location, className, kind, sibling);
}
}
static JavaFileObject makeStringSource(String name, String code) {
return new StringInputBuffer(name, code);
}
static URI toURI(String name) {
File file = new File(name);
if (file.exists()) {
return file.toURI();
} else {
try {
final StringBuilder newUri = new StringBuilder();
newUri.append("mfm:///");
newUri.append(name.replace('.', '/'));
if (name.endsWith(EXT)) newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT);
return URI.create(newUri.toString());
} catch (Exception exp) {
return URI.create("mfm:///com/sun/script/java/java_source");
}
}
}
}
package meituan.zylproxy;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class DynamicLoader {
public static Map<String, byte[]> compile(String javaSrc) {
Pattern pattern = Pattern.compile("public\\s+class\\s+(\\w+)");
Matcher matcher = pattern.matcher(javaSrc);
if (matcher.find())
return compile(matcher.group(1) + ".java", javaSrc);
return null;
}
public static Map<String, byte[]> compile(String javaName, String javaSrc) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null);
try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) {
JavaFileObject javaFileObject = manager.makeStringSource(javaName, javaSrc);
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject));
if (task.call())
return manager.getClassBytes();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static class MemoryClassLoader extends URLClassLoader {
Map<String, byte[]> classBytes = new HashMap<String, byte[]>();
public MemoryClassLoader(Map<String, byte[]> classBytes) {
super(new URL[0], MemoryClassLoader.class.getClassLoader());
this.classBytes.putAll(classBytes);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] buf = classBytes.get(name);
if (buf == null) {
return super.findClass(name);
}
classBytes.remove(name);
return defineClass(name, buf, 0, buf.length);
}
}
}
通过DynamicLoader的compile方法可以把纯字符串的str转成byte[]数组,有了byte[]数组就可以很方便的获取到class对象了,自定义一个MemoryClassLoader通过defineClass方法来获取到class对象。这样基本所有的事情都做完了。下面我们写一个工厂类来获取代理类。
package meituan.zylproxy.util;
import java.util.Map;
import meituan.zylproxy.DynamicLoader;
import meituan.zylproxy.handlder.ZYLInvocationHandler;
public class PorxyFactory {
//单interface的时候用
public static Object newProxyInstance(Class<?> c,ZYLInvocationHandler h) throws Exception{
String classStr = ClassUtil.mackProxyClass(c);
Map<String, byte[]> m = DynamicLoader.compile(classStr);
DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m);
Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]);
return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h);
}
//多interface的时候用
public static Object newProxyInstancewWithMultiClass(Class<?>[] c,ZYLInvocationHandler h) throws Exception{
String classStr = ClassUtil.mackMultiProxyClass(c);
System.out.println (classStr);
Map<String, byte[]> m = DynamicLoader.compile(classStr);
DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(m);
Class<?> proxy =classLoader.loadClass(m.keySet().toArray(new String[0])[0]);
return proxy.getConstructor(ZYLInvocationHandler.class).newInstance(h);
}
}
最后一步我们测试一下结果吧,写一个测试类
package meituan.zylproxy.test;
import meituan.zylproxy.handlder.Hander;
import meituan.zylproxy.test.i.Idto;
import meituan.zylproxy.test.i.impl.DtoImpl;
import meituan.zylproxy.util.PorxyFactory;
public class ZylPorxyTest {
public static void main(String[] args) throws Exception {
Idto d = (Idto) PorxyFactory.newProxyInstancewWithMultiClass(DtoImpl.class.getInterfaces(), new Hander(new DtoImpl()));
d.add();
}
}
很简单,第一个参数是所有的接口,第二个是handler实现。最后我们看看结果。
大功告成。
有更多的更多的源码交流,请加群825199617交流,spring源码,spring mvc源码,手写企业级高可用rpc框架等等更多精彩源码,等你来。