在这一篇文章里,我们关注反射及其相关话题。
反射可以帮助我们查看指定类型中的信息、创建类型的实例,调用类型的方法。我们平时使用框架,例如Spring、EJB、Hibernate等都大量的使用了反射技术。
反射简单示例
下面来演示反射相关的基本操作
首先是基础代码,我们定义一个接口及其实现,作为我们反射操作的目标:
interface HelloWorldService
{
void sayHello(String name);
} class MyHelloWorld implements HelloWorldService
{
public String name; public void sayHello(String name)
{
System.out.println("Hello " + name + ".");
} public void setName(String name) {
this.name = name;
} public String getName() {
return name;
}
}
获取方法及字段信息
下面的代码会输出给定类型中的方法和字段的声明信息:
private static void printClassTypeInfo(String type) throws ClassNotFoundException
{
Class classType = Class.forName(type);
Method[] methods = classType.getDeclaredMethods();
System.out.println("Methods info as below:");
for(Method method : methods)
{
System.out.println(method.toGenericString());
}
Field[] fields = classType.getFields();
System.out.println("Fields info as below:");
for (Field field : fields)
{
System.out.println(field.toGenericString());
}
}
在使用反射时,我们一般会使用java.lang.reflect包中的内容。
然后我们调用下面的代码:
printClassTypeInfo("sample.reflection.MyHelloWorld");
输出结果如下:
Methods info as below:
public void sample.reflection.MyHelloWorld.sayHello(java.lang.String)
public java.lang.String sample.reflection.MyHelloWorld.getName()
public void sample.reflection.MyHelloWorld.setName(java.lang.String)
Fields info as below:
public java.lang.String sample.reflection.MyHelloWorld.name
实例化对象
我们可以使用class.netInstance的方式来创建一个对象,代码如下:
private static void createInstanceTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
Class classType = Class.forName("sample.reflection.MyHelloWorld");
MyHelloWorld hello = (MyHelloWorld)classType.newInstance();
hello.sayHello("Zhang San");
}
输出结果:
Hello Zhang San.
调用对象的方法
我们可以通过方法的名称以及参数类型构建一个Method实例,然后调用Method的invoke方法,来触发方法。
示例代码如下:
private static void invokeMethodTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
{
Class classType = Class.forName("sample.reflection.MyHelloWorld");
MyHelloWorld hello = (MyHelloWorld)classType.newInstance();
Method method = classType.getMethod("sayHello", new Class[]{String.class});
method.invoke(hello, new Object[]{"Zhang San"});
}
输出结果同上。
修改字段的值
和C#不同,Java中一般使用setxxx和getxxx显示为属性赋值,因此Java中并没有Property类型,而是有Field类型。
我们可以对Field的值进行修改,代码如下:
private static void setFieldTest() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException
{
Class classType = Class.forName("sample.reflection.MyHelloWorld");
MyHelloWorld hello = (MyHelloWorld)classType.newInstance();
System.out.println("name is " + hello.name);
Field field = classType.getField("name");
field.set(hello, "Zhang San");
System.out.println("name is " + hello.name);
}
执行结果如下:
name is null
name is Zhang San
可以看出,我们成功的修改了name的值。
Annotation探索
一开始我们提到,反射是很多技术的基础,Annotation就是这样的,我们可以把Annotation看做是C#中的Attribute, 它可以对类型、方法、属性、字段、方法参数等信息进行修饰。我们可以使用“@+Annotation名”的方式来使用Annotation。
Annotation基本操作
来看下面的代码,我们定义了基于Type、Method、Parameter和Field上面的Annotation示例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ClassAnnotation
{
public String value();
} @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface MethodAnnotation
{
public String methodName();
public String returnType();
} @Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ParameterAnnotation
{
public String value();
} @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FieldAnnotation
{
public String value();
}
接着,我们定义了一个MyClass类型,使用了上述的Annotation:
@ClassAnnotation("这是作用在类型上的Annotation")
class MyClass
{
@MethodAnnotation(methodName="printInfo", returnType="void")
public void printInfo(String info)
{
System.out.println(info);
} @MethodAnnotation(methodName="printError", returnType="void")
public void printError(@ParameterAnnotation("这是作用在参数上的Annotation")String error)
{
System.err.println(error);
} @FieldAnnotation("这是作用在字段上的Annotation")
public int count;
}
对于使用了Annotation,我们可以获取其中的信息,下面两种方式都可以获取Annotation,第一种方式是通过反射遍历类型及其方法、字段,一一读取Annotation信息;第二种方式是读取指定类型的Annotation:
private static void annotationTest1()
{
MyClass temp = new MyClass(); Annotation[] annotations = temp.getClass().getAnnotations();
for(Annotation a : annotations)
{
System.out.println(a.toString());
} Method[] methods = temp.getClass().getDeclaredMethods();
for(Method method : methods)
{
annotations = method.getAnnotations();
for(Annotation a : annotations)
{
System.out.println(a.toString());
}
Annotation[][] paraAnnotations = method.getParameterAnnotations();
for(int i = 0; i < paraAnnotations.length; i++)
{
for (Annotation a : paraAnnotations[i])
{
System.out.println(a.toString());
}
}
} Field[] fields = temp.getClass().getFields();
for (Field field : fields)
{
annotations = field.getAnnotations();
for(Annotation a : annotations)
{
System.out.println(a.toString());
}
}
}
private static void annotationTest2() throws ClassNotFoundException
{
Class classType = Class.forName("sample.reflection.annotation.MyClass");
boolean flag = classType.isAnnotationPresent(ClassAnnotation.class);
if (flag)
{
ClassAnnotation annotation = (ClassAnnotation) classType.getAnnotation(ClassAnnotation.class);
System.out.println(annotation.toString());
}
Method[] methods = classType.getMethods();
for(Method method : methods)
{
if (method.isAnnotationPresent(MethodAnnotation.class))
{
System.out.println(((MethodAnnotation)method.getAnnotation(MethodAnnotation.class)).toString());
}
Annotation[][] paraAnnotations = method.getParameterAnnotations();
for(int i = 0; i < paraAnnotations.length; i++)
{
for (Annotation a : paraAnnotations[i])
{
System.out.println(a.toString());
}
}
}
Field[] fields = classType.getFields();
for (Field field:fields)
{
if (field.isAnnotationPresent(FieldAnnotation.class))
{
System.out.println(((FieldAnnotation)field.getAnnotation(FieldAnnotation.class)).toString());
}
}
}
上述两个方法的输出都是一样的,如下:
@sample.reflection.annotation.ClassAnnotation(value=这是作用在类型上的Annotation)
@sample.reflection.annotation.MethodAnnotation(methodName=printInfo, returnType=void)
@sample.reflection.annotation.MethodAnnotation(methodName=printError, returnType=void)
@sample.reflection.annotation.ParameterAnnotation(value=这是作用在参数上的Annotation)
@sample.reflection.annotation.FieldAnnotation(value=这是作用在字段上的Annotation)
在WebService中使用Annotation
上述代码看上去可能有些枯燥,不能显示出Annotation的威力,那么我们接下来看WebService,在WebService中,我们可以使用WebMethod、WebParam等Annotation来声明方法或者参数。
接下来,我们来实现一个非常简单的Web服务:
@WebService(targetNamespace="http://test", serviceName="HelloService")
public class HelloServiceProvider
{
@WebResult(name="HelloString")
@WebMethod
public String sayHello(@WebParam(name="userName") String name)
{
return "Hello " + name;
} @Oneway
@WebMethod(action="userLogin", operationName="userLogin")
public void login()
{
System.out.println("User has logged on.");
} public static void main(String[] args)
{
Thread thread = new Thread(new HelloServicePublisher());
thread.start();
}
}
然后定义一个Publisher:
class HelloServicePublisher implements Runnable
{
public void run()
{
Endpoint.publish("http://localhost:8888/test/HelloService", new HelloServiceProvider());
}
}
在命令行中,我们定位到源代码路径,执行下面的命令:
wsgen -cp . HelloServiceProvider
wsgen位于JDK的bin目录中。
然后我们启动HelloServiceProvider,在浏览器中输入如下地址:http://localhost:8888/test/HelloService,可以看到如下信息:
aaarticlea/png;base64,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" alt="" width="710" height="196" />
点击WSDL链接,可以看到:
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><definitions targetNamespace="http://test" name="HelloService"><types><xsd:schema><xsd:import namespace="http://test" schemaLocation="http://localhost:8888/test/HelloService?xsd=1"/></xsd:schema></types><message name="sayHello"><part name="parameters" element="tns:sayHello"/></message><message name="sayHelloResponse"><part name="parameters" element="tns:sayHelloResponse"/></message><message name="userLogin"><part name="parameters" element="tns:userLogin"/></message><portType name="HelloServiceProvider"><operation name="sayHello"><input wsam:Action="http://test/HelloServiceProvider/sayHelloRequest" message="tns:sayHello"/><output wsam:Action="http://test/HelloServiceProvider/sayHelloResponse" message="tns:sayHelloResponse"/></operation><operation name="userLogin"><input wsam:Action="userLogin" message="tns:userLogin"/></operation></portType><binding name="HelloServiceProviderPortBinding" type="tns:HelloServiceProvider"><soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/><operation name="sayHello"><soap:operation soapAction=""/><input><soap:body use="literal"/></input><output><soap:body use="literal"/></output></operation><operation name="userLogin"><soap:operation soapAction="userLogin"/><input><soap:body use="literal"/></input></operation></binding><service name="HelloService"><port name="HelloServiceProviderPort" binding="tns:HelloServiceProviderPortBinding"><soap:address location="http://localhost:8888/test/HelloService"/></port></service></definitions>
JDK中自带了Web服务器,我们不需要把上述代码部署到其他服务器中。
动态代理机制
Spring中一大特色是AOP,面向方面编程也是框架设计一个趋势。对于业务中的共通操作,诸如记录日志、维护事务等,如果和业务逻辑纠缠在一起,会造成代码职责不清,后续维护困难等问题。利用AOP,我们可以很好的分离共通操作和业务操作。
下面我们来实现一个简单的AOP框架,要实现这样一个框架,需要3部分:1)InvocationHandler,来触发方法;2)Interceptor,来定义拦截器;3)DynamicProxy,来动态创建代理对象。
首先我们看Interptor的定义:
interface AOPInterceptor
{
public void before(Method method, Object[] args);
public void after(Method method, Object[] args);
public void afterThrowing(Method method, Object[] args);
public void afterFinally(Method method, Object[] args);
}
接下来是InvocationHandler:
class DynamicProxyInvocationHandler implements InvocationHandler
{
private Object target;
private AOPInterceptor interceptor; public DynamicProxyInvocationHandler(Object target, AOPInterceptor interceptor)
{
this.target = target;
this.interceptor = interceptor;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
try
{
interceptor.before(method, args);
Object returnValue = method.invoke(target, args);
interceptor.after(method, args);
return returnValue;
}
catch(Throwable t)
{
interceptor.afterThrowing(method, args);
throw t;
}
finally
{
interceptor.afterFinally(method, args);
}
}
}
最后是DynamicProxy:
class DynamicProxyFactoryImpl implements DynamicProxyFactory
{
public <T> T createProxy(Class<T> clazz, T target, AOPInterceptor interceptor)
{
InvocationHandler handler = new DynamicProxyInvocationHandler(target, interceptor);
return (T)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {clazz}, handler);
}
}
至此,我们构建了一个”简易“的AOP拦截器。下面我们来创建一些测试代码。
首先是实现AOPInterceptor接口:
class MyInterceptor implements AOPInterceptor
{ public void after(Method method, Object[] args) {
System.out.println("方法执行结束。");
} public void afterFinally(Method method, Object[] args) {
System.out.println("方法体Finally执行结束。");
} public void afterThrowing(Method method, Object[] args) {
System.out.println("方法抛出异常。");
} public void before(Method method, Object[] args) {
System.out.println("方法开始执行");
}
}
然后利用本文一开始定义的HelloWorldService,来完成测试,需要在MyHello的sayHello方法最后,追加一行代码:
throw new RuntimeException();
接着是测试代码:
private static void test()
{
MyInterceptor interceptor = new MyInterceptor();
HelloWorldService hello = new MyHelloWorld();
DynamicProxyFactory factory = new DynamicProxyFactoryImpl();
HelloWorldService proxy = factory.createProxy(HelloWorldService.class, hello, interceptor);
proxy.sayHello("Zhang San");
}
最终,执行结果如下:
方法开始执行
Hello Zhang San.
方法抛出异常。
方法体Finally执行结束。
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at sample.reflection.dynamicproxy.$Proxy0.sayHello(Unknown Source)
at sample.reflection.dynamicproxy.Sample.test(Sample.java:18)
at sample.reflection.dynamicproxy.Sample.main(Sample.java:9)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sample.reflection.dynamicproxy.DynamicProxyInvocationHandler.invoke(Sample.java:60)
... 3 more
可以看出,我们已经在业务执行的前、后、异常抛出后以及finally执行后进行了拦截,达到了我们期望的效果。