Reflection helps us to view information of the specified type, create an instance of the type, and call a method of the type. We usually use frameworks, such as Spring, EJB, and Hibernate. reflection technology is widely used.
Simple reflection example
The following describes the basic operations related to reflection.
The first is the basic code. We define an interface and its implementation as the goal of our reflection operation:
Copy codeThe Code is as follows: 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;
}
}
Obtain method and field information
The following code outputs the declaration information of methods and fields of the given type:Copy codeThe Code is as follows: 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 ());
}
}
When using reflection, we generally use the content in the java. lang. reflect package.
Then we call the following code:
Copy codeThe Code is as follows: printClassTypeInfo ("sample. reflection. MyHelloWorld ");
The output result is as follows:
Copy codeThe Code is as follows: 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
Instantiate object
We can use class. netInstance to create an object. The Code is as follows:Copy codeThe Code is as follows: private static void createInstanceTest () throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
Class classType = Class. forName ("sample. reflection. MyHelloWorld ");
MyHelloWorld hello = (MyHelloWorld) classType. newInstance ();
Hello. sayHello ("Zhang San ");
}
Output result:Copy codeThe Code is as follows: Hello Zhang San.
Method of calling object
We can create a Method instance by using the Method name and parameter type, and then call the Method's invoke Method to trigger the Method.
The sample code is as follows:
Copy codeThe Code is as follows: 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 "});
}
The output result is the same as the preceding one.
Modify Field Value
Unlike C #, setxxx and getxxx are usually used in Java to assign values to properties. Therefore, there is no Property type in Java, but Field type.
We can modify the Field value. The Code is as follows:
Copy codeThe Code is as follows: 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 );
}
The execution result is as follows:Copy codeThe Code is as follows: name is null
Name is Zhang San
We can see that we have successfully modified the name value.
Annotation Exploration
As we mentioned at the beginning, reflection is the basis of many technologies, and Annotation is like this. We can regard Annotation as the Attribute in C, it can modify information such as type, method, attribute, field, and method parameter. We can use the "@ + Annotation name" method to use Annotation.
Annotation basic operations
The following code defines the Annotation example based on Type, Method, Parameter, and Field:
Copy codeThe Code is as follows: @ Target (ElementType. TYPE)
@ Retention (RetentionPolicy. RUNTIME)
@ Brief ented
@ Interface ClassAnnotation
{
Public String value ();
}
@ Target (ElementType. METHOD)
@ Retention (RetentionPolicy. RUNTIME)
@ Brief ented
@ Interface MethodAnnotation
{
Public String methodName ();
Public String returnType ();
}
@ Target (ElementType. PARAMETER)
@ Retention (RetentionPolicy. RUNTIME)
@ Brief ented
@ Interface ParameterAnnotation
{
Public String value ();
}
@ Target (ElementType. FIELD)
@ Retention (RetentionPolicy. RUNTIME)
@ Brief ented
@ Interface FieldAnnotation
{
Public String value ();
}
Next, we define a MyClass type and use the above Annotation:Copy codeThe Code is as follows: @ ClassAnnotation ("this is the Annotation applied to the type ")
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 ("this is the Annotation applied to the parameter") String error)
{
System. err. println (error );
}
@ FieldAnnotation ("this is the Annotation applied to the field ")
Public int count;
}
If Annotation is used, we can obtain the information in it. The following two methods can be used to obtain Annotation. The first method is to read Annotation information one by reflecting the traversal type, methods, and fields; the second method is to read the Annotation of the specified type:Copy codeThe Code is as follows:Method 1 for reading 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 ());
}
}
}
Copy codeThe Code is as follows:Method 2 for reading 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 ());
}
}
}
The outputs of the above two methods are the same, as shown below:Copy codeThe Code is as follows: @ sample. reflection. annotation. ClassAnnotation (value = This is the Annotation applied to the type)
@ Sample. reflection. annotation. MethodAnnotation (methodName = printInfo, returnType = void)
@ Sample. reflection. annotation. MethodAnnotation (methodName = printError, returnType = void)
@ Sample. reflection. annotation. ParameterAnnotation (value = This is the Annotation applied to the parameter)
@ Sample. reflection. annotation. FieldAnnotation (value = This is the Annotation applied to the field)
Use Annotation in WebService
The above code may seem boring and cannot display the power of Annotation. Let's look at WebService. In WebService, we can use Annotation such as WebMethod and WebParam to declare methods or parameters.
Next, we will implement a very simple Web Service:
Copy codeThe Code is as follows: @ 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 ();
}
}
Then define a Publisher:Copy codeThe Code is as follows: class HelloServicePublisher implements Runnable
{
Public void run ()
{
Endpoint. publish ("http: // localhost: 8888/test/HelloService", new HelloServiceProvider ());
}
}
In the command line, locate the source code path and execute the following command:Copy codeThe Code is as follows: wsgen-cp. HelloServiceProvider
Wsgen is located in the bin directory of JDK.
Start HelloServiceProvider and enter the following address in the browser: http: // localhost: 8888/test/HelloService. The following information is displayed:
Click the WSDL link and you will see:
Copy codeThe Code is as follows: WSDL Information
<! -- 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 has its own Web server. We do not need to deploy the above Code to other servers.
Dynamic proxy mechanism
One major feature of Spring is AOP, and Aspect-Oriented Programming is also a trend in framework design. For common operations in the business, such as logging and maintaining transactions, if they are entangled with the business logic, it may cause problems such as unclear code responsibilities and difficulties in subsequent maintenance. With AOP, We can well separate common operations from business operations.
Next we will implement a simple AOP framework. To implement such a framework, we need three parts: 1) InvocationHandler to trigger the method; 2) Interceptor to define the Interceptor; 3) DynamicProxy, to dynamically create proxy objects.
First, let's look at the definition of Interptor:
Copy codeThe Code is as follows: 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 );
}
Next is InvocationHandler:
Copy codeThe Code is as follows: class DynamicProxyInvocationHandler implements InvocationHandler
{
Private Object target;
Private AOPInterceptor interceptor;
Public DynamicProxyInvocationHandler (Object target, AOPInterceptor interceptor)
{
This.tar get = 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 );
}
}
}
Finally, DynamicProxy:
Copy codeThe Code is as follows: 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 );
}
}
So far, we have built a "simple" AOP interceptor. Next we will create some test code.
First, implement the AOPInterceptor interface:
Copy codeThe Code is as follows: class MyInterceptor implements AOPInterceptor
{
Public void after (Method method, Object [] args ){
System. out. println ("method execution ends. ");
}
Public void afterFinally (Method method, Object [] args ){
System. out. println ("method body Finally execution ends. ");
}
Public void afterThrowing (Method method, Object [] args ){
The System. out. println ("method throws an exception. ");
}
Public void before (Method method, Object [] args ){
System. out. println ("method execution started ");
}
}
Then, use the HelloWorldService defined at the beginning of this article to complete the test. At the end of the sayHello method of MyHello, append a line of code:Copy codeThe Code is as follows: throw new RuntimeException ();
The following is the test code:
Copy codeThe Code is as follows: 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 ");
}
Finally, the execution result is as follows:
Copy codeThe Code is as follows:
Hello Zhang San.
Method throw an exception.
The method is Finally executed.
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
We can see that we have intercepted the execution before, after the exception is thrown, and after finally execution, which has achieved the expected results.