天天看点

Java类反射的应用

刚刚写了一篇类反射的笔记:一个相当详细的Java类反射笔记    ,然后现在再来把他实现一下

首先设定一下类反射的应用场景,现在我有一个接口

public interface Inte {
	public abstract void init();
	public abstract void servlet();
	public abstract void destroy();
}
           

然后我前面已经有了一个实现类了,现在不想修改源代码就能使用另一个实现类(这是项目开发的一大原则:开闭原则,也就是对增加开放,对修改关闭,可以百度一下),假设实现类1如下

public class Impl_1 implements Inte{
	@Override
	public void init() {
		System.out.println("servlet_1--准备服务");
	}
	@Override
	public void servlet() {
		System.out.println("servlet_1--开始服务");
	}
	@Override
	public void destroy() {
		System.out.println("servlet_1--已被销毁");
	}
}
           

现在我需要改为使用实现类2

public class Impl_2 implements Inte{
	@Override
	public void init() {
		System.out.println("servlet_2--准备服务");
	}
	@Override
	public void servlet() {
		System.out.println("servlet_2--开始服务");
	}
	@Override
	public void destroy() {
		System.out.println("servlet_2--已被销毁");
	}
}
           

那么,现在需要的工具就是:dom4j-1.61.jar(这个版本倒是差不多的)、一个xxx.xml文档、web-app_2_5xsd约束文档对xml文档进行约束。

我把约束文档web-app_2_5xsd也搬上来了,可以不用看的,更不需要自己开发,需要使用的就是下面这一小部分

<web-app xmlns="http://www.example.org/web-app_2_5" 
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
			version="2.5">
           
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
	模拟servlet2.5规范,如果开发人员需要在xml使用当前Schema约束,必须包括指定命名空间。
	格式如下:
	<web-app xmlns="http://www.example.org/web-app_2_5" 
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
			version="2.5">
-->
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 
	targetNamespace="http://www.example.org/web-app_2_5"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:tns="http://www.example.org/web-app_2_5" 
	elementFormDefault="qualified">
	
	<xsd:element name="web-app">
		<xsd:complexType>
			<xsd:choice minOccurs="0" maxOccurs="unbounded">
				<xsd:element name="servlet">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="servlet-name"></xsd:element>
							<xsd:element name="servlet-class"></xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
				<xsd:element name="servlet-mapping">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="servlet-name"></xsd:element>
							<xsd:element name="url-pattern" maxOccurs="unbounded"></xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
				<xsd:element name="welcome-file-list">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="welcome-file" maxOccurs="unbounded"></xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
			</xsd:choice>
			<xsd:attribute name="version" type="double" use="optional"></xsd:attribute>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>
           

然后写xml文档,先将约束文档摆上台,就是上面所讲的那一小段代码,然后按照约束写

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://www.example.org/web-app_2_5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd"
	version="2.5">

    <!-- 实现类1的配置
	<servlet>
	    <servlet-name>Impl_1</servlet-name>
	    <servlet-class>S00_web.xmlFoReflect.Impl_1</servlet-class>
	</servlet>
	<servlet-mapping>
	    <servlet-name>Impl_1</servlet-name>
	    <url-pattern>/impl_1</url-pattern>
	</servlet-mapping>
	 -->
	<!-- 
	实现类2的配置
	//只需要修改xml文档就可以使用另一个实现类而不需要修改代码    -->
	<servlet>
	    <servlet-name>Impl_2</servlet-name>
	    <servlet-class>S00_web.xmlFoReflect.Impl_2</servlet-class>
	</servlet>
	<servlet-mapping>
	    <servlet-name>Impl_2</servlet-name>
	    <url-pattern>/impl_2</url-pattern>
	</servlet-mapping>

</web-app>
           

这就可以了,现在我们来测试一下

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

public class TestReflex {
	@Test
	public void test1(){
		try {
			//1.创建解析器对象
			SAXReader sReader = new SAXReader();
			//2.使用解析器加载web.xml文件得到document对象
			Document doc = sReader.read("src/S00_web/xmlFoReflect/web.xml");
			//3.获取根元素节点
			Element rootElement = doc.getRootElement();
			//4.根据元素名称获取子元素节点
			Element servletElement = rootElement.element("servlet");
			//5.根据元素名称获取servlet-class的文本节点
			String servletClass = servletElement.elementText("servlet-class");
			
			//6.通过类全名获取字节码文件,类反射就在这里
			Class<?> clazz = Class.forName(servletClass);
			//7.创建实例对象
			Inte inte = (Inte) clazz.newInstance();
			//8.调用实例对象里面的方法
			inte.init();
			inte.servlet();
			inte.destroy();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}
}
           

OK,最后输出的是

servlet_2--准备服务

servlet_2--开始服务

servlet_2--已被销毁

证明类反射应用成功了