Article Directory
AOP introduction
Reference blog post
Spring AOP-aspect-oriented programming in Spring
1. What is AOP thinking?
AOP (Aspect Orient Programming), literally translated is aspect-oriented programming. AOP is a programming idea and a supplement to object-oriented programming (OOP). Object-oriented programming abstracts programs into various levels of objects, while aspect-oriented programming abstracts programs into various aspects.
Picked up a picture from the book "Spring Actual Combat (4th Edition)":
2. What is AOP generally used for
- Transaction processing: Before executing the method, open the transaction, close the transaction after the execution is completed, and roll back the transaction when an exception occurs
- Judgment of authority: before executing the method, judge whether it has authority
- Log: log processing before execution
For example, you want to record user access logs for your website:
some URLs do not need to be recorded, and some need to be recorded.
If you still use OOP, object-oriented,
then you can only use the Controller corresponding to those URLs In the code, one by one is written on the log records.
And what if you use AOP?
There is no need to add code to the control class, but directly add a log class to record logs non-invasively through aspects.
3. Advantages of AOP
- Reduce repetitive code
- Improve development efficiency
- Easy maintenance
4. AOP related terms
the term | significance |
---|---|
Joinpoint (connection point) | The so-called connection points are those points that are intercepted. In spring, these points refer to methods, because spring only supports connection points of method types. |
Pointcut (entry point) | The so-called entry point refers to the definition of which Joinpoint we want to intercept. |
Advice | The so-called notification refers to the notification after intercepting Joinpoint. Notification types: pre-notification, post-notification, exception notification, final notification, surround notification. |
Proxy | After a class is woven and enhanced by AOP, a result proxy class is generated. |
Aspect | It is a combination of entry point and notification (introduction). |
Introduction(引介) | Introduction is a special kind of notification. On the premise of not modifying the class code, Introduction can dynamically add some methods or fields to the class at runtime. |
Target | The target object of the agent. |
Configure AOP by way of annotation
1. Pointcut grammar
We use the execution indicator to select the play method of Instrument. The method expression starts with an * to indicate that we do not care about the return value type of the method. Then we specified the fully qualified class name and method name. For the method parameter list, we use... to identify the cut point to select any play method, no matter what the input parameters of the method are.
We can use more than one match between the link symbol &&
, ||
, !
to mean "and", "or" relationship "not" of. But when using XML file configuration, these symbols have special meaning, so we use " and
"," or
", " not”
to indicate.
For example:
limit the pointcut to only match the package com.sharpcj.aopdemo.test1
, you can use
execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..)) && within(com.sharpcj.aopdemo.test1.*)
Select bean in the cut point, you can use
execution(* com.sharpcj.aopdemo.test1.IBuy.buy(..)) && bean(girl)
2. Five notification types
Comment (name) | effect |
---|---|
@Before | The notification method will be executed before the target method is called |
@After | The notification method will be called after the target method returns or abnormal |
@AfterReturning | The notification method will be called after the target method returns, if an exception occurs, it will not be called |
@AfterThrowing | The notification method will be called after the target method throws an exception |
@Around (surround notification) | The notification method encapsulates the target |
3. Simple example
User class
package test_aop.pojo;
import org.springframework.stereotype.Component;
@Component
public class User {
public String point(boolean s) {
System.err.println("User.point() arg s is==" + s);
return "message";
}
}
AdviceConfig class
package test_aop.advice;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
// 一定要是用aspect注解
// true代表使用cglib代理方式(使用注解) false代表使用jdk动态代理模式
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Component
@Aspect
public class UserAdvice {
// 方法路径
final static String FUNTION_NAME = "execution(* test_aop.pojo.User.point(..))";
// 在point调用之前执行
// point参数代表当前的目标方法,我们可以通过这个参数获取目标方法的 参数,返回值等相关信息
@Before(value = FUNTION_NAME)
public void before(JoinPoint point) {
System.out.println("UserAdvice.before()");
}
// 在point调用之后执行
// point参数代表当前的目标方法,我们可以通过这个参数获取目标方法的 参数,返回值等相关信息
@After(value = FUNTION_NAME)
public void after(JoinPoint point) {
System.out.println("UserAdvice.after()");
}
// 该通知方法会目标方法返回后调用,如果出现异常则不会调用
// returning参数指定用什么参数名接受返回的值
@AfterReturning(pointcut = FUNTION_NAME, returning = "re")
public void afterReturning(Object re) {
System.out.println("UserAdvice.afterReturning() re==" + re);
}
// 该通知方法会在目标方法抛出异常后调用
// throwing参数指定用什么名称的参数接受异常
@AfterThrowing(pointcut = FUNTION_NAME, throwing = "e")
public void afterThrowing(Exception e) {
System.err.println(e);
}
// 该通知法会将目标封装起来,必须执行proceed方法,相当与放行的操作
@Around(value = FUNTION_NAME)
public void arround(ProceedingJoinPoint p) throws Throwable {
System.out.println("UserAdvice.arround() before");
p.proceed();
System.out.println("UserAdvice.arround() after");
}
}
main class
package test_aop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import test_aop.pojo.User;
@SpringBootApplication
// 扫描注解
@ComponentScan(basePackages = {
"test_aop.pojo", "test_aop.advice" })
public class App {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
User user = context.getBean(User.class);
user.point(true);
}
}
result