1.需求的引出
每个类有3个方法,这三个方法执行的时候有不同的控制台输出:
public void init(){
System.out.println("myservlet1-init");
}
public void service(){
System.out.println("myservlet1-service");
}
public void destory(){
System.out.println("myservlet1-destory");
}
}
2.实现
而我们需要用java类调用执行。对于我们说这样是不难的,我们可以轻而易举的写出如下的代码:
// 模拟从外界传递过来的参数
String url = "/s1";
// 如果url是s1, 执行myServlet1
// 如果url是s2, 执行myServlet2
// 如果url是s3, 执行myServlet3
if ("/s1".equals(url)) {
MyServlet1 myServlet1 = new MyServlet1();
myServlet1.init();
myServlet1.service();
myServlet1.destory();
} else if ("/s2".equals(url)) {
MyServlet2 myServlet2 = new MyServlet2();
myServlet2.init();
myServlet2.service();
myServlet2.destory();
}
缺点:不利于程序功能追加,功能扩展,程序扩展性不强 。 优点:执行效率高
而要增强扩展性,自然而然的引出了反射。用反射去改进上述的第一版代码:
// 模拟从外界传递过来的参数
String url = "/s1";
// 如果url是s1, 执行myServlet1
// 如果url是s2, 执行myServlet2
// 如果url是s3, 执行myServlet3
// 反射修改 1.创建字节码文件
Class clazz = Class.forName("xml.demo1.MyServlet1");
// 2.创建实例对象
Object object = clazz.getConstructor().newInstance();
// 3.反射执行init service destory
Method init = clazz.getMethod("init");
init.invoke(object, null);
Method service = clazz.getMethod("service");
service.invoke(object, null);
Method destory = clazz.getMethod("destory");
destory.invoke(object, null);
反射的优点:增加了代码的复用性,代码可以复用,需要修改的:forName的参数,动态赋值
第三版代码如下;
// 模拟从外界传递过来的参数
String url = "/s1";
// 如果url是s1, 执行myServlet1
// 如果url是s2, 执行myServlet2
// 如果url是s3, 执行myServlet3
// map集合 不需要有序,
Map<String, String> map = new HashMap<String, String>();
map.put("/s1", "xml.demo1.MyServlet1");
map.put("/s2", "xml.demo1.MyServlet2");
map.put("/s3", "xml.demo1.MyServlet3");
// 反射修改 1.创建字节码文件
Class clazz = Class.forName(map.get(url));
// 2.创建实例对象
Object object = clazz.getConstructor().newInstance();
// 3.反射执行init service destory
Method init = clazz.getMethod("init");
init.invoke(object, null);
Method service = clazz.getMethod("service");
service.invoke(object, null);
Method destory = clazz.getMethod("destory");
destory.invoke(object, null);
优点: 增强程序的扩展性,并且将配置信息存储到map 中。 功能追加,只需要维护map数据可以
缺点: .class文件不可以直接修改,如果项目上线【给用户直接使用】,用户得到的全是class文件,不利于用户进行程序维护
那么怎么去解决这个问题呢?最先开始想到的就是可以用Properties配置文件 对应map集合 key = value 的形式。 用properties去解决这个问题是十分不错的,是一个可行的办法,同时与properties一样功能的xml配置文件。从灵活程度上来说: .xml格式的文件要比.properties格式的文件更灵活一些,.properties格式的文件已键值对形式存在,主要就是赋值,而且只能赋值,不能够进行其他的操作。
.xml格式的文件可以有多种操作方法,例如添加一个属性,或者做一些其他的定义等。
3.xml的引入
第四版修改
//模拟从外界传递进来的参数
String url="/s2";
//需要根据url参数 判断执行哪个java类
//相当于程序配置信息
//如果是/s1 执行MyServlet1 如果是/s2 执行MyServlet2 如果是/s3 执行MyServlet3
//数据是存储在xml中,是把xml中的数据读取出来填充进map中
//解析三步 把数据读取到内存中
SAXReader reader = new SAXReader();
Document dom = reader.read(new FileInputStream("src\\xml\\web.xml"));
Element root = dom.getRootElement();
//把所有的Servlet标签都获取到 全路径
List<Element> servletList = root.elements("servlet");
//把所有的Servlet-mapping标签都获取 url参数
List<Element> servletmappingList = root.elements("servlet-mapping");
//需要将 名字-全路径 key=名字 value=全路径 map
HashMap<String, String> servletMap = new HashMap<String,String>();
//填充servletMap
for(Element temp:servletList){
String key = temp.elementText("servlet-name");
String value = temp.elementText("servlet-class");
servletMap.put(key, value);
}
//需要将 名字-url key=名字 value=url map
HashMap<String, String> servletmappingMap = new HashMap<String,String>();
for(Element temp:servletmappingList){
String key = temp.elementText("servlet-name");
String value = temp.elementText("url-pattern");
servletmappingMap.put(key, value);
}
//把上述两个map转存到底下的map中
//key=url value=全路径
Map<String, String> map = new HashMap<String,String>();
for(String key:servletMap.keySet()){
String url_param = servletmappingMap.get(key);
String servlet_class = servletMap.get(key);
map.put(url_param, servlet_class);
}
//反射修改 MyServlet1
//1、获取对应的字节码文件
Class clazz = Class.forName(map.get(url));
//2、创建实例对象 MyServlet1 obj = new MyServlet1();
Object obj = clazz.getConstructor().newInstance();
//3、反射执行init service destory
Method init = clazz.getMethod("init");
init.invoke(obj, null);
Method service = clazz.getMethod("service");
service.invoke(obj, null);
Method destory = clazz.getMethod("destory");
destory.invoke(obj, null);
}
xml如下
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5">
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>xml.demo1.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Servlet2</servlet-name>
<servlet-class>xml.demo1.MyServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet2</servlet-name>
<url-pattern>/s2</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Servlet3</servlet-name>
<servlet-class>xml..demo.MyServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet3</servlet-name>
<url-pattern>/s3</url-pattern>
</servlet-mapping>
</web-app>
注意:
反射和xml解析意味着效率底下,从上述代码的改进可以看出效率与扩展性永远是一道单选题,如果要增强效率必然要牺牲效率。