利用java反射实现tomcat运行中添加新类

个人博客地址:http://www.cnblogs.com/wdfwolf3/。转载注明出处,谢谢。

  Java 反射一个是可以获取程序在运行时刻的内部结构,二是在运行时刻对一个Java对象进行操作。主要用途有以下几点:

1.工厂模式:Factory类中用反射的话,添加了一个新的类之后,就不需要再修改工厂类Factory

2.数据库JDBC中通过Class.forName(Driver)来获得数据库连接驱动

3.分析类文件:得到类中的方法等等访问一些不能访问的变量或属性(破解别人代码)。

  之前学习了反射的一些知识,这里针对第二个功能写一个小demo,试一下不停止tomcat的运行(即在web服务启动以后不重启服务),将新的的类放入服务中,并能够成功加载使用。这里只是为了测试反射,对于功能和web的搭建都很简单。直接上源代码,不难理解,后面主要讲一下操作过程。

项目结构如下,使用idea+maven+servlet+tomcat

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="WebApp_ID" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <!-- 这里名称随意,因为打成war包放进tomcat,访问url路径与这里的名字没有关系。 -->
        <servlet-name>HttpRequest</servlet-name>
        <!--用来指定servlet的实现类-->
        <servlet-class>com.wdf.HttpRequest</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <!-- 名称需与servlet里的name一致 -->
        <servlet-name>HttpRequest</servlet-name>
        <!-- 页面中调用servlet类时,名称可以任意取,但是需要/ -->
        <url-pattern>/my</url-pattern>
    </servlet-mapping>
</web-app>

DynamicOne.java和DynamicTwo.java两个类都是新建的空类,不需要实现什么方法。HttpRequest.java为HttpServlet继承类,如下

package com.wdf;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class HttpRequest extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            //classname.txt中存放待加载的类名,这个也可以放在数据库中测试,每次查询出来。只是懒得写jdbc了。
            BufferedReader bufferedReader = new BufferedReader(new FileReader("classname.txt文件相对路径"));
            String className = null;
            List<String> list = new ArrayList<>();
       //文件中每行一个类名,按行读取加载,然后将类名放入list待网页显示。
            while ((className = bufferedReader.readLine()) != null) {
                Class c = Class.forName(className);
                Object object = c.newInstance();
                list.add(className);
            }
            PrintWriter printWriter = response.getWriter();
            printWriter.println("<html><title></title><body>" + Arrays.toString(list.toArray()) + "</body></html>");
            printWriter.flush();
            printWriter.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

classname.txt存放类名,放入本地某个位置待函数调用。

com.wdf.reflect.DynamicOne
com.wdf.reflect.DynamicTwo

  代码就是这些,然后通过maven project下的package将项目打成war包,放入tomcat的webapps目录下。这里不用maven或者不用idea都无所谓,就是打成war包即可。war包名称是reflect.war(默认项目名称.war)。这个名称是url的根路径,即127.0.0.1:8080/reflect,然后加上web.xml中<servlet-mapping>设定的/my,就是访问的我们写的HttpRequest类。可以看到页面上显示[com.wdf.reflect.DynamicOne, com.wdf.reflect.DynamicTwo],正是我们预期的。
  然后我们在com.wdf.reflect包下新建一个DynamicThree类,并build成class文件,将这个文件放入webapps/reflect/WEB-INF/classes/com/wdf/reflect/下面,因为这里就是tomcat启动后解析war包,得到class文件后的存放位置,放入正确的包位置中才可以正确的找到。然后修改一下classname.txt文件,加入一行com.wdf.reflect.DynamicThree,这样函数可以读取到这一行,得到这个类名,然后去加载DynamicThree.class。这两步完成后刷新页面,看到如下,说明成功加载。


 整个过程不需要停止tomcat,利用反射,实现了新增类的加载。反射的另一个功能就是完成加载类之后的具体使用。
原文地址:https://www.cnblogs.com/wdfwolf3/p/7423436.html