Spring AOP introduction Demo Share

  • 2020-12-09 00:50:34
  • OfStack

Before reading this article, you can refer to article 1, IOC and AOP and Code Examples for a simple Understanding of Spring to get a brief understanding of ioc and aop. Let's get down to business.

This article will create the simplest example step by step to use Spring's AOP feature as a primer for Spring AOP. As a beginner, running such a simple Demo takes a lot of potholes.

Question of OOP, supplement of AOP

OOP is helpless when it comes to introducing common behavior for dispersed objects. In other words, OOP allows you to define relationships from top to bottom, but not from left to right. Such as logging. Logging code tends to be spread horizontally across all object hierarchies and has nothing to do with the core functionality of the objects to which it is spread. The same is true for other types of code, such as security, exception handling, and transparent persistence. This scattered, unrelated code is known as crosscutting (ES22en-ES23en) code, and in the OOP design it leads to a lot of code duplication that discourages the reuse of individual modules.

The so-called "aspect", simply put, is to encapsulate the logic or responsibility that has nothing to do with the business but is called jointly by the business module, so as to reduce the repeated code of the system, reduce the coupling degree between modules, and facilitate the operability and maintainability in the future.

Support for AOP in Spring

AOP agents in Spring are generated and managed by IoC container of Spring, and their dependencies are also managed by IoC container. Thus, the AOP agent can directly target other Bean instances in the container, a relationship that can be provided by dependency injection of the IoC container. Spring uses Java dynamic proxies by default to create AOP proxies, so you can create proxies for any interface instance. Spring automatically switches to using the CGLIB proxy or to forcing the use of CGLIB when the class to which the proxy is required is not a proxy interface.

The logic for this example is as follows: There is an Car class (business class) that logs before and after the go method in the Car class is run, but the Car class itself is not aware of any logic for logging.

Create the Maven project and add dependencies

First, create a new Maven project, use the maven templates, archetype, quickstart templates, then open the pom.xml file and add the dependencies that Spring AOP needs to run


<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>4.0.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>4.0.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.0.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>4.0.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.1</version>
</dependency>

Write business code

A new business class, Car, contains an go() method


package com.wowo.spring_aop_demo1;
public class Car {
  public void go(){
    System.out.println("go go go!");
  }
}

Write the section class

The logging class records how the system is doing, but the logging logic is not written everywhere in the business class, but exists as a facet class.


package com.wowo.spring_aop_demo1;
public class CarLogger {
  public void beforeRun(){
    System.out.println("car is going to run");
  }
  public void afterRun(){
    System.out.println("car is running");
  }
}

The section class contains two methods, one for pre-notification and the other for post-notification.

Associations are configured via bean

Add a new profile, named bean.xml in this case, to associate aspects with notifications in the profile


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context 
      http://www.springframework.org/schema/context/spring-context-2.5.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd"
  >
  <bean id="car" class="com.wowo.spring_aop_demo1.Car"/>
  <bean id="logger" class="com.wowo.spring_aop_demo1.CarLogger" />
  <aop:config>
    <aop:aspect ref="logger">
      <aop:pointcut expression="execution(* com.wowo.spring_aop_demo1.Car.go(..))" id="go"/>

      <aop:before pointcut-ref="go" method="beforeRun" />
      <aop:after pointcut-ref="go" method="afterRun" />
    </aop:aspect>
  </aop:config>
</beans>

Note: In this configuration file, the aop namespace and several addresses contained in xsi:schemaLocation are required.
execution(* com.wowo.spring_aop_demo1.Car.go(..) ) is an AspectJ pointcut expression, execution means triggered at execution time, followed by * indicates return value of any type, ES105en.wowo.spring_ES108en_ES109en1.ES110en refers to the class where the pointcut is located, go(..) Is the method name,.. Represents any parameter.

There are five types of notifications that can be applied to Spring sections:

· Before -- Call notification before the method is called
· After -- Calls the notification after the method completes, whether or not the method executes successfully
· After-returning -- Calls the notification after the method executes successfully
· ES125en-throwing -- Calls the notification after the method throws an exception
· Around -- Notifications wrap notified methods and perform custom behavior both before and after the notified method invocation

Running business code

Let's create a class that contains the main() method to run the business code


package com.wowo.spring_aop_demo1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App 
{
  public static void main( String[] args )
  {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    Car car=(Car) context.getBean("car");
    car.go();
  }
}

In the code above, an car object is created by Spring. Spring when creating the object, found that it is a method of configuring a tangent point (pointcut), so, when to instantiate the object, will create a proxy object, when go tangent point method () executes, intercept will be Spring create a proxy object, go methods before operation, will be called the cut surface of the corresponding class beforeRun CarLogger preparation method (), and then call Car. go () method, It then calls the post-method afterRun() of the faceted class CarLogger.

Note: Objects containing pointcuts must be created using Spring. If you create them yourself, Spring will not be monitored and its operation will not be notified.

The output of the project is


car is going to run
go go go!
car is running

Use surround notifications

If we want to use surround notifications, we need to modify the notification methods and configuration files in the section class without any changes to the business class because they are completely decoupled. First, modify the section class CarLogger


import org.aspectj.lang.ProceedingJoinPoint;
public class CarLogger {

  public void aroundRun(ProceedingJoinPoint joinpoint){
    System.out.println("car is going to run");
    try {
      // Calls the target method of the object being represented, which in this case points to Car.go() methods 
      joinpoint.proceed();
    } catch (Throwable e) {
      e.printStackTrace();
    }
    System.out.println("car is running");
  }
}

The method around the notification needs to accept arguments of type ProceedingJoinPoint, whose proceed() method will call the target method of the object being represented, so normally this method 1 must be called. We can also organize the run of the proxy object by not calling this method.

Next, change the aop:config section of the configuration file to look like this


<aop:config>
    <aop:aspect ref="logger">
      <aop:pointcut expression="execution(* com.wowo.spring_aop_demo1.Car.go(..))" id="go"/>
      <aop:around method="aroundRun" pointcut-ref="go"/>
    </aop:aspect>
  </aop:config>

Note: Surround notifications cannot exist at the same time as pre/post notifications. After running the code, the output remains the same.

conclusion

Above is the introduction to Spring AOP Demo to share all the content, hope to be helpful to you. Interested friends can continue to refer to other related topics in this site, if there is any deficiency, welcome to comment out. Thank you for your support!


Related articles: