Overview: This article is important! This article will teach you how to write a section for your project. Many developers don’t know how to write a section when they start.

We explained AOP programming for Spring earlier, essentially adding extra functionality to Spring objects by creating proxy objects. All of the previous approaches are implemented through XML configuration. Let’s briefly review the previous steps.

  1. The original object
  2. Additional functionality
  3. The breakthrough point
  4. The assembly

I. Development steps

1.Additional features: previously written publicclass MyArround implements MythodInterceptor{
  public Object  invoke(MethodInvocation invocation){...}
  
  }
2.<aop:confg><aop:pointcut id="pc" expression="executionn(* com.xxx.. *. * (..) )" />
    <aop:advisor advice-ref="around" pointcut-ref="pc" />
</aop:confg> 
Copy the code

Spring itself provides an annotated way to implement AOP programming, so let’s take a look at the code.

  1. Create aspect classes that define additional functionality and pointcuts.
/** 1. Additional features: Public Implements MythodInterceptor{public Object Invocation (MethodInvocation){}} 2. 
      
        < AOP :pointcut id=" PC "expression="execution(* login(..)) )" />  */
      
@Aspect // Specify the cut class
public class MyAspect{
	
    @Arround("execution(* login(..) )" // Specify additional functionality and pointcut expressions
    public Object arround(ProceedingJoinPoint joinPoint) throws Throwable{
    System.out.println("---log---")
    Object ret = joinPoint.proceed();
    returnret; }}Copy the code
  1. Configuration section:
<bean id="arround" class="com.xxx.MyAspect" />
<! Tell Spring to develop facets based on annotations -->
<aop:aspectj-autoproxy />
Copy the code

This completes our previous four steps, and now the object we fetch from the factory is the proxy object, which performs additional functionality when the method is called (note: methods that conform to the pointcut expression).

Second, detailed analysis

  1. Pointcut reuse

Pointcut reuse: Pointcut expression is defined in this way by defining a function in the aspect and adding the @pointcut annotation. Pointcut reuse is realized, which is equivalent to the Pointcut extraction. It is convenient for pointcuts to increase the redundant problem of multiple additional functions. This gives us the flexibility to freely combine pointcuts and additional functionality.

@Aspect // Specify the cut class
public class MyAspect{
  
  @Pointcut("execution(* login(..) )"
  public void myPointCut(a){}
	
  @Arround(value="myPointcut()"))
	public Object arround(ProceedingJoinPoint joinPoint) throws Throwable{
      System.out.println("---log---")
      Object ret = joinPoint.proceed();
      return ret;
  }
  
  @Arround(value="myPointcut()")
	public Object arround1(ProceedingJoinPoint joinPoint) throws Throwable{
      System.out.println("---tx---")
      Object ret = joinPoint.proceed();
      returnret; }}Copy the code
  1. How to create a dynamic proxy
JDK dynamic proxy: create a proxy object by implementing an interface. Cglib dynamic proxy: create a proxy object by inheriting a parent class. < AOP :aspectj-autoproxy proxy-target-class=true /> < ASPectj-autoproxy proxy-target-class=true />Copy the code

Once set, we can observe the breakpoint:

How to set up the cglib dynamic proxy when we did not use annotations:

<aop:confg proxy-target-class="true">
	<aop:pointcut id="pc" expression="@annocation(com.xxx.Log)" />
  <aop:advisor advice-ref="around" pointcut-ref="pc" />
</aop:confg>
Copy the code

A pit in AOP development

One of the problems we sometimes encounter with proxy development is the failure of additional functionality. Let’s take a look at how this problem arises.

  1. Start by setting up a slice to add extra functionality.
@Aspect // Specify the cut class
public class MyAspect{
  
  @Pointcut("execution(* *.. UserServiceImpl.*(..) )"
  public void myPointCut(a){}
	
  @Arround(value="myPointcut()"))
	public Object arround(ProceedingJoinPoint joinPoint) throws Throwable{
      System.out.println("---log---")
      Object ret = joinPoint.proceed();
      return ret;
  }
  
  @Arround(value="myPointcut()")
	public Object arround1(ProceedingJoinPoint joinPoint) throws Throwable{
      System.out.println("---tx---")
      Object ret = joinPoint.proceed();
      returnret; }}Copy the code
  1. We make the call in the target method:

public class UserServiceImpl implements UserService {
  
  @Override
  public void register(User user){
    System.out.println("registe----")
      // Call the original object login method -- the core function, the section function does not execute
      // Call the login method of the proxy object
      this.login("abc"."123456");
 
  }
  
  @Override
  public boolean login(String name, String password){
    System.out.println("login-----")}}Copy the code

Notice at this point that when we get the UserService object from the factory and call the register method, the register method performs additional functions, but since the register method uses this to call login, The login method performs no additional functionality at this point. The reason for this is that the login method is called with this, so it doesn’t get a proxy object, so it doesn’t perform any extra functionality. It’s like calling a method directly from the original class. What if the login method also has an extra feature at this point, which is that we call the login method through a proxy object.

This can be done using the ApplicationContextAware we talked about in previous articles, by injecting the factory and retrieving the object call from the factory.

public class UserServiceImpl implements UserService implements ApplicationContextAware{
  
  private ApplicationContext ctx;
  
  public void setApplicationContext(AppliactionContext application){
    	this.ctx = application;
  }
  
  @Override
  public void register(User user){
    System.out.println("registe----")
      // Call the original object login method -- the core function, the section function does not execute
      // Call the login method of the proxy object
      this.login("abc"."123456");
    	// Get the proxy object
    	UserService userService = (UserService)ctx.getBean("userService");
    	userService.login("abc"."123456");
  }
  
  @Override
  public boolean login(String name, String password){
    System.out.println("login-----")}}Copy the code

To sum up: In the same business class, when business methods are called each other, only the outermost method is added with additional functions. The inner method is called in the ordinary way, which calls the original method. If you want the inner method to also call the method of the proxy object, you need to obtain the existing factory through the ApplicationContextAware interface. To obtain the proxy object

AOP summary: