程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 基於Java回想之反射的應用剖析

基於Java回想之反射的應用剖析

編輯:關於JAVA

基於Java回想之反射的應用剖析。本站提示廣大學習愛好者:(基於Java回想之反射的應用剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是基於Java回想之反射的應用剖析正文


反射可以贊助我們檢查指定類型中的信息、創立類型的實例,挪用類型的辦法。我們日常平凡應用框架,例如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:

讀取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());
         }
     }
 }


讀取Annotation方法二
 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,可以看到以下信息:

  點擊WSDL鏈接,可以看到:

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" /><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履行落後行了攔阻,到達了我們希冀的後果。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved