JavaWeb综合案例-Servlet优化

文章详细介绍了Java反射机制,包括Class类、类加载、成员变量、方法和构造方法的访问。同时,讨论了Servlet的优化,如何将WebServlet的访问路径改为通配符形式,以及如何通过反射动态执行方法,实现基于请求路径的方法分发,替代HttpServlet的默认行为。
摘要由CSDN通过智能技术生成

在这里插入图片描述

将WebServlet的访问路径不要写死,写成通配符的形式

1. 反射笔记(后续代码会用到该机制)

1.1 基础概念

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

言简意赅的说法就是:反射就是将Java类中各个成分映射成为一个个的Java对象

  1. 成员变量
  2. 方法、构造方法
  3. 包等等

但在此之前,先要把class类以及类的加载机制,在此基础上再探讨如何通过反射获取class类以及类的成员变量等等

1.1.1 Class类

Class类是一个实实在在的类,存在于java.lang包中;
Class类的实例标识java应用运行时的类或接口;
数组同样也被映射为class对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象;
手动编写的类被编译后会产生一个Class对象,其表示的是创建的类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件);
每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象;
Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载
Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要

1.1.2 类加载

在这里插入图片描述

1.1.3 反射的使用

我们如何通过反射获取Class类对象以及类中的成员变量、方法、构造方法?

在类加载的时候,jvm会创建一个class对象;
在Java中,Class类与java.lang.reflect类库一起对反射技术进行了全力的支持;
常用的类主要有Constructor类:表示的是Class 对象所表示的类的构造方法,利用它可以在运行时动态创建对象;
Field类:表示Class对象所表示的类的成员变量,通过它可以在运行时动态修改成员变量的属性值(包含private);
Method类:表示Class对象所表示的类的成员方法,通过它可以动态调用对象的方法(包含private)

1.1.4 反射机制的执行流程

在这里插入图片描述

1.1.5 反射小结

反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;
每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;
反射也是考虑了线程安全的,放心使用;
反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;
反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;
当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;
调度反射方法,最终是由jvm执行invoke0()执行;

综述

反射是指程序在运行时可以访问、检测和修改其自身状态或行为的能力。在Java中,反射机制主要由java.lang.Class、java.lang.reflect.Method、java.lang.reflect.Field等类和接口组成,可以通过它们获取类信息、对象信息和方法信息等。

反射的原理是通过Java反射API,通过Java类加载器加载Java类文件到内存中,并且分析字节码文件,把类的各种成分(如类名、方法、属性等)映射成相应的Java类,去创建对应的类对象、方法对象、属性对象等。这些对象都存放在Java虚拟机的堆内存中。

具体来说,当需要对一个类进行反射时,JVM会首先利用类加载器读取类文件字节码,并转换成JVM能够理解的数据结构,然后创建一个Class对象,用来代表这个类。通过Class对象可以获取这个类的各种信息,如类名、方法、属性等,同时也可以创建该类的对象。

2. Servlet优化

在这里插入图片描述

问题一:之前在servlet中写WebServlet资源路径固定,如何解决?
路径不要写成固定,写成通配符形式
如:/brand/*

问题二:获取最后一段路径,也就是方法名称,获取了方法名称怎样执行方法?
通过反射机制,获取BrandServlet的字节码文件,获取其方法的method对象,method.invoke()就可以调用方法了

问题三:BrandServlet extends HttpServlet,而HttpServlet在对应的service方法中通过request的请求方式做了方法分发,例如post请求就是采用doPost(),那么在之前的servlet中我们只能执行doGet()doPost()方法,但现在不写这两个方法,而是写自定义方法,这时就不能继承HTTPServlet了,方法分发的功能也不采用了
而是采用自定义的Servlet,使用请求路径进行方法分发,替换HttpServlet的根据请求方式进行方法分发

针对问题三

不再采用请求方式进行方法分发,而是采用请求路径进行方法分发,所以这里重写service方法

下面代码思想非常关键

/**
 * 替换HttpServlet,根据请求的最后一段路径来进行方法分发
 */

public class BaseServlet extends HttpServlet {

    //根据请求的最后一段路径来进行方法分发
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 获取请求路径
        String uri = req.getRequestURI(); // /brand-case/brand/selectAll

        //2. 获取最后一段路径,方法名
        int index = uri.lastIndexOf('/');
        String methodName = uri.substring(index + 1); //  /selectAll? selectAll?

        //3. 执行方法

        // 谁调用我(this),我代表谁
        // BrandServlet会被Tomcat服务器调用,而它继承了BaseServlet
        // 其中BaseServlet的service方法也是由Tomcat服务器调用,由BrandServlet调用
        // 所以this指代的是BrandServlet
        //System.out.println(this);

        //3.1 获取BrandServlet /UserServlet 字节码对象 Class
        Class<? extends BaseServlet> cls = this.getClass();
        //3.2 获取方法 Method对象
        try {
            // 获取方法名,参数
            Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            //3.3 执行方法
            method.invoke(this,req,resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}

最后

修改前端页面的URL路径即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值