Catalog
9.2 AOP configuration for Spring
9.2.2 Writing of pointcut expressions
9.2.3 Configuration File Modification
9.3 Five notification types of Spring AOP (using XML)
9.4 Spring AOP Annotation Configuration for Five Notification Types
9.4.2 ConfigurationContext.java
9. AOP in Spring
9.1 Details of AOP
9.1.1 Terminology of AOP
Joinpoint: (method)
Connection points are those intercepted. In spring, these points refer to methods, because spring only supports join points of method types.
All methods in the target object are join points.
Pointcut (entry point): (method)
The entry point is the definition of which Joinpoint s we want to intercept.
Some methods in the target object: Enhanced methods are entry points.
Advice (Notification/Enhancement): (Method)
Notification is what happens when Joinpoint is intercepted.
Types of notifications: pre-notification, post-notification, exception notification, final notification, surround notification.
Notification is the way to enhance.
Target (target object):
The target object of the agent.
Weaving (weaving):
The process of applying enhancements to target objects to create new proxy objects.
spring uses dynamic proxy weaving, while AspectJ uses compile-time weaving and class-loading weaving.
Proxy (Agent):
When a class is enhanced by AOP weaving, a result proxy class is generated.
Aspect: (section): (class)
It is a combination of entry point and notification (introduction).
Notification methods need to be placed in a class, which is facet.
Introduction (Introduction):
Introduction s are special notifications that dynamically add methods or fields to a class at run time without modifying the class code.
9.2 AOP configuration for Spring
[Requirements] Add log operations before accessing methods in AccountServiceImpl.java
9.2.1 applicationContext.xml
<! - Create Service (Target Object) --> <bean id="accountService" class="com.cpz.service.impl.AccountServiceImpl"></bean> <! - Spring's aop configuration, specifying aspects (classes), notifications (methods), entry points (methods)--> Create Logger (Aspect without Soul)--> <bean id="logger" class="com.cpz.utils.Logger"></bean> <! - Introduce aop space and configure spring's aop - >. <aop:config> <!-2: Configuration entry point Expression: An expression that defines a pointcut Parametric 1: Access modifier (not required) Parametric 2: Return value (required) Parametric 3: Package name. Class name (not required). It is recommended to write, if not, that all classes are entry points. Parameter 4: Method name (parameter) (required) Parametric 5: Exceptions (not required) Access modifier return value package name, package name, package name, class name, method name (parameter list) --> <aop:pointcut id="myPointcut" expression="execution(public void com.cpz.service.impl.AccountServiceImpl.saveAccount())"></aop:pointcut> <!--<aop:pointcut id="myPointcut1" expression="execution(public void com.cpz.service.impl.AccountServiceImpl.updateAccount(int))"></aop:pointcut>--> <!--<aop:pointcut id="myPointcut2" expression="execution(public int com.cpz.service.impl.AccountServiceImpl.deleteAccount())"></aop:pointcut>--> <!-1: Configuration of facets (facets with souls)--> <aop:aspect id="myAspect" ref="logger"> <!-3: Configuration notification (Pre-notification: Executing notification before accessing the target object method) Method=": method name of notification --> <aop:before method="printLog" pointcut-ref="myPointcut"></aop:before> <!--<aop:before method="printLog" pointcut-ref="myPointcut1"></aop:before>--> <!--<aop:before method="printLog" pointcut-ref="myPointcut2"></aop:before>--> </aop:aspect> </aop:config>
9.2.2 Writing of pointcut expressions
Keyword: execution expression:
Parametric 1: Access modifier (not required)
Parametric 2: Return value (required)
Parametric 3: Package name. Class name (not required)
Parametric 4: Method name (parameter) (required)
Parametric 5: Exception (not mandatory) access modifier return value package name. package name. package name... class name. method name (parameter list)
Standard expression writing: public void com.cpz.service.impl.AccountServiceImpl.saveAccount() Access modifiers can be omitted void com.cpz.service.impl.AccountServiceImpl.saveAccount() The return value can use wildcards (*: for arbitrary) to represent any return value. * com.cpz.service.impl.AccountServiceImpl.saveAccount() Package names can use wildcards to represent arbitrary packages. But if you have several levels of packages, you need to write a few *. * *.*.*.*.AccountServiceImpl.saveAccount()) The package name can be used to represent the current package and its subpackages. * *..AccountServiceImpl.saveAccount() Class names and method names can be wildcarded using * (which is not normally configurable) * *..*.*() == * *() List of parameters: Data types can be written directly: Basic Type Writes Name Directly int Write package names by reference type. The way class names are written java.lang.String Wildcards can be used to represent any type, but they must have parameters You can use... to indicate whether parameters are available or not, and parameters can be of any type. Full wildcard: * *. *. * (.) Common way to write pointcut expressions in actual development: all methods cut under the business layer implementation class: * com.cpz.service. *. * (.)
9.2.3 Configuration File Modification
<aop:config> <aop:pointcut id="myPointcut" expression="execution(* com.cpz.service..*.*(..))"></aop:pointcut> <aop:aspect id="myAspect" ref="logger"> <aop:before method="printLog" pointcut-ref="myPointcut"></aop:before> </aop:aspect> </aop:config>
9.3 Five notification types of Spring AOP (using XML)
Pre-notification, post-notification, exception notification, final notification, surround notification.
9.3.1 Logger.java
package com.cpz.utils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class Logger { // Before advice public void beforePrintLog(JoinPoint jp){ System.out.println("Pre-notification class name:" + jp.getSignature().getDeclaringTypeName().getName() + ", Method name:" + jp.getSignature().getName()); } // after returning advise public void afterReturningPrintLog(JoinPoint jp){ System.out.println("Post Notification Class Name:" + jp.getSignature().getDeclaringTypeName().getName() + ", Method name:" + jp.getSignature().getName()); } // Exception Notification public void afterThrowingPrintLog(JoinPoint jp){ System.out.println("Exception notification class name:" + jp.getSignature().getDeclaringTypeName().getName() + ", Method name:" + jp.getSignature().getName()); } // Final Notice public void afterPrintLog(JoinPoint jp){ System.out.println("Final Notification Class Name:" + jp.getSignature().getDeclaringTypeName().getName() + ", Method name:" + jp.getSignature().getName()); } // Around Advice public Object aroundPrintLog(ProceedingJoinPoint pjp){ Object returnValue = null; try{ beforePrintLog(pjp); returnValue = pjp.proceed(pjp.getArgs()); afterReturningPrintLog(pjp); return returnValue; } catch (Throwable throwable) { throwable.printStackTrace(); afterThrowingPrintLog(pjp); } finally { afterPrintLog(pjp); } return returnValue; } }
9.3.2 applicationContext.java
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <bean id="accountService" class="com.cpz.service.impl.AccountServiceImpl"></bean> <bean id="logger" class="com.cpz.utils.Logger"></bean> <aop:config> <aop:pointcut id="myPointcut" expression="execution(* com.cpz.service..*.*(..))"></aop:pointcut> <aop:aspect id="myAspect" ref="logger"> <!--<aop:before method="beforePrintLog" pointcut-ref="myPointcut"></aop:before>--> <!--<aop:after-returning method="afterReturningPrintLog" pointcut-ref="myPointcut"></aop:after-returning>--> <!--<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="myPointcut"></aop:after-throwing>--> <!--<aop:after method="afterPrintLog" pointcut-ref="myPointcut"></aop:after>--> <aop:around method="aroundPrintLog" pointcut-ref="myPointcut"></aop:around> </aop:aspect> </aop:config> </beans>
9.4 Spring AOP Annotation Configuration for Five Notification Types
9.4.1 Logger.java
package com.cpz.utils; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component(value = "logger") @Aspect public class Logger { @Pointcut("execution(* com.cpz.service..*.*(..))") private void myPointcut(){} // Before advice //@Before(value = "myPointcut()") public void beforePrintLog(JoinPoint jp){ System.out.println("Pre-notification class name:" + jp.getSignature().getDeclaringTypeName() + ", Method name:" + jp.getSignature().getName()); } // after returning advise //@AfterReturning(value = "myPointcut()") public void afterReturningPrintLog(JoinPoint jp){ System.out.println("Post Notification Class Name:" + jp.getSignature().getDeclaringTypeName() + ", Method name:" + jp.getSignature().getName()); } // Exception Notification //@AfterThrowing(value = "myPointcut()") public void afterThrowingPrintLog(JoinPoint jp){ System.out.println("Exception notification class name:" + jp.getSignature().getDeclaringTypeName() + ", Method name:" + jp.getSignature().getName()); } // Final Notice //@After(value = "myPointcut()") public void afterPrintLog(JoinPoint jp){ System.out.println("Final Notification Class Name:" + jp.getSignature().getDeclaringTypeName() + ", Method name:" + jp.getSignature().getName()); } // Around Advice @Around(value = "myPointcut()") public Object aroundPrintLog(ProceedingJoinPoint pjp){ Object returnValue = null; try{ beforePrintLog(pjp); returnValue = pjp.proceed(pjp.getArgs()); afterReturningPrintLog(pjp); return returnValue; } catch (Throwable throwable) { throwable.printStackTrace(); afterThrowingPrintLog(pjp); } finally { afterPrintLog(pjp); } return returnValue; } }
9.4.2 ConfigurationContext.java
package com.cpz.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan(basePackages = "com.cpz") @EnableAspectJAutoProxy public class ConfigurationContext { }