SpringBoot AOP 初步理解
刚开始接触spring的时候不可避免的会提到AOP,网上一查,给你一句话就叫切面编程,个人在这里提出下我自己的一些理解以及一个例子
1.AOP
记得小时候在夏天的时候,有一次说风来吧风就来了,雨来吧雨就来了,而不需要我们去拿一个吹风机制造风,或者制造雨。那么AOP就如同我们小时候想像的咒语一样,说来就来,只需要结果不需要我去创造。
那么程序中的AOP也一样,比如AOP思想常用的事物、权限检查、日志等地方,但是AOP只能作为一个辅助并不能代理OOP(面向对象编程),说白了AOP也是基于OOP来实现的,
AOP中相关概念
- Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
- Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 joint point。
- Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方
- Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码
- Target(目标对象):织入 Advice 的目标对象
- Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程
Advice的类型
- before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码)
- after return advice, 在一个 join point 正常返回后执行的 advice
- after throwing advice, 当一个 join point 抛出异常后执行的 advice
- after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice
- around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice
- introduction,introduction可以为原有的对象增加新的属性和方法
Spring AOP Demo
1.建立Advice类实现切割点以及advice中的各个类型方法
@Aspect
@Order(-99) // 控制多个Aspect的执行顺序,越小越先执行
@Component
public class CheckUser {
@Pointcut("execution(* com.yafei.demo.*.find*(..))")
public void checkUser(){
System.out.println("**************The System is Searching Information For You****************");
}
@Pointcut("execution(* com.yafei.demo.*.add*(..))")
public void checkAdd(){
System.out.println("**************<< Add User >> Checking.....***************");
}
@Before("checkUser()")
public void beforeCheck(){
System.out.println(">>>>>>>> 准备搜查用户..........");
}
@After("checkUser()")
public void afterCheck(){
System.out.println(">>>>>>>> 搜查用户完毕..........");
}
@Before("checkAdd()")
public void beforeAdd(){
System.out.println(">>>>>>>> 增加用户--检查ing..........");
}
@After("checkAdd()")
public void afterAdd(){
System.out.println(">>>>>>>> 增加用户--检查完毕!未发现异常!..........");
}
//声明环绕通知
@Around("checkUser()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("进入方法---环绕通知");
Object o = pjp.proceed();
System.out.println("退出方法---环绕通知");
return o;
}
其中@Pointcut注解中用execution正则定义了哪些类或者方法是需要进行切入的。
2.建立User实现类进行测试
@Service
public class IUserImpl implements User {
public static Map map = null;
public static void init() {
String[] list = { "Lucy", "Tom", "小明", "Smith", "Hello" };
Map tmp = new HashMap();
for (int i = 0; i < list.length; i++) {
tmp.put(list[i], list[i] + "00");
}
map = tmp;
}
public void addUser(String username) {
init();
map.put(username, username + "11");
System.out.println("--------------【addUser】: " + username + " --------------");
System.out.println("【The new List:" + map + "】");
}
public void findAll() {
init();
System.out.println("---------------【findAll】: " + map + " ------------------");
}
public String findUser(String username) {
init();
String password = "没查到该用户";
if (map.containsKey(username)) {
password = map.get(username).toString();
}
System.out.println("-----------------【findUser】-----------------");
System.out.println("-----------------Username:" + username + "-----------------");
System.out.println("-----------------【Result】:" + password + "------------------");
return password;
}