Concept and understanding of AOP: Understanding aspect oriented programming (AOP) by drawing
AOP terminology and XML configuration quick start
(1) Create target interface and implementation class
package com.ssm.aop.service; import com.ssm.aop.game.Role; public interface RoleService { public void printRole(Role role); }
package com.ssm.aop.service.Impl; import com.ssm.aop.game.Role; import com.ssm.aop.service.RoleService; import org.springframework.stereotype.Component; @Component public class RoleServiceImpl implements RoleService { @Override public void printRole(Role role) { System.out.println("{id: "+role.getId()+", " +"role_name:"+role.getRoleName()+", " +"note:"+role.getNote()+"}"); } }
(2) Create a facet class (a method to enhance the target class)
package com.ssm.aop.aspect; import org.aspectj.lang.annotation.*; @Aspect public class RoleAspect { @Before("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))") public void before() { System.out.println("before..."); } @After("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))") public void after() { System.out.println("after..."); } @AfterReturning("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))") public void afterReturning() { System.out.println("afterReturning..."); } @AfterThrowing("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))") public void afterThrowing() { System.out.println("afterThrowing..."); } }
Adding the @ Aspect annotation above the class indicates that the class is a faceted class
@Before: the method of adding the annotation indicates that the method is called before the method of the proxy object, that is, the pre notification.
@After: the method of adding the annotation indicates that the method is called after the method of the proxy object, that is, post notification.
@AfterReturning: the method of adding the annotation indicates that the method is called after the method of the proxy is returned normally.
@AfterThrowing: the method of adding the annotation indicates that the method is invoked after throwing an exception in the method of the proxy.
The configuration item in the parentheses of the annotation on the method (defining the regular expression of execution to match the corresponding tangent point) is used to define the tangent point:
Syntax of expression:
execution([modifier] return value type package name. Class name. Method name (parameter))
- Access modifiers can be omitted
- The return value type, package name, class name and method name can be represented by *
- A point between the package name and the class name Represents the class under the current package, two points Represents the classes under the current package and its sub packages
- The parameter list can use two points Represents any number and any type of parameter list.
Take the following expression as an example:
execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))
execution: triggered when the method is executed
*: represents a method of any return type
com.ssm.aop.service.Impl.RoleServiceImpl: represents the fully qualified name of the class
printRole: the name of the intercepted method
(..): Arbitrary parameters
In the above facet class, the definition of the Pointcut is repetitive code, which is troublesome. You can avoid this trouble by introducing @ Pointcut to define a Pointcut
Define @ Pointcut annotation above a method without any logic, and the configuration item is the expression of tangent point. When in use, just configure the method name without logic in the configuration item.
The improved code is as follows
package com.ssm.aop.aspect; import org.aspectj.lang.annotation.*; @Aspect public class RoleAspect { @Pointcut("execution(* com.ssm.aop.service.Impl.RoleServiceImpl.printRole(..))") public void print() { } @Before("print()") public void before() { System.out.println("before..."); } @After("print()") public void after() { System.out.println("after..."); } @AfterReturning("print()") public void afterReturning() { System.out.println("afterReturning..."); } @AfterThrowing("print()") public void afterThrowing() { System.out.println("afterThrowing..."); } }
(3) Disposition
To make the above annotation effective, you must first start AspectJ automatic proxy, so that Spring can generate dynamic proxy objects.
The configuration code is as follows:
package com.ssm.aop.config; import com.ssm.aop.aspect.RoleAspect; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy @ComponentScan("com.ssm.aop") public class AopConfig { @Bean public RoleAspect getRoleAspect() { return new RoleAspect(); } }
@EnableAspectJAutoProxy
@Bean
public RoleAspect getRoleAspect()
{
return new RoleAspect();
}
This part of the code represents the automatic agent that starts the AspectJ framework
Another way to enable automatic proxy is through XML configuration:
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <aop:aspectj-autoproxy/> <bean id="roleAspect" class="com.ssm.aop.aspect.RoleAspect"/> <bean id="roleService" class="com.ssm.aop.service.Impl.RoleServiceImpl"/> </beans>
You can see that the RoleAspect aspect class and RoleServiceImpl target class are added to the Ioc container as beans in XML, which is equivalent to @ Bean and @ Component in the annotation
< AOP: AspectJ AutoProxy > has the same function as the annotation @ EnableAspectJautoProxy, enabling the automatic proxy function.
(4) Testing
The test code is as follows:
import com.ssm.aop.config.AopConfig; import com.ssm.aop.game.Role; import com.ssm.aop.service.RoleService; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);//Configure using config class // ApplicationContext ctx=new ClassPathXmlApplicationContext("application-config.xml");// Using XML configuration files RoleService roleService = (RoleService) ctx.getBean(RoleService.class); Role role = new Role(); role.setId(1L); role.setRoleName("role_name_1"); role.setNote("note_1"); roleService.printRole(role); System.out.println("####################"); //Test exception notification role = null; roleService.printRole(role); } }
The operation results are shown in the figure below;
An empty object was deliberately created in the test code to trigger the exception notification.
In the absence of errors, you can see first calling the pre notification, then calling the printRole method, calling the notification returned successfully, and finally calling the post notification.
When an exception is thrown, the first notification is invoked and then an exception occurs when the pringRole method is invoked. Then the exception notification is sent to output afterThrowing and finally the post notification is invoked.
In other words, the post notification will be called whether the call to pringRole is successful or not.