1. Junit testing tool
@Test defines test method
1. Methods marked with @BeforeClass are executed before all methods
2. Methods marked with @AfterCalss are executed after all methods
3. Methods marked with @Before are executed before each @Test method
4. Methods marked with @After are executed after each @Test method
public class StringUtilTest{ @Before public void test1(){ System.out.println("--> test1 Before was executed"); } @BeforeClass public static void test11(){ System.out.println("--> test11 BeforeClass executed"); } @After public void test2(){ System.out.println("--> test2 After was executed"); } @AfterCalss public static void test22(){ System.out.println("--> test22 AfterCalss was executed"); } }
2. Reflection
Definition: Reflection technology refers to loading the bytecode of a class into memory, and using programming methods to analyze the various components of the class (member variables, methods, constructors, etc.)
2.1. Obtain class object (bytecode object)
Since the design principle of Java is that everything is an object, the obtained class is actually embodied in the form of an object, which is called a bytecode object and is represented by the Class class. After obtaining the bytecode object, you can obtain the components of the class through the bytecode object. These components are actually objects, in which each member variable is represented by an object of the Field class , Each member method is represented by an object of the Method class, and Each constructor is represented by an object of the Constructor class.
Three ways to obtain Class objects
- Class c1=class name.class
- Call the method provided by Class: public static Class forName(String package);
- Methods provided by Object: public Class getClass();Class c3=object getClass();
2.2 Get the constructor of the class
Class provides methods to obtain constructors from classes method Constructor<?>[] getConstructors() gets all constructors (only public modified ones can be obtained) Constructor<?>[] getDeclaredConstructors() Get all constructors (you can get them as long as they exist) Constructor<T> getConstructor(Class<?>... parameterTypes) Get a certain constructor (only public modified ones can be obtained) Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) Get a certain constructor (you can get it as long as it exists) get: get Declared: With this word, you can get any one. Without this word, you can only get one public modified one. Constructor: The meaning of constructor method Suffix s: means you can get multiple ones, without suffix you can only get one
2.3 Obtain the function of the constructor
Get the function of the class constructor: still initialize the object and return it Methods provided by Constructor T newInstance(Object... initargs) (can be any number of parameters) calls the constructor represented by this constructor object, passes in the parameters, completes the initialization of the object and returns public void setAccessible(boolean flag) is set to true, which means that checking access control (violent reflection) is prohibited
2.4 Reflection to obtain member variables & use
Class provides methods to obtain member variables from the class method public Field[] getFields() Gets all member variables of the class (only public modified ones can be obtained) public Field[] getDeclaredFields() Gets all member variables of the class (you can get them as long as they exist) public Field getField(String name) Gets a member variable of the class (only public modified ones can be obtained) public Field getDeclaredField(String name) Gets a member variable of the class (you can get it as long as it exists)
Get the function of member variables: they are still assignment and value acquisition. method void set(Object obj, object value): Assignment (need to pass in the object, otherwise you will not know which object to assign value to) object get(Object obj) value public void setAccessible(boolean flag) is set to true, which means that checking access control is prohibited (violent reflection)
2.5 Obtaining and values of member methods
Get the member methods of the class Class provides an API to obtain member methods from the class. method Method[] getMethods() gets all member methods of the class (only public modified ones can be obtained) Method[] getDeclaredMethods() Gets all member methods of the class (you can get them as long as they exist) Method getMethod(String name, Class<?>... parameterTypes) Gets a member method of the class (only public modified ones can be obtained) Method getDeclaredMethod(String name, Class<?>.. parameterTypes) Gets a member method of the class (you can get it as long as it exists) The role of member methods: still executes Method provided by Method public Object invoke(Object obj, Object... args) triggers the execution of this method on an object. public void setAccessible(boolean flag) is set to true, which means that checking access control (violent reflection) is prohibited
public class Test3Method{
public static void main(String[] args){
//1. The first step of reflection: first obtain the Class object
Class c = Cat.class;
//2. Get all member methods in the class Method[] methods = c.getDecalaredMethods(); //3. Traverse each method object in this array for(Method method : methods){ System.out.println(method.getName() + "-->" + method.getParameterCount() + "-->" + method.getReturnType()); } System.out.println("-----------------------"); //4. Get the private modified run method and get the Method object Method run = c.getDecalaredMethod("run"); //Execute the run method, you need to cancel the permission check before execution Cat cat = new Cat(); run.setAccessible(true); Object rs1 = run.invoke(cat); System.out.println(rs1) //5. Get the private modified eat(String name) method and get the Method object Method eat = c.getDeclaredMethod("eat",String.class); eat.setAccessible(true); Object rs2 = eat.invoke(cat,"鱼儿"); System.out.println(rs2) }
}
Get the results returned by the operation
2.6 The role of reflection
Reflection is used to write the framework, that is, no matter what type of object is input, we can get the corresponding class file to do some unified processing. Let’s write a framework that can write the attribute name and attribute value of any object to a file. It doesn’t matter how many properties the object has, or whether the object’s property names are the same.
1. First write two classes, a Student class and a Teacher class 2. Write an ObjectFrame class to represent the frame Define a saveObject(Object obj) method in the ObjectFrame class to save any object to a file. Parameters: Object obj: represents the object to be stored in the file \t 3. Write the code inside the method and store the object’s attribute name and attribute value in the file. 1) What attributes are there in the parameter obj object, what are the attribute names and what are the implementation values, the object in it knows best. 2) Then obtain the member variable information of the class through reflection (variable name, variable value) 3) Write the variable name and variable value to the file
Write an ObjectFrame to represent the framework you designed. The code is as shown below
public class ObjectFrame{ public static void saveObject(Object obj) throws Exception{ PrintStream ps = new PrintStream(new FileOutputStream("Module name\src\data.txt",true)); //1) What are the attributes in the parameter obj object, what are the attribute names, and what are the implementation values. The objects in the object know best. //2) Then obtain the member variable information of the class through reflection (variable name, variable value) Class c = obj.getClass(); //Get bytecode ps.println("---------" + class.getSimpleName() + "---------"); Field[] fields = c.getDeclaredFields(); //Get all member variables //3) Write the variable name and variable value to the file for(Field field : fields){ String name = field.getName(); Object value = field.get(obj) + ""; ps.println(name); } ps.close(); } }
Use the framework you designed to write the information of the Student object and the information of the Teacher object into the file.
Prepare the Student class and Teacher class first
public class Student{ private String name; private int age; private char sex; private double height; private String hobby; }
public class Teacher{ private String name; private double salary; }
Create a test class. In the test class, create a Student object and a Teacher object. Use the ObjectFrame method to write all the attribute names and attribute values of these two objects to the file.
public class Test5Frame{ @Test public void save() throws Exception{ Student s1 = new Student("Dark Horse Daniel Wu",45, 'Male', 185.3, "Basketball, Ice Hockey, Reading"); Teacher s2 = new Teacher("博妞",999.9); ObjectFrame.save(s1); ObjectFrame.save(s2); } }
The end result is that different types of information are saved to files
Use of 3 annotations
Annotations are used together with reflection to serve the implementation of the framework. We can understand it as the JUnit annotation, which tells the system that it will be executed after adding this annotation. It is also similar to the meaning of defining beans in spring. You can know which beans are in the system through annotations.
- Java annotations are special marks in the code, such as @Override, @Test, etc., whose function is to allow other programs to decide how to execute the program based on the annotation information.
3.1 Custom annotation format
public @interface MyTest{ String aaa(); boolean bbb() default true; //default true means the default value is true, and you don’t need to assign a value when using it. String[] ccc(); }
Note: If the attribute name of the annotation is value, and only value has no default value, the value name can be omitted when using annotations. For example, now redefine a MyTest2 annotation
public @interface MyTest2{ String value(); //Special attributes } @MyTest2("Sun Wukong") //Equivalent to @MyTest2(value="Sun Wukong")
3.2 What is the essence of annotation
1.MyTest1 annotations are essentially interfaces. Each annotation interface inherits the sub-Annotation interface.
2.The attributes in the MyTest1 annotation are essentially abstract methods
3.@MyTest1 is actually the implementation class object of the MyTest interface
4. The attribute values in @MyTest1(aaa=”Sun Wukong”, bbb=false, ccc={“Python”, “front-end”, “Java”}) can be obtained by calling aaa(), bbb(), ccc() method to obtain
3.3 yuan annotation
Meta-annotations are annotations that modify annotations
@Target is used to declare that annotations can only be used in those locations, such as: classes, methods, member variables, etc. @Retetion is used to declare the annotation retention period, such as: source code period, bytecode period, runtime period
For example, the @target of test is type, and @retention is runtime.
3.4 Parsing annotations
1. If the annotation is on the class, first obtain the bytecode object of the class, and then obtain the annotation on the class 2. If the annotation is on the method, first obtain the method object, and then obtain the annotation on the method. 3. If the annotation is on a member variable, first obtain the member variable object, and then obtain the annotation on the variable. In short: whoever the annotation is on, get it first, and then use whoever it is to get the annotation on that person.
public class AnnotationTest3{ @Test public void parseClass(){ //1. Get the Class object first Class c = Demo.class; //2. Parse the annotations on the Demo class if(c.isAnnotationPresent(MyTest4.class)){ //Get the MyTest4 annotation on the class MyTest4 myTest4 = (MyTest4)c.getDeclaredAnnotation(MyTest4.class); //Get the attribute value of MyTests4 annotation System.out.println(myTest4.value()); System.out.println(myTest4.aaa()); System.out.println(myTest4.bbb()); } } @Test public void parseMethods(){ //1. Get the Class object first Class c = Demo.class; //2. Parse the annotation MyTest4 annotation on the test1 method in the Demo class Method m = c.getDeclaredMethod("test1"); if(m.isAnnotationPresent(MyTest4.class)){ //Get the MyTest4 annotation on the method MyTest4 myTest4 = (MyTest4)m.getDeclaredAnnotation(MyTest4.class); //Get the attribute value of MyTests4 annotation System.out.println(myTest4.value()); System.out.println(myTest4.aaa()); System.out.println(myTest4.bbb()); } } }
The picture above shows the annotations on the obtained classes and methods.
3.4 Application scenarios of annotations-simulating Junit to write a test framework
That is to say, annotated methods or classes will be treated specially.
public class AnnotationTest4{ @MyTest public void test1(){ System.out.println("=====test1===="); } @MyTest public void test2(){ System.out.println("======test2===="); } public void test3(){ System.out.println("======test2===="); } public static void main(String[] args){ AnnotationTest4 a = new AnnotationTest4(); //1. Get the Class object first Class c = AnnotationTest4.class; //2. Parse all method objects in the AnnotationTest4 class Method[] methods = c.getDeclaredMethods(); for(Method m: methods){ //3. Determine whether there is a MyTest annotation on the method, and execute the method if so. if(m.isAnnotationPresent(MyTest.class)){ m.invoke(a); } } } }
4. Dynamic proxy
Key points: interface (the method of declaring a proxy is equivalent to abstracting what is to be done, and can be used as parameter 2 to indicate what the proxy looks like when the proxy generates a proxy object), tool classes generate dynamic proxy objects, and the Proxy class newInstamce generates a proxy object and overrides the invoke method to implement the callback function
ProxyUtil tool class, generates proxy objects for BigStar objects public class ProxyUtil { public static Star createProxy(BigStar bigStar){ /* newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) Parameter 1: used to specify a class loader Parameter 2: Specify what the generated agent looks like, that is, what methods are there? Parameter 3: Used to specify what the generated proxy object is to do. */ // Star starProxy = ProxyUtil.createProxy(s); // starProxy.sing("Good Day") starProxy.dance() Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{Star.class}, new InvocationHandler() { @Override // callback method public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //What the proxy object has to do will be written here. if(method.getName().equals("sing")){ System.out.println("Prepare the microphone, charge 200,000"); }else if(method.getName().equals("dance")){ System.out.println("Prepare the venue, collect 10 million"); } return method.invoke(bigStar, args); } }); return starProxy; } }
new proxyInstance(loader,class> [] interfaces,invocationhalder):
- 1. Define the class loader
- 2. Define the methods that should be included in the proxy object, which can have multiple interfaces
- 3. This is to define what the proxy object should do
public class ProxyUtil { public static UserService createProxy(UserService userService){ UserService userServiceProxy = (UserService) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), new Class[]{UserService.class}, new InvocationHandler() { @Override public Object invoke( Object proxy, Method method, Object[] args) throws Throwable { if( method.getName().equals("login") || method.getName().equals("deleteUsers")|| method.getName().equals("selectUsers")){ //Record the millisecond value before the method is run long startTime = System.currentTimeMillis(); //execution method Object rs = method.invoke(userService, args); //Record the millisecond value after executing the method long endTime = System.currentTimeMillis(); System.out.println(method.getName() + "Method execution time:" + (endTime - startTime)/ 1000.0 + "s"); return rs; }else { Object rs = method.invoke(userService, args); return rs; } } }); //return proxy object return userServiceProxy; } }
The bottom layer of AOP is also a dynamic proxy implementation. What is used elsewhere is the delayed loading in mybatis, which uses CGLIB dynamic proxy to implement the search and save operation when this function is needed.