ef只修改一个字段_对Java反射的理解,应用举例:修改Tomcat Request Headers

1、什么是反射?
我们在学Java的过程中一定会遇到Java反射,不管是我们常用的框架,还是面试官的问题。多多少少都会牵扯到。那么什么才是反射?很抽象的一个概念!!没有之一,反射的功能很强大,范围很广泛,所以说它不是一句话能概括的了的。我理解反射就是:在程序运行期间,我们通过一系列操作去获取到对象所有信息(如:类、方法、成员变量等等)的操作。(感觉这样定义,把反射说的很狭义)
2、反射应用
日常业务开发很少会用到反射。但是涉及到通用模块、框架开发等肯定会涉及到反射的应用。
如我们配置数据源时通常配置的数据库驱动、Spring配置文件注入Bean时,都是通过反射来实现。
3、经典案例:我们通过反射,修改HttpServletRequest的Header值(Tomcat)
我们知道在Java中HttpServletRequest是一个接口,具体实现是由服务器去实现对应类。这里选择的是Tomcat,如果更换服务器,这个代码是不适用的。
先把全部代码贴出来:

    /**     * 修改request请求头信息,只适用于Tomcat     * @param servletRequest    request     * @param headerKey 修改HeaderKey     * @param headerValue   修改HeaderValue     */    private int modifyHeader(HttpServletRequest servletRequest, String headerKey, String headerValue){        try {            logger.info("HttpServletRequest implement class is {}", servletRequest.getClass().getName());            //获取org.apache.catalina.connector.RequestFacade类中request字段            Field requestField = servletRequest.getClass().getDeclaredField("request");            //设置字段跳过安全检查            requestField.setAccessible(true);            //获取javax.servlet.http.HttpServletRequest实现类中request字段对象:org.apache.catalina.connector.Request            Object requestObject = requestField.get(servletRequest);            logger.info("RequestFacade class filed request implement class is {}.", requestObject.getClass().getName());            //获取org.apache.catalina.connector.Request类中coyoteRequest字段            Field coyoteRequestField = requestObject.getClass().getDeclaredField("coyoteRequest");            //设置字段跳过安全检查            coyoteRequestField.setAccessible(true);            //获取org.apache.catalina.connector.Request实现类中coyoteRequest字段对象:org.apache.catalina.connector.Request.coyoteRequest            Object coyoteRequestObject = coyoteRequestField.get(requestObject);            logger.info("org.apache.coyote.Request class filed coyoteRequest implement class is {}", coyoteRequestObject.getClass().getName());            //获取org.apache.catalina.connector.Request.coyoteRequest类中headers字段            Field headersField = coyoteRequestObject.getClass().getDeclaredField("headers");            //设置字段跳过安全检查            headersField.setAccessible(true);            //获取org.apache.catalina.connector.Request.coyoteRequest实现类中headers字段对象实现:org.apache.tomcat.util.http.MimeHeaders            Object headersObject = headersField.get(coyoteRequestObject);            //确定字段类型为:org.apache.tomcat.util.http.MimeHeaders            if(headersObject instanceof MimeHeaders){                //使用MimeHeaders类方法设置Header值                MimeHeaders headers = (MimeHeaders) headersObject;                //addValue只添加,setValue会遍历查找,如果不存在此Header再添加//                headers.addValue(headerKey).setString(headerValue);                headers.setValue(headerKey).setString(headerValue);                logger.info("update request Headers success:{}", servletRequest.getHeader(headerKey));            }        }catch (Exception e){            logger.error("Update Request Headers Exception; {}", e.getMessage(), e);            return 1;        }        return 0;    }

解析:

我们通过getClass().getName()知道Tomcat对HttpServletRequest的实现类是:org.apache.catalina.connector.RequestFacade。查看RequestFacade类getHeader()方法的实现和调用流程如下:

8f74f1f72f29b5fd0da76f153c210158.pngorg.apache.catalina.connector.RequestFacade#getHeader方法调用的是org.apache.catalina.connector.Request#getHeader方法:

     ……    /**     * The wrapped request.     */    protected Request request = null;    ……    @Override    public String getHeader(String name) {        if (request == null) {            throw new IllegalStateException(                            sm.getString("requestFacade.nullRequest"));        }        return request.getHeader(name);    }    ……

8f74f1f72f29b5fd0da76f153c210158.pngorg.apache.catalina.connector.Request#getHeader方法调用的是org.apache.coyote.Request#getHeader方法:

    ……    /**     * Coyote request.     */    protected org.apache.coyote.Request coyoteRequest;    @Override    public String getHeader(String name) {        return coyoteRequest.getHeader(name);    }    ……

8f74f1f72f29b5fd0da76f153c210158.pngorg.apache.coyote.Request#getHeader方法调用的是org.apache.tomcat.util.http.MimeHeaders#getHeader方法:

……    private final MimeHeaders headers = new MimeHeaders();    public String getHeader(String name) {        return headers.getHeader(name);    }    ……

8f74f1f72f29b5fd0da76f153c210158.png在org.apache.tomcat.util.http.MimeHeaders#getHeader中我们可以看到Header的键值对是从org.apache.tomcat.util.http.MimeHeaderField中遍历获取。

    /**     * The header fields.     */    private MimeHeaderField[] headers = new MimeHeaderField[DEFAULT_HEADER_SIZE];    public String getHeader(String name) {        MessageBytes mh = getValue(name);        return mh != null ? mh.toString() : null;    }        public MessageBytes getValue(String name) {        for (int i = 0; i < count; i++) {            if (headers[i].getName().equalsIgnoreCase(name)) {                return headers[i].getValue();            }        }        return null;    }

8f74f1f72f29b5fd0da76f153c210158.png且在org.apache.tomcat.util.http.MimeHeaders中,我们看到此类提供了org.apache.tomcat.util.http.MimeHeaders#setValue方法返回org.apache.tomcat.util.buf.MessageBytes类,且在org.apache.tomcat.util.buf.MessageBytes中存在org.apache.tomcat.util.buf.MessageBytes#setString方法。所以我们可以通过反射,获取到org.apache.tomcat.util.http.MimeHeaders对象,然后使用MimeHeaders对象的setValue方法进行设置Header值。

完毕!!!


面试总结题目——Redis部分

面试总结—Mysql-01

面试总结—Mysql02—索引、数据库引擎、乐观锁

面试总结—Java01_Jdk7和Jdk8区别

面试总结—Java02

欢迎点赞:我的博客

ab2774b275f8865f8a1ece6583c25022.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值