[JUnit unit test, reflection, annotation, dynamic agent]
Learning objectives
- Be able to use Junit for unit testing
- The Class bytecode object can be obtained through reflection technology
- It can obtain the construction method object through reflection technology and create the object.
- You can get the member method object through reflection and call the method.
- The attribute object can be obtained through reflection, and the attribute of the object can be assigned and valued.
- Be able to say the role of annotations
- Ability to customize and use annotations
- Be able to say common meta annotations and their functions
- Be able to parse the annotation and obtain the data in the annotation
- MyTest cases that can complete annotation
- Be able to say the role of dynamic proxy mode
- The Proxy object can be generated using the Proxy method
- Can use four methods of reference
- Base64 can be used to encode and decode basic data, URL and MIME types
Chapter I Junit unit test
Junit What is it? * Junit yes Java Third party unit testing framework written in(Tool class) * Class library ==> class junit.jar Unit test concept * Unit: in Java In, a class is a unit * Unit test: a small piece of code written by a program to test the function or business logic of a method in a class. Junit Role of unit test framework * It is used to purposefully test the function of methods in classes to ensure the correctness and stability of programs. * Enables methods to run independently. Junit Usage steps of unit test framework * Write a business class and write business methods in the business class. For example, the method of adding, deleting, modifying and querying * Write test classes, write test methods in test classes, and write test code in test methods to test. * Naming conventions for test classes: Based on Test Start with the business class name and end with the hump naming method * Each word is capitalized, which is called the big hump naming method, such as class name and interface name... * Starting with the first letter of the second word, it is called the small hump naming method, such as naming method * For example, business class name: ProductDao,Then the test class name should be: TestProductDao * Naming rules for test methods: test Start with business method name and end with business method name * For example, the business method name is: save,Then the test method name should be: testSave Test method precautions * Must be public Decorated, no return value, no parameters * Annotation must be enabled@Test modification How to run a test method * Selected method name --> Right click --> Run 'Test method name' Run the selected test method * Select the test class class name --> Right click --> Run 'Test class name' Run all test methods in the test class * Select the module name --> Right click --> Run 'All Tests' Run all test methods of all test classes in the module How to view test results * Green: indicates that the test has passed * Red: indicates that the test failed and there is a problem Junit Common notes(Junit4.xxxx edition) * @Before: Used to decorate a method that is executed once before each test method is executed. * @After: Used to decorate a method that is executed once after each test method is executed. * @BeforeClass: Used to statically decorate a method that is executed once before all test methods. * @AfterClass: Used to statically decorate a method that executes once after all test methods. Junit Common notes(Junit5.xxxx edition) * @BeforeEach: Used to decorate a method that is executed once before each test method is executed. * @AfterEach: Used to decorate a method that is executed once after each test method is executed. * @BeforeAll: Used to statically decorate a method that is executed once before all test methods. * @AfterAll: Used to statically decorate a method that executes once after all test methods.
- Sample code
/** Business class: implement addition, subtraction, multiplication and division */ public class Cacluate { /* Business method 1: sum a and b */ public int sum(int a,int b){ return a + b + 10; } /* Business method 2: find the difference between a and b */ public int sub(int a,int b){ return a - b; } } public class TestCacluate { static Cacluate c = null; @BeforeClass // Used to statically decorate a method that is executed once before all test methods. public static void init(){ System.out.println("Initialization operation"); // Create a caculate object c = new Cacluate(); } @AfterClass // Used to statically decorate a method that executes once after all test methods. public static void close(){ System.out.println("Release resources"); c = null; } /* @Before // Used to decorate a method that is executed once before each test method is executed. public void init(){ System.out.println("Initialization operation ""); // Create a caculate object c = new Cacluate(); } @After // Used to decorate a method that is executed once after each test method is executed. public void close(){ System.out.println("Free resource ""); c = null; }*/ @Test public void testSum(){ int result = c.sum(1,1); /* Assertion: preview and judge that a condition must be true. If the condition is not true, it will run away directly. assertEquals Method parameters (String message, double expected, double actual) message: Message string expected: expected value actual: actual value */ // If the expected value is consistent with the actual value, nothing will happen, otherwise it will collapse directly. Assert.assertEquals("The expected value is inconsistent with the actual value",12,result); System.out.println(result); } @Test public void testSub(){ // Create a caculate object // Cacluate c = new Cacluate(); int result = c.sub(1,1); // If the expected value is consistent with the actual value, nothing will happen, otherwise it will collapse directly. Assert.assertEquals("The expected value is inconsistent with the actual value",0,result); System.out.println(result); } }
Chapter II reflection
2.1 overview of reflection
2.1.1 introduction of reflection
- Question: how do objects in the IDEA know which properties and methods a class has?
The object class is dissected by reflection technology, and all members of the class are obtained.
2.1.2 concept of reflection
Reflection is a mechanism that can be used to dissect classes and manipulate all members of classes during program operation(Member variable, member method, construction method)
2.1.3 prerequisites for using reflection operation class members
To obtain this type of bytecode file object, you Class object
2.1.4 application of reflection in practical development
* development IDE(Integrated development environment),such as IDEA,Eclipse * Design and learning of various frameworks, such as Spring,Hibernate,Struct,Mybaits....
2.2 obtaining method of class object
2.2.1 three acquisition methods
* Mode 1: By class name.class get * Method 2: by object name.getClass()Method obtain * Mode 3: Pass Class Class to obtain: static Class forName("Class full name") * Of each class Class There is only one object.
- Sample code
public class ReflectDemo01 { public static void main(String[] args) throws ClassNotFoundException { // Get the Class object corresponding to the Student Class Class c1 = Student.class; // Create student object Student stu = new Student(); // Through the getClass method Class c2 = stu.getClass(); System.out.println(c1 == c2); // Obtain: static Class forName("Class full name") through the static method of Class Class c3 = Class.forName("com.itheima._03 reflex.Student"); System.out.println(c1 == c3); System.out.println(c2 == c3); } }
2.2.2 common methods of class
String getSimpleName(); Get class name string: class name String getName(); Get full class name: package name+Class name T newInstance() ; establish Class Object associated with the object of the class
- Sample code
public class ReflectDemo02 { public static void main(String[] args) throws Exception { // Get Class object Class c = Student.class; // Get class name string: class name System.out.println(c.getSimpleName()); // Get full class name: package name + class name System.out.println(c.getName()); // create object Student stu = (Student) c.newInstance(); System.out.println(stu); } }
2.3 operation and construction method of reflection
2.3.1 overview of constructor
Purpose of reflection operation construction method * get Constructor Object to create the object of the class. Constructor Class overview * Every constructor in a class is a Constructor Object of class
2.3.2 Constructor related methods in class
1. Constructor getConstructor(Class... parameterTypes) * Get the corresponding value according to the parameter type Constructor Object. * Only get public Construction method of modification 2. Constructor getDeclaredConstructor(Class... parameterTypes) * Get the corresponding value according to the parameter type Constructor Objects, including private 3. Constructor[] getConstructors() Get all constructor objects in the class, only public of 4. Constructor[] getDeclaredConstructors() Get all constructor objects in the class, including private Embellished
2.3.3 common methods of constructor object
1. T newInstance(Object... initargs) Creates an object based on the specified parameters 2. void setAccessible(true) Set whether to cancel permission check, true Cancel permission check, false Indicates no cancellation(Violent reflex)
2.3.4 example code
public class ReflectDemo03 { /* Constructor[] getConstructors() Get all constructor objects in the class, only public Constructor[] getDeclaredConstructors() Get all constructor objects in the class, including private decorated objects */ @Test public void test03() throws Exception { // Get Class object Class c = Student.class; // Get all constructor objects in the class, only public // Constructor[] cons = c.getConstructors(); Constructor[] cons = c.getDeclaredConstructors(); for (Constructor con:cons) { System.out.println(con); } } /* Constructor getDeclaredConstructor(Class... parameterTypes) Obtain the corresponding Constructor object according to the parameter type */ @Test public void test02() throws Exception { // Get Class object Class c = Student.class; // Get two parameters to construct the method object Constructor con = c.getDeclaredConstructor(String.class,String.class); // Cancel permission check (violent reflection) con.setAccessible(true); // Create objects according to the construction method Object obj = con.newInstance("rose","female"); System.out.println(obj); } /* Constructor getConstructor(Class... parameterTypes) Obtain the corresponding Constructor object according to the parameter type */ @Test public void test01() throws Exception { // Get Class object Class c = Student.class; // Get a parameterless constructor object Constructor con = c.getConstructor(); // Create objects according to the construction method Object obj = con.newInstance(); System.out.println(obj); // Gets the constructor object with parameters Constructor con2 = c.getConstructor(String.class, String.class,int.class); // create object Object obj2 = con2.newInstance("jack", "male",18); System.out.println(obj2); } }
2.4 operation method of reflection
2.4.1 Method class overview
The purpose of the operation member method of reflection * operation Method Object to call member methods Method Class overview * Each member method is a Method Class.
2.4.2 Method related methods in class
* Method getMethod(String name,Class...args); * Get the corresponding construction method object according to the method name and parameter type. Only public of * Method getDeclaredMethod(String name,Class...args); * Obtain the corresponding construction method object according to the method name and parameter type, including private of * Method[] getMethods(); * Get all member method objects in the class and return an array. You can only get public Decorated and containing a parent class * Method[] getDeclaredMethods(); * Get all member method objects in the class and return an array,Only the of this class is obtained, including private Embellished
2.4.3 common methods of method object
* Object invoke(Object obj, Object... args) * Call the specified object obj This method * args: Parameters passed when the method is called * void setAccessible(true) Set whether to cancel permission check, true Cancel permission check, false Indicates no cancellation(Violent reflex)
2.4.4 example code
public class ReflectDemo04 { // Reflection operation static method @Test public void test04() throws Exception { // Get Class object Class c = Student.class; // Get the corresponding member method object according to the method name Method method = c.getDeclaredMethod("eat",String.class); // Execute the corresponding method through method method.invoke(null,"Fried rice with egg"); } /* * Method[] getMethods(); * Get all member method objects in the class and return an array. You can only get those decorated with public and containing the parent class * Method[] getDeclaredMethods(); * Get all the member method objects in the class, return the array, and only get the of this class, including the private modifier */ @Test public void test03() throws Exception { // Get Class object Class c = Student.class; // Get all member method objects in the class and return an array. You can only get those decorated with public and containing the parent class // Method[] methods = c.getMethods(); // Get all the member method objects in the class, return the array, and only get the of this class, including the private modifier Method[] methods = c.getDeclaredMethods(); for (Method m: methods) { System.out.println(m); } } /* Method getDeclaredMethod(String name,Class...args); * Obtain the corresponding construction method object according to the method name and parameter type, */ @Test public void test02() throws Exception { // Get Class object Class c = Student.class; // Create student object from Class object Student stu = (Student) c.newInstance(); // Get the Method object corresponding to the sleep Method Method m = c.getDeclaredMethod("sleep"); // Violent reflex m.setAccessible(true); // Execute stuy method through m object m.invoke(stu); } /* Method getMethod(String name,Class...args); * Obtain the corresponding construction method object according to the method name and parameter type, */ @Test public void test01() throws Exception { // Get Class object Class c = Student.class; // Create student object from Class object Student stu = (Student) c.newInstance(); // Get the Method object corresponding to the study Method Method m = c.getMethod("study"); // Execute stuy method through m object m.invoke(stu); ///Get the Method object corresponding to the study Method Method m2 = c.getMethod("study", int.class); // Execute stuy method through m2 object m2.invoke(stu,8); } }
2.5 operation member variables of reflection
2.5.1 overview of field class
The purpose of the reflected operation member variable * adopt Field Object to assign and value the corresponding member variable Field Class overview * Each member variable is a Field Class.
2.5.2 Field related methods in class
* Field getField(String name); * Get the corresponding value according to the member variable name Field Object, you can only get public modification * Field getDeclaredField(String name); * Get the corresponding value according to the member variable name Field Object containing private Embellished * Field[] getFields(); * Get the corresponding values of all member variables Field Object, you can only get public of * Field[] getDeclaredFields(); * Get the corresponding values of all member variables Field Object containing private of
2.5.3 common methods of field object
void set(Object obj, Object value) void setInt(Object obj, int i) void setLong(Object obj, long l) void setBoolean(Object obj, boolean z) void setDouble(Object obj, double d) Object get(Object obj) int getInt(Object obj) long getLong(Object obj) boolean getBoolean(Object ob) double getDouble(Object obj) void setAccessible(true);Violent reflection, set to directly access the properties of private types. Class getType(); Gets the type of the property and returns Class Object.
setXxx methods are used to set the properties of object obj, and select different methods for different types.
The getXxx method is to obtain the attribute value corresponding to the object obj, and select different methods for different types.
2.5.4 example code
public class ReflectDemo05 { /* Field[] getFields(); * Get the Field objects corresponding to all member variables, only public Field[] getDeclaredFields(); * Get the Field objects corresponding to all member variables, including private */ @Test public void test02() throws Exception { // Get Class object Class c = Student.class; // Get the Field object corresponding to all member variables // Field[] fields = c.getFields(); // Get the Field objects corresponding to all member variables, including private Field[] fields = c.getDeclaredFields(); for (Field f: fields) { System.out.println(f); } } /* Field getField(String name); Get the corresponding Field object according to the member variable name, and only the public modifier can be obtained Field getDeclaredField(String name); * Obtain the corresponding Field object according to the member variable name, including the Field object decorated with private */ @Test public void test01() throws Exception { // Get Class object Class c = Student.class; // create object Object obj = c.newInstance(); // Get the Field object corresponding to the member variable name Field f = c.getField("name"); // Assign a value to the member variable name // Assign the name attribute of the specified object obj to jack f.set(obj,"jack"); // Gets the value of the obj member variable name of the specified object System.out.println(f.get(obj)); // jack // Gets the name of the member variable System.out.println(f.getName()); // name // Assign a value to the member variable gender // Get the Field object corresponding to the member variable gender Field f1 = c.getDeclaredField("gender"); // Violent reflex f1.setAccessible(true); // Assign male to the gender attribute of the specified object obj f1.set(obj,"male"); System.out.println(obj); } }
Chapter III notes
3.1 overview of notes
3.1.1 concept of annotation
-
The annotation is jdk1 5 new features.
-
Annotation is a kind of tag, which is a part of the class and can carry some additional information to the class.
-
Tags (annotations) can be added to packages, classes, fields, methods, method parameters, and local variables.
-
Annotations are for the compiler or JVM. The compiler or JVM can complete the corresponding functions according to the annotations.
Annotation is equivalent to a mark. Adding an annotation to a program is equivalent to marking the program. Later, javac compilers, development tools and other programs can know whether there are any marks on your classes and various elements through reflection. Depending on what marks your program has, they can do the corresponding things. Marks can be added to packages, classes, attributes and methods, Method and local variables.
3.1.2 role of notes
The function of annotation is to bring parameters into the program.
Annotations are used in the following common operations:
-
Generate help documents: @ author and @ version
-
@Author: used to identify the author's name.
-
@Version: used to identify the version number of an object. Scope of application: file, class and method.
-
Using * * @ author and @ version annotation is to tell Javadoc tool * * to mark the author's name and version number in the document when generating the help document. As shown below:
-
-
-
Compilation check: @ Override
-
@Override: used to modify method declarations.
- It is used to tell the compiler that the method overrides the method in the parent class. If the method does not exist in the parent class, the compilation fails. As shown below
-
-
Configuration of framework (framework = code + configuration)
- Please pay attention to the learning of the content of the framework course.
3.1.3 common notes
- @Author: used to identify the author's name. The default of eclipse development tools is the system user name.
- @Version: used to identify the version number of an object. Scope of application: file, class and method.
- @Override: used to modify the method declaration and tell the compiler that the method overrides the method in the parent class. If the method does not exist in the parent class, the compilation fails.
3.2 user defined annotation
3.2.1 definition format
public @interface Annotation name{ } For example, define a Student Notes for public @interface Student { }
3.2.2 attributes of annotations
-
Format of attribute
- Format 1: data type attribute name ();
- Format 2: data type attribute name (default) default value;
-
Attribute definition example
// full name String name(); // Age int age() default 18; // hobby String[] hobby();
-
The data type to which the attribute applies
* Eight data types(int,short,long,double,byte,char,boolean,float) * String,Class,Annotation type, enumeration class * Array form of the above types
3.3 using custom annotations
3.3.1 definitions and notes
- Define an annotation: Book
- Include attribute: String value() book name
- Include attribute: double price(), the default value is 100
- Include attribute: String[] authors() multiple authors
- code implementation
@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Book { String value(); double price() default 100; String[] authros(); }
3.3.2 use notes
- Defines the class to use the Book annotation on member methods
- Precautions for use
- If the attribute has a default value, the attribute can be used without assignment.
- If the attribute has no default value, it must be assigned a value when using annotations.
3.3.3 special attribute value
/** Special attribute value * If there is only one attribute in the annotation and its name is value, the attribute can be assigned directly when using the annotation without giving the attribute name. * If there are other attributes besides the value attribute in the annotation, and as long as one attribute has no default value, when assigning a value to the attribute value The property name cannot be omitted. Summary: if there is only one attribute in the annotation, the attribute name is generally named value */ @interface TestA{ String[] value(); int age() default 100; String name(); } @interface TestB{ String name(); } @TestB(name = "zzz") @TestA(name = "yyy",value = {"xxx","xxx"}) public class AnnotationDemo02 { }
3.4 meta annotation of annotation
Meta annotation overview * Java Official notes * The annotation used to define the annotation * Any official definition of non meta annotations uses meta annotations. Common meta annotations * @Target * Function: used to identify the location where the annotation is used. If the annotation is not used, the customized annotation can be used in any location. * Available values are defined in ElementType In the enumeration class, common values are as follows TYPE,Class, interface FIELD, Member variable METHOD, Member method PARAMETER, Method parameters CONSTRUCTOR, Construction method LOCAL_VARIABLE, local variable * @Retention * Function: used to identify the lifecycle of annotations(Effective range) * Available values are defined in RetentionPolicy In the enumeration class, common values are as follows * SOURCE: Annotations only work in the source code stage, and do not exist in the generated bytecode file * CLASS: Annotations are used in the source code stage, bytecode file stage and run stage. The default value does not exist * RUNTIME: Annotations are used in the source code stage, bytecode file stage and run stage
3.5 annotation analysis
What is annotation parsing * use Java The process of obtaining data on annotations is called annotation parsing. Interface related to annotation parsing * Annotation: Annotation class, which is the parent class of all annotations. * AnnotatedElement:This interface defines methods related to annotation parsing T getAnnotation(Class<T> annotationClass) Obtain the corresponding annotation object according to the annotation type Annotation[] getAnnotations() * Get all annotations used on the current object, and return the annotation array, including those inherited by the parent class Annotation[] getDeclaredAnnotations() * Get all annotations used on the current object and return the annotation array,Contains only of this class boolean isAnnotationPresent(Class<Annotation> annotationClass) * Judge whether the current object uses the specified annotation. If so, return true,otherwise false Principle of obtaining annotation data * The object corresponding to the member on which the annotation works will be used to obtain the annotation * For example, to annotate a member method, you need to obtain the corresponding member method Method object * For example, if annotations are applied to a class, the class's Class object * For example, if an annotation acts on a member variable, you need to obtain the corresponding value of the member variable Field Object. * Field,Method,Constructor,Class And other classes are implemented AnnotatedElement Interface
3.5.4.1 requirements description
- Define the annotation Book as follows:
- Include attribute: String value() book name
- Include attribute: double price(), the default value is 100
- Include attribute: String[] authors() multiple authors
- Restrict where annotations are used: on classes and member methods
- Specifies the valid range of the annotation: RUNTIME
- Define the BookStore class and use the Book annotation on the class and member methods
- Define the TestAnnotation test class to get the data on the Book annotation
3.5.4.2 code implementation
- Annotation Book
@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Book { String value(); double price() default 100; String[] authros(); }
- BookShelf class
@Book(value = "The Dream of Red Mansion",authros = {"Cao Xueqin"}) public class BookShelf { @Book(value = "Journey to the West",authros = {"Wu Chengen","Bethune"},price = 200) public void showBook(){ } }
- TestAnnotation class
/** What is annotation parsing * The process of obtaining data on annotations using Java technology is called annotation parsing. Interface related to annotation parsing * Annotation: Annotation class, which is the parent class of all annotations. * AnnotatedElement:This interface defines methods related to annotation parsing T getAnnotation(Class<T> annotationClass) Obtain the corresponding annotation object according to the annotation type Annotation[] getAnnotations() * Get all annotations used on the current object, and return the annotation array, including those inherited by the parent class Annotation[] getDeclaredAnnotations() * Get all annotations used on the current object and return the annotation array, which contains only the annotations of this class boolean isAnnotationPresent(Class<Annotation> annotationClass) * Judge whether the current object uses the specified annotation. If so, return true; otherwise, false Principle of obtaining annotation data * The object corresponding to the member on which the annotation works will be used to obtain the annotation * For example, to annotate a member Method, you need to obtain the Method object corresponding to the member Method * For example, if annotations are applied to a Class, the Class object of the Class should be * For example, if an annotation acts on a member variable, you need to obtain the Field object corresponding to the member variable. * Field,Method,Constructor,Class And other classes implement the AnnotatedElement interface */ public class AnnotationDemo04 { /* Gets the annotation data used on the class */ @Test public void test02() throws Exception { // Get Class object Class c = BookShelf.class; // Determine whether the Book annotation is used on the class if(c.isAnnotationPresent(Book.class)){ // Obtain the corresponding annotation object according to the annotated Class object Book annotation = (Book) c.getAnnotation(Book.class); // Get book title System.out.println(annotation.value()); // Get author System.out.println(Arrays.toString(annotation.authros())); // Get price System.out.println(annotation.price()); } // Get all annotations used on the current object and return the annotation array // Annotation[] annotations = c.getAnnotations(); Annotation[] annotations = c.getDeclaredAnnotations(); System.out.println(Arrays.toString(annotations)); } /* Get annotated data on member methods */ @Test public void test01() throws Exception { // Get Class object Class c = BookShelf.class; // Get the Method object corresponding to the member Method Method m = c.getMethod("showBook"); // Obtain the corresponding annotation object according to the annotated Class object Book annotation = m.getAnnotation(Book.class); // Get book title System.out.println(annotation.value()); // Get author System.out.println(Arrays.toString(annotation.authros())); // Get price System.out.println(annotation.price()); } }
3.6 annotated cases
3.6.1 case description
- @ Test simulating Junit Test
3.6.2 case analysis
- To simulate the annotation @ Test of Junit Test, first write the custom annotation @ MyTest and add meta annotation to ensure that the custom annotation can only modify methods and can be obtained at run time.
- Then write the target class (test class), and then use @ MyTest annotation for the target method (test method). Write three methods, two of which are annotated with @ MyTest annotation.
- Finally, write the calling class and use the main method to call the target class to simulate the operation of Junit. As long as there is @ MyTest annotation, the method will run.
3.6.3 case code
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyTest { } public class TestMyTest { @MyTest public void tests01(){ System.out.println("test01"); } public void tests02(){ System.out.println("test02"); } @MyTest public void tests03(){ System.out.println("test03"); } } /** * @author pkxing * @version 1.0 * @Package com.itheima * @date 2018/6/23 9:10 pm */ public class AnnotationDemo05 { public static void main(String[] args) throws Exception { // Get Class object Class c = TestMyTest.class; Object obj = c.newInstance(); // Get all member methods Method[] methods = c.getMethods(); for(Method m:methods){ // Determine whether the m method uses the MyTest annotation if(m.isAnnotationPresent(MyTest.class)){ // Call method m.invoke(obj); } } } }
Chapter IV dynamic agent (important thought)
4.1 Proxy Pattern
Why is there an "agent"? There are many examples in life, such as entrusted business, etc. the agent is that the agent is unable or unwilling to complete something, and needs to find someone to complete it instead of himself. This is the reason for the existence of "agent". For example, I need to go abroad now, but I don't want to apply for a visa, book air tickets and hotels by myself (if I feel troublesome, I can find a travel agency to help me. At this time, the travel agency is the agent, and I am the agent myself.
4.2 overview of dynamic agent
Dynamic proxy is simply to intercept direct access to real object methods and enhance the functions of real object methods
In detail, dynamic proxy is: the proxy object created by the proxy class when the program runs is called dynamic proxy, that is, in this case, the proxy class is not defined in Java code, but dynamically generated at run time according to our "instructions" in Java code. In other words, if you want to obtain the proxy of which object, the dynamic proxy will dynamically generate the proxy object of this object for you. Dynamic proxy can enhance the methods of the proxy object, enhance the functions of the proxy object methods without modifying the method source code, and do whatever you want before and after the method is executed. Dynamic proxy technology is mostly used in the framework. For example, some mainstream framework technologies such as struts 1, struts 2, Spring and Hibernate all use dynamic proxy technology.
4.3 case introduction
Now, suppose we want to realize such a requirement: in the large-scale system of the enterprise, the execution of each business layer method needs to have corresponding log records, such as when the method was called and how long it took. According to these log information, we can see the system execution, especially when the system has errors, These log information is particularly important. Now there is an implementation idea. The implementation class code of the business layer is as follows:
public interface SchoolService{ String login(String loginName, String passWord); String getAllClazzs(); } public class SchoolServiceImpl implements SchoolService { @Override public String login(String loginName, String passWord) { // The point in time at which method execution begins long startTimer = System.currentTimeMillis(); try { Thread.sleep(500); if("admin".equals(loginName) && "123456".equals(passWord)){ return "success"; } } catch (Exception e) { throw new RuntimeException("Login exception"); } long endTimer = System.currentTimeMillis(); // When and how long did it take SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("login Method execution->"+sdf.format(endTimer)+",Time consuming:"+(endTimer - startTimer)); return "The login name or password is incorrect"; } @Override public String getAllClazzs() { // point of time long startTimer = System.currentTimeMillis(); try { Thread.sleep(1000); return "Returned to all classes(1 Class, class 2, class 3)"; } catch (Exception e) { throw new RuntimeException("Query class exception"); }finally{ long endTimer = System.currentTimeMillis(); // When and how long did it take SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("getAllClazzs Method execution->"+sdf.format(endTimer)+",Time consuming:"+(endTimer - startTimer)); } } }
.
We record the start time and end time every time the methods in the business layer are executed. In this way, although we can record the deadline and time-consuming of each method, the code is very bloated. These journaling codes themselves are code that has nothing to do with business functions.
4.4 optimizing code using dynamic agents
So is there a way to solve this problem?
Dynamic proxy is a very good implementation means to solve such problems. Through dynamic proxy, we can provide a dynamic proxy object for the class object implemented by the business layer. The proxy object can proxy all the methods of the implementation class, and enhance the method function of the proxy. In other words, as long as the method of the class object implemented by the proxy is called, the execution of the method will first enter the proxy object. The proxy object can record the start time before the method is executed, and then trigger the execution of the method. After the method is executed, the proxy object will record the end time, and then calculate the time difference as a log record, Because the logging of the method is completed by the agent, the method of the proxy object does not need to log its own operations. This produces a very good design model.
Now let's write a logging agent class using dynamic agent:
The code is as follows:
public class LogProxy { // Provides a method for producing proxy objects that need to be proxied. public static Object getProxy(Object obj) { return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // Record the start time first long startTimer = System.currentTimeMillis(); try { // Actually trigger the execution of the method in the proxy object return method.invoke(obj, args); } catch (Exception e) { throw new RuntimeException(e); } finally { long endTimer = System.currentTimeMillis(); // When and how long did it take SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); System.out.println(method.getName() + "Method execution->" + sdf.format(endTimer) + ",Time consuming:" + (endTimer - startTimer)); } } }); } }
4.5 key categories and methods
In the above code, the getProxy method is a proxy object used to obtain an implementation class object. In this code, if you want to understand the mechanism of Java Dynamic Proxy, you first need to understand the following related classes or interfaces:
java.lang.reflect.Proxy: This is the main class of Java dynamic proxy mechanism. It provides a static method to dynamically generate proxy classes and their objects for a set of interface implementation classes.
Details of the three parameters of the newProxyInstance method:
This method is used to generate a dynamic proxy class instance for the specified class loader, a set of interfaces and the calling processor
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 1,obj.getClass().getClassLoader()Target object pass getClass Method gets all the information of the class and calls getClassLoader() Method to get the class loader. After obtaining the class loader, you can use this type of loader to load the generated proxy class into the JVM Namely Java In the virtual machine so that the runtime needs it! 2,obj.getClass().getInterfaces()Obtain all interface information of the proxy class so that the generated proxy class can have all methods in the proxy class interface. 3,InvocationHandler This is the calling processor interface, which customizes a invoke Method is used to centrally process method calls on dynamic proxy class objects. It is usually used to process and access delegate class methods.
Parameters of the invoke method
public Object invoke(Object proxy, Method method, Object[] args) 1,Object proxy The generated proxy object is not specifically understood here, but I think it has been generated in memory proxy Object. 2,Method method: An abstraction of the method represented in the represented object. 3,Object[] args: Parameters in the proxied method. Here, because the number of parameters is uncertain, it is represented by an object array.
After the proxy class definition is completed, the business layer implementation class method does not need to declare the journaling code itself, because the proxy object will help to make journaling. The modified implementation class code is as follows:
public class SchoolServiceImpl implements SchoolService { @Override public String login(String loginName, String passWord) { try { Thread.sleep(500); if("admin".equals(loginName) && "123456".equals(passWord)){ return "success"; } } catch (Exception e) { throw new RuntimeException("Login exception"); } return "The login name or password is incorrect"; } @Override public String getAllClazzs() { try { Thread.sleep(1000); return "Returned to all classes(1 Class, class 2, class 3)"; } catch (Exception e) { throw new RuntimeException("Query class exception"); } } }
Start using dynamic proxy to access methods:
public class TestMain { public static void main(String[] args) { // Get the proxy object of the business layer implementation class object, and the business layer implementation class object will be proxy SchoolService schoolService = (SchoolService) LogProxy.getProxy(new SchoolServiceImpl()); System.out.println(schoolService.login("admin", "1234256")); System.out.println(schoolService.getAllClazzs()); } }
In this code, the business layer object is already represented by the agent. After calling the method of the business layer object, the call of the method will be handled by the proxy object first. The agent will record the start time of the execution of the method first, then pass the method.. Invoke (obj, args) to actually trigger the execution of the method, and then the proxy object records the method end time and outputs the log. In this way, the whole process is perfectly realized through the agent.
4.6 summary
Dynamic proxy is very flexible and can be used as proxy for any interface implementation class object
The dynamic agent can act as a proxy for all methods of all interfaces of the proxy object. The dynamic agent can enhance the function of the method without changing the method source code,
The bytecode of dynamic proxy class is dynamically generated by Java reflection mechanism when the program is running, and there is no need for programmers to write its source code manually.
Dynamic proxy class not only simplifies programming, but also improves the scalability of software system, because Java reflection mechanism can generate any type of dynamic proxy class.
Dynamic agent also improves the development efficiency.
Disadvantages: only the implementation class of the interface can be used as a proxy object, and ordinary classes cannot be used as proxy objects.