jjzjj

反射时竟然NoSuchMethodException了!看这篇超详细的解决方案吧

马剑威老师 2023-08-30 原文

前几天九哥在讲Servlet时,为了灵活地使用同一个Servlet来处理对同一张表的业务操作请求,我给学生讲解了BaseServlet工具类的封装,基本实现思路有如下几个步骤。

一. 反射封装BaseServlet工具类

使用反射封装BaseServlet工具类,无论是哪个Servlet接收到请求,都由该类完成请求分发。因此该类的主要作用就是通过反射机制,确定我们请求的到底是哪个Servlet的哪个方法。

/*
 * BaseServlet 获取客户端请求的是哪个servlet的哪个方法
 * */
public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取客户端发来请求的标识:即要执行的方法名
        String method = req.getParameter("method");
        //获取方法属于哪个Servlet类
        Class<? extends BaseServlet> clazz = this.getClass();
        //通过类字节码对象获取要执行方法的对象
        try {
            Method mh = clazz.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
            //执行方法
            mh.invoke(this,req,resp); // this.insert(req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

二. 继承BaseServlet父类

以后再创建Servlet时,我们要使任意一个Servlet类,不再直接继承HttpServlet,而是要继承统一的BaseServlet,完成请求的分发管理,例如:

@WebServlet("/stuinfo")
public class StuinfoServlet extends BaseServlet {
    //删除方法
    public void delById(HttpServletRequest req, HttpServletResponse resp) {

    }

    //修改学员信息
    public void update(HttpServletRequest req, HttpServletResponse resp){

    }

    //根据学号查询方法
    public void findById(HttpServletRequest req, HttpServletResponse resp)  {
    }

    //查询全部方法
    public void findAll(HttpServletRequest req, HttpServletResponse resp)  {
    }

    //添加方法
    public void insert(HttpServletRequest req, HttpServletResponse resp)  {
    }
}

三. 异常展现

然而有个别同学在按照上述思路自己编写代码时,却遇到了下面的NoSuchMethodException异常。他排查许久未果,于是就来找九哥帮他解决。

四. 异常原因

起初,九哥以为是学生从客户端发出请求时,未携带执行方法的标识或携带的方法标识与实际方法名不匹配,从而导致通过反射机制获取方法对象时报错。因为我们知道,在通过Methodmh=clazz.getMethod(method,HttpServletRequest.class,HttpServletResponse.class)获取Method对象时,必须保证方法名、参数匹配,才能找到指定的方法,否则就会出现此类异常。

但经过排查,发现并不是以上原因,该学生的代码如下:

@WebServlet("/stuinfo")
public class StuinfoServlet extends BaseServlet {
    //创建serivce层对象
    private StuinfoService ss = new StuinfoSerivceImpl();
    
    //查询方法
    private void findAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //调用service层查询方法
        List<Stuinfo> list = ss.findAll();
        //将list集合数据保存到域对象中
        req.setAttribute("stuList",list);
        //跳转到主页面
        req.getRequestDispatcher("index.jsp").forward(req,resp);
    }
}

五. 异常解决

可能你也一眼就看到了,上述代码中,查询方法使用的是private修饰符,而私有成员在该类的外部是不能被访问的!因此我们在利用反射,通过getMethod()方法获取Method对象时就会出现NoSuchMethodException异常。所以现在的解决办法,你是不是立刻就明朗了,我们直接将private改成public就可以了

六. 暴力反射

上面的问题是解决了,但大家还要知道,反射机制中还有一种叫暴力反射,听起来是不是很厉害!!利用暴力反射,即使被private修饰也可以进行正常的操作。

九哥在这里给大家再补上一刀,反射里的Constructor、Field、Method三个类都有getDeclaredXxx方法(这里的Xxx表示Constructor、Field、Method),该方法可以不受权限控制,就能够获取到类中的这些成员信息。如果我们想要使用私有的构造函数、字段、方法,则会自动访问类的isAccessable,其默认值是false,表示在访问成员时需要安全检查,如果发现是私有的则不允许访问。所以,如果我们想要访问类中的私有成员时,需要调用setAccessible(boolean flag)方法,将其改为true。这样,我们就可以对类中的私有成员进行操作了。

 *威哥Java学习交流Q群:691533824
加群备注:CSDN推荐
      

有关反射时竟然NoSuchMethodException了!看这篇超详细的解决方案吧的更多相关文章

  1. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  2. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  3. Ruby 守护进程和 JRuby - 备选方案 - 2

    我有一个应用程序正在从Ruby迁移到JRuby(由于需要通过Java提供更好的Web服务安全支持)。我使用的gem之一是daemons创建后台作业。问题在于它使用fork+exec来创建后台进程,但这对JRuby来说是禁忌。那么-是否有用于创建后台作业的替代gem/wrapper?我目前的想法是只从shell脚本调用rake并让rake任务永远运行......提前致谢,克里斯。更新我们目前正在使用几个与Java线程相关的包装器,即https://github.com/jmettraux/rufus-scheduler和https://github.com/philostler/acts

  4. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  5. H2数据库配置及相关使用方式一站式介绍(极为详细并整理官方文档) - 2

    目录H2数据库入门以及实际开发时的使用1.H2数据库的初识1.1H2数据库介绍1.2为什么要使用嵌入式数据库?1.3嵌入式数据库对比1.3.1性能对比1.4技术选型思考2.H2数据库实战2.1H2数据库下载搭建以及部署2.1.1H2数据库的下载2.1.2数据库启动2.1.2.1windows系统可以在bin目录下执行h2.bat2.1.2.2同理可以通过cmd直接使用命令进行启动:2.1.2.3启动后控制台页面:2.1.3spring整合H2数据库2.1.3.1引入依赖文件2.1.4数据库通过file模式实际保存数据的位置2.2H2数据库操作2.2.1Mysql兼容模式2.2.2Mysql模式

  6. ruby-on-rails - 能够处理 rar/tar/zip/7z 的 Ruby/rubyzip 替代方案? - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭9年前。Improvethisquestion我想知道是否有人知道Ruby的ruby​​zip替代品,它可以处理各种格式,特别是zip/rar/7z?我知道libarchive,但它对我的目的来说并不完整(它是一个很好的gem)。(澄清一下,libarchive-对我不起作用-因为

  7. ruby-on-rails - 对于 Ruby 应用程序,是否有比 Sanitize 更好的替代方案? - 2

    我爱Sanitize.这是一个了不起的实用程序。我遇到的唯一问题是,它需要永远准备一个开发环境,因为它使用Nokogiri,这对编译时间来说是一种痛苦。是否有任何程序可以在不使用Nokogiri的情况下执行Sanitize的操作(如果没有别的,只是温和地执行它的操作)?这将以指数方式提供帮助! 最佳答案 Rails有自己的SanitizeHelper。根据http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html,它将Thissanitizehe

  8. ruby-on-rails - rails3 中 cron 作业的解决方案 - 2

    我尝试每天在我的Rails应用程序中自动记录一些数据。我想知道是否有人知道一个好的解决方案?我找到了https://github.com/javan/whenever,但我想确保在选择之前了解所有选项。谢谢!艾略特 最佳答案 我真的很喜欢whenever-这是一个很棒的Gem,我已经在生产中使用了它。关于它还有一个很好的Railscasts插曲:http://railscasts.com/episodes/164-cron-in-ruby 关于ruby-on-rails-rails3中c

  9. 华为ensp详细安装包、安装教程及所遇问题 - 2

    目录一、安装包链接二、安装详细步骤1.安装Wireshark和WinPcap2.安装OracleVMVirtualBox3.安装ensp三、安装后注册四、启动路由器出现40错误怎么解决一、安装包链接二、安装详细步骤链接:https://pan.baidu.com/s/1QbUUYMOMIV2oeIKHWP1SpA?pwd=xftx提取码:xftx1.安装Wireshark和WinPcap找到Wireshark安装包所在文件夹,双击它,按照以下步骤安装。2.安装OracleVMVirtualBox找到OracleVMVirtualBox安装包所在文件夹,双击它,按照以下步骤安装。注:可自定义安装

  10. Linux操作系统CentOS7安装Nginx[详细版] - 2

    Nginx安装1.官网下载Nginx2.使用XShell和Xftp将压缩包上传到Linux虚拟机中3.解压文件nginx-1.20.2.tar.gz4.配置nginx5.启动nginx6.拓展(修改端口和常用命令)(一)修改nginx端口(二)常用命令1.官网下载Nginxhttp://nginx.org/en/download.html这里我下载的是1.20.2版本,大家按需下载对应稳定版即可2.使用XShell和Xftp将压缩包上传到Linux虚拟机中没有XShell可以参考《Linux操作系统CentOS7连接XShell》3.解压文件nginx-1.20.2.tar.gz1)检查是否存

随机推荐