Knowledge point induction
1. Introduction and use of AOP entry point expressions
2. Examples to introduce the execution order of notifications
3. Round-based notification execution
4. Spring aop based on xml configuration
4. Which is better based on annotation and xml?
AOP entry point expression
Spring aop supports the realization of AspectJ cut-off identifiers, which are used to cut-off expressions. The most used are 1, 2, 4.
1. Execution is used to match method connection points, the most used pointcut identifier, can be matched to the method level, fine-grained. Based on method.
@Before(“execution(* cn.allen.service.impl.*.*(..))”)
2. @annotation matches which methods have this annotation on them. Based on annotations.
@Before(“@annotation(jdk.nashorn.internal.runtime.logging.Logger)”)
3. @within can only match up to the class level, and there is a certain annotation on the companion class.
4. This is used to match the class that implements an interface. Based on the interface.
5. args are matched by parameters.
The expression merges && || !, corresponding to AND or NOT
@Before(“execution(* cn.allen.service.impl.*.*(..)) && @annotation(jdk.nashorn.internal.runtime.logging.Logger)")
Execution order of Spring AOP notifications
Execution sequence: pre-position -> post-position -> post-abnormal -> post-return
正常: @Before -> Method -> @After -> @AfterReturning
异常:@Before -> Method -> @After -> @AfterThrowing
Example descriptions of pre-notification, post-notification, post-return notification, and post-abnormal notification.
Add a knowledge point, JoinPoint is the link point we mentioned earlier, in which you can get some specific information inside the method, such as method name, method parameters, specific examples are as follows
The pre-notification @Before will be executed before the called method.
Post notification @After, executed after the called method
The post-return notification @AfterReturning is executed before the called method is about to complete and the structure is returned.
The post-exception pass @AfterThrowing, which will be executed when the called method sends a real exception.
@Component
@Aspect
public class LogAspect {
@Before("execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))")
public void before(JoinPoint point){
System.out.println("@Before --- "+ point.getArgs()[0] + " is the name for a candidate girl!");
}
@After("execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))")
public void after(JoinPoint point){
System.out.println("@Before --- "+ point.getSignature().getName() + " was been called just now!");
}
@AfterReturning(value = "execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))", returning = "returnVal")
public void afterReturn( Object returnVal){
XiaoJieJie xiaojiejie = (XiaoJieJie)returnVal;
System.out.println("@AfterReturning --- "+ xiaojiejie.getName() + " have been returned !");
}
@AfterThrowing(value = "execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))", throwing = "errorInfo")
public void afterException(Exception errorInfo){
StringWriter sw = new StringWriter();
errorInfo.printStackTrace(new PrintWriter(sw,true));
System.out.println("@AfterThrowing --- unexpected result happens, please check !!!" + sw.getBuffer().toString() );
}
}
There are 2 cut methods, getByage and getByName:
@Repository
public class GetXiaoJieJieDaoImpl implements GetXiaoJieJieDao {
public XiaoJieJie getByAge(Integer age){
System.out.println("--- method getByAge is been calling ---!");
if (age==null){
throw new RuntimeException("age is null ,please check");
}
return new XiaoJieJie("Lucy",age);
}
public XiaoJieJie getByName(String name){
System.out.println("--- method getByName is been calling ---!");
return new XiaoJieJie(name,18);
}
}
test:
public class TestAop {
public static void main(String[] args) {
ClassPathXmlApplicationContext xml = new ClassPathXmlApplicationContext("spring.xml");
GetXiaoJieJieDao findXiaojiejie = xml.getBean(GetXiaoJieJieDao.class);
XiaoJieJie girl = findXiaojiejie.getByName("lulu");
girl.play();
findXiaojiejie.getByAge(null);
}
}
Results of the:
@Before --- lulu is the name for a candidate girl!
--- method getByName is been calling ---!
@Before --- getByName was been called just now!
@AfterReturning --- lulu have been returned !
my Master, I am lulu ,18 years old, will you play with me
@Before --- null is the name for a candidate girl!
--- method getByAge is been calling ---!
@Before --- getByAge was been called just now!
@AfterThrowing --- unexpected result happens, please check !!!java.lang.RuntimeException: age is null ,please check
at com.allen.trainning.spring.aop.dao.impl.GetXiaoJieJieDaoImpl.getByAge(GetXiaoJieJieDaoImpl.java:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
Each of the above notification methods has written its own pointcut expression, and they are all the same, which looks very inelegant. Pointcut variables, this concept can help us solve this problem. At this time, we use the pointcut annotation @PointCut, as follows
@Pointcut("execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))")
public void pointCut(){
}
Therefore, the pointcut expressions on the above notifications can be replaced with pointCut().
@Before("pointCut()")
@After("pointCut()")
@AfterReturning(value = "pointCut()", returning = "returnVal")
@AfterThrowing(value = "pointCut()", throwing = "errorInfo")
Use of Surround Notification @Around
The surrounding notification is simply a notification to replace the above four notifications, the specific implementation is as follows:
@Component
@Aspect
public class LogAspectPointCut {
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinpoint) {
String methodName = joinpoint.getSignature().getName(); //获取方法名字
String paraValue = (String)joinpoint.getArgs()[0];//获取方法参数
Object object = null;
try {
System.out.println("前置通知" + methodName+ paraValue);
object = joinpoint.proceed();
System.out.println("前置通知");
} catch (Throwable throwable) {
System.out.println("异常通知");
} finally {
System.out.println("返回通知");
}
return object;
}
}
Results of the:
前置通知 方法名:getByName 参数:lulu
--- method getByName is been calling ---!
后置通知
返回通知
my Master, I am lulu ,18 years old, will you play with me
前置通知 方法名:getByAge 参数:null
--- method getByAge is been calling ---!
异常通知
返回通知
Process finished with exit code 0
Configure AOP based on XML
You cannot use && in xml, you need to escape &&
The specific configuration is as follows:
The first step is to remove the configuration of the enable aop annotation
<aop:aspectj-autoproxy/>
The second step is to configure the aopconfig
<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.allen.trainning.spring.aop"/>
<aop:config>
<aop:aspect ref="logAspect">
<aop:pointcut id="logPointcut" expression="execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))"></aop:pointcut>
<aop:before method="before" pointcut="execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))&&execution(* com.allen.trainning.spring.aop.dao.impl.*.*(Integer))"></aop:before>
<aop:after method="after" pointcut-ref="logPointcut"></aop:after>
<aop:after-returning method="afterReturn" pointcut-ref="logPointcut" returning="returnVal"></aop:after-returning>
<aop:after-throwing method="afterException" throwing="errorInfo" pointcut-ref="logPointcut"></aop:after-throwing>
</aop:aspect>
</aop:config>
<aop:config>
<aop:aspect ref="logAspectPointCut">
<aop:pointcut id="logPointcut" expression="execution(* com.allen.trainning.spring.aop.dao.impl.*.*(..))"></aop:pointcut>
<aop:around method="around" pointcut-ref="logPointcut" ></aop:around>
</aop:aspect>
</aop:config>
</beans>
The test result, which is the same as the commented test result, will not be posted twice.
What about annotations and xml, it was annotations at the time
As follows, annotations can merge multiple pointcut expressions defined by themselves, xml does not work
Annotations are also relatively simple and convenient to use.
Interview questions:
1. Which are the spring aop notification types?
2. What are the steps of annotation and xml implementation?