Before reading this article, you can refer to the article " Simple understanding of Spring's IOC and AOP and Code Examples " to briefly understand the relevant content of IOC and AOP. Let’s get to the topic.
This article will create the simplest example step by step to use Spring's AOP features, which is considered a beginner demo of Spring AOP. As a beginner, running such a simple demo has also been hit by many pitfalls.
OOP's problem, supplementary to AOP
When we need to introduce public behavior to scattered objects, OOP seems powerless. That is, OOP allows you to define relationships from top to bottom, but is not suitable for defining relationships from left to right. For example, logging function. Log code is often scattered horizontally across all object levels without any relation to the core functionality of the object to which it is scattered. The same is true for other types of code, such as security, exception handling, and transparency. This kind of irrelevant code scattered everywhere is called cross-cutting code. In OOP design, it causes a lot of code duplication, which is not conducive to the reuse of each module.
The so-called "aspect", simply put, encapsulates logic or responsibilities that are not related to the business but are called jointly by the business module, which facilitates reducing the system's duplication of code, reducing the coupling between modules, and promoting future operability and maintainability.
Support for AOP in Spring
The AOP agent in Spring is responsible for generation and management of Spring's IoC containers, and its dependencies are also managed by the IoC containers. Therefore, the AOP proxy can directly target other Bean instances in the container, and this relationship can be provided by dependency injection of the IoC container. Spring uses Java dynamic proxy to create AOP proxy by default, so that it can create proxy for any interface instance. When the class that needs a proxy is not a proxy interface, Spring will automatically switch to using CGLIB proxy, and it can also force CGLIB.
The logic of this example is as follows: There is a Car class (business class). Before and after the go method in the Car class is run, there will be corresponding log records, but the Car class itself does not know any logic of the log.
Create a Maven project and add dependencies
First, create a new Maven project, use the mavenarchetypequickstart template, then open the pom.xml file, and add the dependency packages required for Spring AOP 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-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>
Writing business code
Added a business class Car, including a go() method
package com.wowo.spring_aop_demo1;public class Car { public void go(){ System.out.println("go go go!"); }}Write facets
The log class will record the operation of the system, but the log logic will not be 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"); }}This aspect class contains two methods, namely the pre-notification and the post-notification.
Configure associations through beans
Added a new configuration file, named bean.xml in this example, to associate the face and notifications in the configuration file
<?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"/> <bean id="logger" /> <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 namespace of aop and several addresses contained in xsi:schemaLocation are required.
execution(* com.wowo.spring_aop_demo1.Car.go(..)) is an AspectJ point-cut expression. execution means triggering during execution. The following * represents the return value of any type. com.wowo.spring_aop_demo1.Car refers to the class where the point-cut is located. go(..) is the method name, and... represents any parameter.
There are 5 types of notifications that can be applied to Spring sections:
・Before--Call notification is called before the method is called
・After--A notification is called after the method is completed, regardless of whether the method is executed successfully.
・After-returning--Call notification is called after the method is successfully executed
・After-throwing--Call notification after the method throws an exception
・Around--Notification packages the notified method, and performs custom behavior before and after the notified method call.
Run business code
Below is a class containing 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 above code, a car object is created by Spring. When Spring creates this object, it finds that one of its methods is configured as pointcut. Therefore, when instantiating the object, a proxy object will be created. When the point-cut method go() is executed, it will be intercepted by the proxy object created by Spring. Before running the go method, it will call the corresponding pre-process CarLogger's corresponding pre-process beforeRun(), then call the Car.go() method, and then call the post-process of the section-cut class CarLogger afterRun().
Note: Spring must be used to create an object containing tangents. If you create it yourself, Spring cannot monitor it and its operation will not be notified by applying any application.
The output result of the project is
car is going to rungo go go!car is running
Use Surround Notifications
If you want to use surround notifications, we need to modify the notification methods and configuration files in the aspect class. The business class does not need to make any modifications 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 { //Calling the target method of the proxy object, in this example pointing to the Car.go() method joinpoint.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("car is running"); }}The method surrounding notification needs to accept parameters of type ProceedingJoinPoint, and its process() method will call the target method of the proxy object, so under normal circumstances, this method must be called. We can also organize the run of the proxy object by not calling this method.
Next, modify the aop:config part of the configuration file to the following
<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 front/back notifications. After running the code, the output result remains unchanged.
Summarize
The above is all the content shared by this article about the introduction to Spring AOP Demo, I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!