Spring dynamic proxy

1. Static proxy

static proxy

  1. To implement the same interface;
  2. have primitive objects;
  3. To have extra functionality.

The following is an example of a static proxy.

public class UserServiceProxy implements UserService {

    private UserServiceImpl userService = new UserServiceImpl();

    @Override
    public void addUser() {
        userService.addUser();
        System.out.println("UserServiceProxy.addUser");
    }

    @Override
    public void deleteUser() {
        userService.deleteUser();
        System.out.println("UserServiceProxy.deleteUser");
    }
}

The biggest feature of static proxy is that if we have an original class, we must have a proxy class. Static means that the proxy class needs to manually write a source file.

Problems with static proxies:

  • The number of class files is too large, which is not conducive to project management;
  • The maintainability of the extra functions is poor, and it is troublesome to modify the extra functions in the proxy class;

2. Dynamic proxy

Spring dynamic proxy

  1. create original object (target object);

    public class UserServiceImpl implements UserService {
    
        @Override
        public void register() {
            System.out.println("UserServiceImpl.register business computing + DAO");
        }
    
        @Override
        public boolean login() {
            System.out.println("UserServiceImpl.login");
            return true;
        }
    }
    

    Add this to the container:

    <bean class="edu.lsu.service.impl.UserServiceImpl" id="userService"/>
    
  2. provide additional functionality;

    Spring provides an interface MethodBeforeAdvice, additional functionality is written in the implementation of the interface and will run before the original method runs.

    public class Before implements MethodBeforeAdvice {
        @Override
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("Before.before---MethodBeforeAdvice");
        }
    }
    
    <bean class="edu.lsu.dynamic.Before" id="before"/>
    
  3. Define pointcut: where extra functionality is added

    Purpose: It is up to the programmer to decide where additional functions should be added according to their own needs.

    <aop:config>
            <aop:pointcut id="pc" expression="execution(* *(..))"/>
    </aop:config>
    
  4. assemble

    Integrate pointcuts with additional functionality;

    <aop:config>
        <aop:pointcut id="pc" expression="execution(* *(..))"/>
    <!--    All methods are added before extra features    -->
        <aop:advisor advice-ref="before" pointcut-ref="pc"/>
    </aop:config>
    
  5. transfer

    Purpose: Obtain the dynamic proxy object created by the Spring factory and call it;

    • Spring's factory obtains the proxy object through the id value of the original object;
    • Proxy objects can be stored using interface types.

3. Detailed analysis

Where are the dynamic proxy classes created by Spring?

At runtime, the Spring framework, through dynamic bytecode technology, runs inside the JVM when the JVM is created, and disappears with the JVM after the program ends.

Dynamic proxies do not need to define class files, they are all dynamically created during the running of the JVM, so it will not cause the problem of excessive number of static proxy class files affecting project management.

The maintainability of dynamic proxies is greatly enhanced.

4. Detailed explanation of Spring dynamic proxy

MethodBeforeAdvice

We implement additional functionality by implementing the MethodBeforeAdvice interface.

@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
      System.out.println("Before.before---MethodBeforeAdvice");
}

The interface has a method before, which has 3 parameters:

  • method: the original method to which the extra functionality was added;
  • objects: parameters of the original method;
  • o: Represents the original object to which the extra functionality was added.

MethodInterceptor

It is also called method interceptor

The org.aopalliance.intercept.MethodInterceptor is used here, one is also provided in the cjlib package, but we do not use that one.

The interface has an invoke method that can be overridden to have additional functionality executed before or after the original method, or both.

public class Around implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        return null;
    }
}

Parameters MethodInvocation: The original method to which additional functions are added, methodInvocation.proceed(); represents the original method operation.

The return value represents the return value after the execution of the original method.

public class Around implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("Around.invoke----run before the original method.");
        Object res = methodInvocation.proceed();
        System.out.println("Around.invoke----run after the original method.");
        return res;
    }
}
<bean class="edu.lsu.service.impl.UserServiceImpl" id="userService"/>
<bean class="edu.lsu.dynamic.Around" id="around"/>
<aop:config>
    <aop:pointcut id="pc" expression="execution(* *(..))"/>
    <!--    All methods are added around extra features    -->
    <aop:advisor advice-ref="around" pointcut-ref="pc"/>
</aop:config>

output:

Around.invoke----run before the original method.
UserServiceImpl.login
Around.invoke----run after the original method.

Around.invoke----run before the original method.
UserServiceImpl.register business computing + DAO
Around.invoke----run after the original method.

pointcut expression

* edu.lsu.service.*.*(..)
  • access modifiers can be omitted;
  • The return value can use the wildcard * to represent any return value;
  • The package name can be any package, but if there are several packages, just write several *. ;
  • *.. represents the current package and its subpackages.
  • The parameter type can use wildcards to indicate any type, and .. can be used to indicate whether there are parameters.

pointcut function

Used to execute pointcut expressions.

  1. execution

    It is the most important pointcut function and has the most complete functions, but it is complicated to write.

  2. args

    Matching for function (method) parameters

    execution(* *(String, String)) == args(String, String)
    
  3. within

    Used to match class and package pointcut expressions

    execution(* *..UserServiceImpl.*(..)) == within(*..UserServiceImpl)
    execution(* top.wsuo.proxy..*.*(..)) == within(top.wsuo.proxy..*)
    
  4. @annotation

    Add extra functionality to methods with special annotations.

    <aop:pointcut id="pc" expression="@annotation(edu.lsu.Log)"/>
    

    Add annotations to the specified method to achieve the function.

  5. Logical operations of pointcut functions

    It refers to integrating multiple pointcut functions to work together to complete more complex requirements.

    • and with operation:

      execution(* login(String, String)) 
      == execution(* login(..)) and args(String, String)
      
    • or or operation:

      execution(* login(..)) or execution(* login(..))
      

Tags: Java

Posted by sone_br on Wed, 18 May 2022 20:04:44 +0300