源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

基于Java回顾之反射的使用分析

  • 时间:2022-11-08 17:02 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:基于Java回顾之反射的使用分析
反射可以帮助我们查看指定类型中的信息、创建类型的实例,调用类型的方法。我们平时使用框架,例如Spring、EJB、Hibernate等都大量的使用了反射技术。 反射简单示例   [b]下面来演示反射相关的基本操作[/b]   首先是基础代码,我们定义一个接口及其实现,作为我们反射操作的目标:
[u]复制代码[/u] 代码如下:
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;      }  }
  [b]获取方法及字段信息 [/b]    下面的代码会输出给定类型中的方法和字段的声明信息:
[u]复制代码[/u] 代码如下:
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包中的内容。   [b]然后我们调用下面的代码: [/b]
[u]复制代码[/u] 代码如下:
printClassTypeInfo("sample.reflection.MyHelloWorld");
  [b]输出结果如下: [/b]
[u]复制代码[/u] 代码如下:
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
  [b]实例化对象 [/b]  我们可以使用class.netInstance的方式来创建一个对象,代码如下:
[u]复制代码[/u] 代码如下:
private static void createInstanceTest() throws ClassNotFoundException, InstantiationException, IllegalAccessException  {      Class classType = Class.forName("sample.reflection.MyHelloWorld");      MyHelloWorld hello = (MyHelloWorld)classType.newInstance();      hello.sayHello("Zhang San");  }
  输出结果:
[u]复制代码[/u] 代码如下:
Hello Zhang San.
  [b]调用对象的方法 [/b]  我们可以通过方法的名称以及参数类型构建一个Method实例,然后调用Method的invoke方法,来触发方法。   示例代码如下:
[u]复制代码[/u] 代码如下:
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"});  }
  输出结果同上。   [b]修改字段的值 [/b]  和C#不同,Java中一般使用setxxx和getxxx显示为属性赋值,因此Java中并没有Property类型,而是有Field类型。   [b]我们可以对Field的值进行修改,代码如下: [/b]
[u]复制代码[/u] 代码如下:
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);  }
  执行结果如下:
[u]复制代码[/u] 代码如下:
name is null name is Zhang San
  可以看出,我们成功的修改了name的值。   [b]Annotation探索 [/b]  一开始我们提到,反射是很多技术的基础,Annotation就是这样的,我们可以把Annotation看做是C#中的Attribute,它可以对类型、方法、属性、字段、方法参数等信息进行修饰。我们可以使用“@+Annotation名”的方式来使用Annotation。   [b]Annotation基本操作 [/b]  来看下面的代码,我们定义了基于Type、Method、Parameter和Field上面的Annotation示例:
[u]复制代码[/u] 代码如下:
@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:
[u]复制代码[/u] 代码如下:
@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:
[u]复制代码[/u] 代码如下:
[b]读取Annotation方式一 [/b] 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());          }      }  }
[u]复制代码[/u] 代码如下:
[b]读取Annotation方式二 [/b] 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());          }      }  }
  上述两个方法的输出都是一样的,如下:
[u]复制代码[/u] 代码如下:
@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)
  [b]在WebService中使用Annotation [/b]  上述代码看上去可能有些枯燥,不能显示出Annotation的威力,那么我们接下来看WebService,在WebService中,我们可以使用WebMethod、WebParam等Annotation来声明方法或者参数。   接下来,我们来实现一个非常简单的Web服务:
[u]复制代码[/u] 代码如下:
@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:
[u]复制代码[/u] 代码如下:
class HelloServicePublisher implements Runnable  {      public void run()      {          Endpoint.publish("http://localhost:8888/test/HelloService", new HelloServiceProvider());      }  }
  在命令行中,我们定位到源代码路径,执行下面的命令:
[u]复制代码[/u] 代码如下:
wsgen -cp . HelloServiceProvider
  wsgen位于JDK的bin目录中。   然后我们启动HelloServiceProvider,在浏览器中输入如下地址:http://localhost:8888/test/HelloService,可以看到如下信息: [img]http://files.jb51.net/file_images/article/201305/20130515154234.png[/img]   点击WSDL链接,可以看到:
[u]复制代码[/u] 代码如下:
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服务器,我们不需要把上述代码部署到其他服务器中。   [b]动态代理机制 [/b]  Spring中一大特色是AOP,面向方面编程也是框架设计一个趋势。对于业务中的共通操作,诸如记录日志、维护事务等,如果和业务逻辑纠缠在一起,会造成代码职责不清,后续维护困难等问题。利用AOP,我们可以很好的分离共通操作和业务操作。   下面我们来实现一个简单的AOP框架,要实现这样一个框架,需要3部分:1)InvocationHandler,来触发方法;2)Interceptor,来定义拦截器;3)DynamicProxy,来动态创建代理对象。   [b]首先我们看Interptor的定义: [/b]
[u]复制代码[/u] 代码如下:
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);  }
  [b]接下来是InvocationHandler: [/b]
[u]复制代码[/u] 代码如下:
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);          }      }  }
  [b]最后是DynamicProxy: [/b]
[u]复制代码[/u] 代码如下:
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拦截器。下面我们来创建一些测试代码。   [b]首先是实现AOPInterceptor接口: [/b]
[u]复制代码[/u] 代码如下:
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方法最后,追加一行代码:
[u]复制代码[/u] 代码如下:
throw new RuntimeException();
  [b]接着是测试代码: [/b]
[u]复制代码[/u] 代码如下:
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");  }
  [b]最终,执行结果如下: [/b]
[u]复制代码[/u] 代码如下:
方法开始执行 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执行后进行了拦截,达到了我们期望的效果。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部