利用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,利用反射,实现了新增类的加载。反射的另一个功能就是完成加载类之后的具体使用。