Java programming -- Java advanced technology

1. Unit test

1.1 overview of unit test

Unit test is to write test code for the smallest functional unit, and the smallest functional unit of Java program is method. Therefore, unit test is to test Java method, and then check the correctness of method.

Current test methods

  • There is only one main method. If the test of one method fails, the test of other methods will be affected.
  • Unable to get the test result report, the programmer needs to observe whether the test is successful.
  • Automated testing is not possible.

Junit unit test framework

  • JUnit is a unit testing framework implemented in Java language. It is open source. Java developers should learn and use JUnit to write unit tests.
  • In addition, almost all ide tools integrate JUnit, so that we can directly write and run JUnit tests in the IDE. The latest version of JUnit is 5.

JUnit benefits

  • JUnit can flexibly choose which test methods to execute, and can execute all test methods with one click.
  • Junit can generate test reports of all methods. If the test is good, it is green, and if the test fails, it is red.
  • The failure of one unit test method will not affect other unit test methods.

1.2 unit test quick start

Requirements: a quick start to use unit tests to test the expected results and correctness of business methods

analysis:

  1. Import the jar package of JUnit into the project
    -IDEA usually integrates Junit framework and generally does not need to be imported.
    -If the IDEA is not integrated well, you need to manually import the following two JUnit jar packages into the module
    -

  2. Write test method: the test method must be a public non static method without parameters and return value.

  3. Use @ Test annotation on the Test method: mark that the method is a Test method

  4. Complete the expected correctness test of the tested method in the test method.

  5. Select the test method and select "JUnit run". If the test is good, it is green; If the test fails, it is red

1.3 common notes of unit test

Junit common notes (Junit version 5.xxxx)

annotationexplain
@Testtest method
@BeforeEachUsed to decorate the instance method, which will be executed once before each test method is executed.
@AfterEachUsed to decorate the instance method, which will be executed once after each test method is executed.
@BeforeAllUsed to statically decorate the method, which will be executed only once before all test methods.
@AfterAllUsed to statically decorate the method, which will be executed only once after all test methods.
  • Method to start execution: initialize resources.
  • Method after execution: release resources.
/**
   Business method
 */
public class UserService {
    public String loginName(String loginName , String passWord){
        if("admin".equals(loginName) && "123456".equals(passWord)){
            return "Login successful";
        }else {
            return "There is a problem with the user name or password";
        }
    }

    public void selectNames(){
        System.out.println(10/2);
        System.out.println("Query all user names succeeded~~");
    }
}

import org.junit.*;

/**
   Test class
 */
public class TestUserService {

    // Modification of instance method
    @Before
    public void before(){
        System.out.println("===before Method is executed once===");
    }

    @After
    public void after(){
        System.out.println("===after Method is executed once===");
    }

    // Modified static method
    @BeforeClass
    public static void beforeClass(){
        System.out.println("===beforeClass Method is executed once===");
    }

    @AfterClass
    public static void afterClass(){
        System.out.println("===afterClass Method is executed once===");
    }


    /**
       test method
       Note:
            1,Must be a public method with no parameters and no return value
            2,The Test method must be marked with the @ Test annotation.
     */
    @Test
    public void testLoginName(){
        UserService userService = new UserService();
        String rs = userService.loginName("admin","123456");

        // Test the correctness of the expected results: assertions.
        Assert.assertEquals("There may be a problem with your login business", "Login successful", rs );
    }

    @Test
    public void testSelectNames(){
        UserService userService = new UserService();
        userService.selectNames();
    }

}

2. Reflection

2.1 reflection overview

  • Reflection means that for any Class, all the components of this Class can be obtained directly "at run time".
  • At runtime, you can directly get the Constructor object of this class: Constructor
  • At runtime, you can directly get the member variable object of this class: Field
  • At runtime, you can directly get the member Method object of this class: Method
  • This ability of dynamically obtaining class information and dynamically calling components in classes at runtime is called the reflection mechanism of Java language.

The key to reflection:

The first step of reflection is to get the compiled Class object first, and then you can get all the components of Class.

2.2 reflection acquisition object

Reflection get class object

public class Student {
}

/**
   The first step of reflection: get the Class object
 */
public class Test {
    public static void main(String[] args) throws Exception {
        // 1. A static method in Class: forname (full name: package name + Class name)
        Class c = Class.forName("com.itheima.d2_reflect_class.Student");
        System.out.println(c); // Student.class

        // 2. Class name class
        Class c1 = Student.class;
        System.out.println(c1);

        // 3. Object getClass() gets the Class object of the corresponding Class of the object.
        Student s = new Student();
        Class c2 = s.getClass();
        System.out.println(c2);
    }
}

Reflection get constructor object

Get the constructor object using reflection technology and use

  • The first step of reflection is to get the class object first, and then get the component object of the class from the class object.
  • Method used to get constructor in Class
methodexplain
Constructor<?>[] getConstructors()Returns an array of all constructor objects (only public)
Constructor<?>[ ] getDeclaredConstructors()Return an array of all constructor objects, and you can get them if they exist
Constructor< T > getConstructor(class<?>... parameterTypes)Return a single constructor object (only public)
Constructor< T > getDeclaredConstructor(Class<?>... parameterTypes)Return a single constructor object, and you can get it if it exists

The method used to create an object in the Constructor class

Symbolexplain
T newInstance(Object... initargs)Creates an object based on the specified constructor
public void setAccessible(boolean flag)Set to true to cancel the access check and perform violent reflection

If it is a non-public constructor, you need to open the permission (violent reflection), and then create the object, setAccessible(boolean). Reflection can destroy encapsulation, and private can also be executed.

public class Student {
    private String name;
    private int age;

    private Student(){
        System.out.println("No parameter constructor execution!");
    }

    public Student(String name, int age) {
        System.out.println("There is a parameter constructor to execute!");
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

import org.junit.Test;

import java.lang.reflect.Constructor;

public class TestStudent01 {
    // 1. getConstructors:
    // Get all constructors: only constructors decorated with public can be obtained.
    // Constructor[] getConstructors()
    @Test
    public void getConstructors(){
        // a. Step 1: get class object
        Class c = Student.class;
        // b. Extract all constructor objects in the class (only public can be used here)
        Constructor[] constructors = c.getConstructors();
        // c. Traversal constructor
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    }


    // 2.getDeclaredConstructors():
    // Get all constructors: as long as you dare to write, you can get them here. It doesn't matter whether the permission is reachable or not.
    @Test
    public void getDeclaredConstructors(){
        // a. Step 1: get class object
        Class c = Student.class;
        // b. Extract all constructor objects in the class
        Constructor[] constructors = c.getDeclaredConstructors();
        // c. Traversal constructor
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
        }
    }

    // 3.getConstructor(Class... parameterTypes)
    // Get a constructor: you can only take a constructor decorated with public
    @Test
    public void getConstructor() throws Exception {
        // a. Step 1: get class object
        Class c = Student.class;
        // b. Locate a single constructor object (locate nonparametric constructors according to parameters. Only one constructor decorated with public can be used)
        Constructor cons = c.getConstructor();
        System.out.println(cons.getName() + "===>" + cons.getParameterCount());
    }


    // 4.getConstructor(Class... parameterTypes)
    // Get a constructor: as long as you dare to write, you can get it here. It doesn't matter whether the permission is reachable or not.
    @Test
    public void getDeclaredConstructor() throws Exception {
        // a. Step 1: get class object
        Class c = Student.class;
        // b. Locate a single constructor object (locate nonparametric constructors by parameters)
        Constructor cons = c.getDeclaredConstructor();
        System.out.println(cons.getName() + "===>" + cons.getParameterCount());

        // c. Locate a parameterized constructor
        Constructor cons1 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(cons1.getName() + "===>" + cons1.getParameterCount());

    }

}

Get member variable object by reflection

Use reflection technology to obtain member variable objects and use

  • The first step of reflection is to get the class object first, and then get the component object of the class from the class object.
  • The method used to get member variables in Class.
methodexplain
Field [ ] getFields()Returns an array of all member variable objects (only public)
Field[ ] getDeclaredFields()Return an array of all member variable objects, and you can get them if they exist
Field getField(String name)Return a single member variable object (only public)
Field getDeclaredField(String name)Return a single member variable object, and you can get it if it exists

The function of getting member variables is still to take values and assign values in an object

Methods used for value taking and assignment in Field class

Symbolexplain
void set(Object obj, Object value):assignment
Object get(Object obj)Get value
public class Student {
    private String name;
    private int age;
    public static String schoolName;
    public static final String  COUNTTRY = "China";

    public Student(){
        System.out.println("No parameter constructor execution!");
    }

    public Student(String name, int age) {
        System.out.println("There is a parameter constructor to execute!");
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import org.junit.Test;

import java.io.File;
import java.lang.reflect.Field;

public class FieldDemo01 {
    /**
     * 1.Get all member variables.
     * Field[] getDeclaredFields();
     *  Get the Field objects corresponding to all member variables. You can get them as long as they are declared
     */
    @Test
    public void getDeclaredFields(){
        // a. Locate Class object
        Class c = Student.class;
        // b. Locate all member variables
        Field[] fields = c.getDeclaredFields();
        // c. Traverse
        for (Field field : fields) {
            System.out.println(field.getName() + "==>" + field.getType());
        }
    }

    /**
        2.Get a member variable object field getdeclaraedfield (string name);
     */
    @Test
    public void getDeclaredField() throws Exception {
        // a. Locate Class object
        Class c = Student.class;
        // b. Locate a member variable by name
        Field f = c.getDeclaredField("age");
        System.out.println(f.getName() +"===>" + f.getType());
    }

}


Reflection get object method

Use reflection technology to obtain method objects and use

  • The first step of reflection is to get the class object first, and then get the component object of the class from the class object.
  • Method used to get member method in Class
methodexplain
Method[ ] getMethods()Returns an array of all member method objects (only public)
Method[ ] getDeclaredMethods()Return an array of all member method objects, and you can get them if they exist
Method getMethod(String name,Class<?>... parameterTypes)Return a single member method object (only public)
Method getDeclaredNethod(String name,Class<?>... parameterTypes)Return a single member method object, and you can get it if it exists

The function of getting member Method is still to execute in an object. This Method is the Method used to trigger execution in the Method class

Symbolexplain
object invoke(0bject obj,object. . . args)Running method \ parameter 1: call the method with obj object \ parameter 2: parameters passed by calling the method (do not write if not) return value: return value of the method (do not write if not)
public class Dog {
    private String name ;
    public Dog(){
    }

    public Dog(String name) {
        this.name = name;
    }

    public void run(){
        System.out.println("A dog runs fast as a thief~~");
    }

    private void eat(){
        System.out.println("Dogs eat bones");
    }

    private String eat(String name){
        System.out.println("Dog eat" + name);
        return "Eat very happy!";
    }

    public static void inAddr(){
        System.out.println("I'm learning Java!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
import org.junit.Test;

import java.lang.reflect.Method;

public class MethodDemo01 {
    /**
     * 1.Gets all member method objects in the class
     */
    @Test
    public void getDeclaredMethods(){
        // a. Get class object
        Class c = Dog.class;
        // b. Extract all methods; Including private
        Method[] methods = c.getDeclaredMethods();
        // c. Traverse all methods
        for (Method method : methods) {
            System.out.println(method.getName() +" Return value type:" + method.getReturnType() + " Number of parameters:" + method.getParameterCount());
        }
    }

    /**
     * 2. Get a method object
     */
    @Test
    public void getDeclardMethod() throws Exception {
        // a. Get class object
        Class c = Dog.class;
        // b. Extract a single method object
        Method m = c.getDeclaredMethod("eat");
        Method m2 = c.getDeclaredMethod("eat", String.class);

        // Violence has turned on permissions
        m.setAccessible(true);
        m2.setAccessible(true);

        // c. Trigger method execution
        Dog d = new Dog();
        // Note: if the method returns no result, it returns null
        Object result = m.invoke(d);
        System.out.println(result);

        Object result2 = m2.invoke(d, "bone");
        System.out.println(result2);
    }
}

2.3 function of reflection

The role of reflection - bypassing the compilation phase to add data to the collection

Reflection is a technology that works at runtime. At this time, the genericity of the collection will not produce constraints. At this time, other elements of any type can be stored for the collection.

ArrayList< Integer > list = new ArrayList<>();
list.add(100);
// list.add("dark horse"); / / an error is reported
list.add(99);

Generics can only restrict the collection to operate certain data types in the compilation stage. When compiling into a Class file and entering the running stage, its real type is ArrayList, and generics are equivalent to being erased. Reflection is a technology that works at runtime, and generics no longer exist.

import java.lang.reflect.Method;
import java.util.ArrayList;

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        // Requirement: after the generic erasure of reflection is implemented, other types of elements are added
        ArrayList<String> lists1 = new ArrayList<>();
        ArrayList<Integer> lists2 = new ArrayList<>();

        System.out.println(lists1.getClass());
        System.out.println(lists2.getClass());

        System.out.println(lists1.getClass() ==  lists2.getClass());  // ArrayList.class

        System.out.println("---------------------------");
        ArrayList<Integer> lists3 = new ArrayList<>();
        lists3.add(23);
        lists3.add(22);
        // lists3.add("33");

        Class c = lists3.getClass(); // ArrayList.class  ===> public boolean add(E e)
        // Locate the add method in class c
        Method add = c.getDeclaredMethod("add", Object.class);
        boolean rs = (boolean) add.invoke(lists3, "33");
        System.out.println(rs);

        System.out.println(lists3);

        ArrayList list4 = lists3;
        list4.add("44");
        list4.add(false);
        System.out.println(lists3);
    }
}

Reflection as a general framework

  • You can get all the components of a class at run time and then operate.
  • Can destroy encapsulation. (very prominent)
  • You can also break the constraints of generics. (very prominent)
  • More importantly, it is suitable for: making Java advanced framework.
  • Basically, mainstream frameworks will design some general technical functions based on reflection.

3. Annotation

3.1 general notes

Java Annotation, also known as Java Annotation, is jdk5 0. Classes, constructors, methods, member variables and parameters in the Java language can be annotated.

Function of annotation: = = mark classes, methods and member variables in Java, and then conduct special processing. What kind of processing is determined by business requirements== For example, in JUnit framework, methods marked with @ Test annotation can be executed as Test methods, while those without marks cannot be executed as Test methods.

3.2 user defined annotation

Custom annotation is to make an annotation to use.

public @interface Annotation name{
	public Property name property name()default Default value;
}

Special properties

  • Value attribute. If there is only one value attribute, the value name can be omitted when using the value attribute!!
  • However, if there are multiple attributes and multiple attributes have no default values, the value name cannot be omitted.
/**
   Learn to customize annotations. Master its definition, format and syntax.
 */
@MyBook(name="<master JavaSE>",authors = {"nameless", "dlei"} , price = 199.5)
//@Book(value = "/delete")
// @Book("/delete")
@Book(value = "/delete", price = 23.5)
//@Book("/delete")
public class AnnotationDemo1 {

    @MyBook(name="<master JavaSE2>",authors = {"nameless", "dlei"} , price = 199.5)
    private AnnotationDemo1(){

    }

    @MyBook(name="<master JavaSE1>",authors = {"nameless", "dlei"} , price = 199.5)
    public static void main(String[] args) {
        @MyBook(name="<master JavaSE2>",authors = {"nameless", "dlei"} , price = 199.5)
        int age = 21;
    }
}

3.3 meta annotation

Meta annotation: it is the annotation of annotation.

There are two meta annotations:

  • @Target: constrains where custom annotations can only be used
  • @Retention: declares the lifecycle of the annotation

@The values that can be used in Target are defined in the ElementType enumeration class. The common values are as follows

  • TYPE, class, interface
  • FIELD, member variable
  • METHOD, member METHOD
  • PARAMETER, method PARAMETER
  • CONSTRUCTOR, CONSTRUCTOR
  • LOCAL_VARIABLE, local variable

@The values that can be used in Retention are defined in the RetentionPolicy enumeration class. Common values are as follows

  • SOURCE: annotation only works in the SOURCE code stage, and does not exist in the generated bytecode file
  • CLASS: annotation is used in the source code stage, bytecode file stage, and the runtime stage does not exist. The default value is
  • RUNTIME: annotations are used in the source code stage, bytecode file stage and RUNTIME stage (commonly used in development)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.FIELD}) // Meta annotation
@Retention(RetentionPolicy.RUNTIME) // Always alive, this annotation does not disappear during the running phase
public @interface MyTest {
}

3.4 annotation analysis

Annotation parsing

Annotation parsing is often required in the operation of annotation. Annotation parsing is to judge whether there are annotations. If there are annotations, the content will be parsed.

Interface related to annotation parsing

  • Annotation: the top-level interface of annotations. Annotations are objects of annotation type
  • AnnotatedElement: this interface defines the parsing methods related to annotation parsing
methodexplain
Annotationl]getDeclaredAnnotations()Get all annotations used on the current object and return the annotation array.
T getDeclaredAnnotation(Class< T > annotationClass)Obtain the corresponding annotation object according to the annotation type
boolean isAnnotationPresent(Class< Annotation > annotationClass)Judge whether the current object uses the specified annotation. If so, return true; otherwise, false

All class components, such as class, method, field and constructor, have implemented the AnnotatedElement interface. They all have the ability to parse annotations

public @interface Book {
    String value(); // Special properties
    double price() ;
    //double price() default 9.9;
}

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Bookk {
    String value();
    double price() default 100;
    String[] author();
}

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
   Objective: to complete annotation parsing
 */
public class AnnotationDemo3 {
    @Test
    public void parseClass(){
        // a. Get the class object first
        Class c = BookStore.class;
        // b. Determine whether this annotation exists on this class
        if(c.isAnnotationPresent(Bookk.class)){
            //c. Get the annotation object directly
            Bookk book = (Bookk) c.getDeclaredAnnotation(Bookk.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.author()));
        }
    }

    @Test
    public void parseMethod() throws NoSuchMethodException {
        // a. Get the class object first
        Class c = BookStore.class;

        Method m = c.getDeclaredMethod("test");

        // b. Determine whether this annotation exists on this class
        if(m.isAnnotationPresent(Bookk.class)){
            //c. Get the annotation directly
            Bookk book = (Bookk) m.getDeclaredAnnotation(Bookk.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.author()));
        }
    }
}

@Bookk(value = "<"Love is deep and rainy"", price = 99.9, author = {"Qiongyao", "dlei"})
class BookStore{

    @Bookk(value = "<The sword of the third young master", price = 399.9, author = {"Gulong", "Xiong Yaohua"})
    public void test(){
    }
}

Techniques for parsing annotations

  • On which component is the annotation, we take which component object first.
  • For example, to annotate a member Method, you need to obtain the Method object corresponding to the member Method, and then take the above annotation
  • For example, if annotations are applied to a Class, you need the Class object of the Class, and then take the above annotations
  • For example, if the annotation acts on a member variable, you need to obtain the Field object corresponding to the member variable, and then take the above annotation

4. Dynamic agent

Simulate the development of enterprise business functions and complete the performance statistics of each function

demand

Simulate the user management business of an enterprise, including user login, user deletion and user query functions, and count the time consumption of each function

analysis

  1. Define a UserService to represent the user business interface, which stipulates that the functions of user login, user deletion and user query must be completed.
  2. Define an implementation class UserServicelmpl to implement UserService, complete relevant functions, and count the time consumption of each function.
  3. Define test classes, create implementation class objects, and call methods.
public class UserServiceImpl implements UserService{
    @Override
    public String login(String loginName, String passWord)  {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if("admin".equals(loginName) && "1234".equals(passWord)) {
            return "success";
        }
        return "There may be something wrong with your login name and password";

    }

    @Override
    public void selectUsers() {
        System.out.println("Queried 100 user data!");
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean deleteUsers() {
        try {
            System.out.println("Delete 100 user data!");
            Thread.sleep(500);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void updateUsers() {
        try {
            System.out.println("Modify 100 user data!");
            Thread.sleep(2500);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
   Simulate user business functions
 */
public interface UserService {
    String login(String loginName , String passWord) ;
    void selectUsers();
    boolean deleteUsers();
    void updateUsers();
}

public class Test {
    public static void main(String[] args) {
        // 1. The business object is directly made into a proxy object and returned. The type of proxy object is also UserService type
        UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
        System.out.println(userService.login("admin", "1234"));
        System.out.println(userService.deleteUsers());
        userService.selectUsers();
        userService.updateUsers(); // Go agent
    }
}

In this case, performance statistics are required for each method of the business object, and there are a large number of duplicate codes.

Dynamic agent

Agent is that the agent is unable or unwilling to complete something and needs to find someone to complete it instead of himself. Dynamic agent is used to represent business functions (Methods).

Key steps

  1. There must be an interface, and the implementation class should implement the interface (the agent is usually implemented based on the interface).
  2. Create an object that implements the class, which is a business object, and then make a proxy object for the business object.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
    public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces, InvocationHandler h)
    Parameter 1: class loader, which is responsible for loading agent classes into memory for use.
    Parameter 2: get all interfaces implemented by the proxy object. The proxy should proxy all methods of all interfaces
    Parameter 3: core processing logic of agent
 */
public class ProxyUtil {
    /**
      Generate the proxy object of the business object.
     * @param obj
     * @return
     */
    public static <T> T  getProxy(T obj) {
        // A proxy object was returned
        return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // Parameter 1: proxy object itself. Generally regardless
                        // Parameter 2: method being represented
                        // Parameter 3: the parameters that should be passed in the proxy method
                       long startTimer = System .currentTimeMillis();
                        // Trigger the real execution of the method immediately. (trigger real business functions)
                        Object result = method.invoke(obj, args);

                        long endTimer = System.currentTimeMillis();
                        System.out.println(method.getName() + "Time consuming method:" + (endTimer - startTimer) / 1000.0 + "s");

                        // Return the execution result of the business function method to the caller
                        return result;
                    }
                });
    }
}

Advantages of dynamic agent

  • It is very flexible. It supports the implementation class object of any interface type to act as a proxy, or directly act as a proxy for the interface itself.
  • You can proxy all methods of the proxied object.
  • You can enhance the function of the method without changing the method source code.
  • It not only simplifies the programming work and improves the scalability of the software system, but also improves the development efficiency.

Tags: Java unit testing reflection Annotation Dynamic Proxy

Posted by ifty on Sun, 17 Apr 2022 16:59:07 +0930