spring AOP
官方文档: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html
要想学习理解AOP,必须先了解AOP的概念,那么AOP到底有哪些概念呢?
AOP概念:
- Aspect(切面) 下面所有的东西拼装成的一个载体(类)的统称
- Pointcut(切点) 连接点的集合
- Join point(连接点) 所要加入通知的所有方法
- Advice(通知) 告诉你(when)什么时候,(where)在哪里放入(what)什么东西
- Introduction(说明) 代表类型声明其他方法或字段
- Target object(目标对象)
- AOP proxy(代理)
- Weaving(织入) 将通知加入目标对象,生成代理对象的过程
通俗的讲: 我们可以把 Pointcut 理解成一张表,那么 Join point 就是表中的数据
AOP 通常几种通知类型:
- Before advice 在连接点之前运行,但不能阻止执行到连接点的通知(除非它抛出异常)
- After returning advice 在连接点正常完成后要运行的通知(例如:如果方法返回并且不引发异常)
- After throwing advice 如果方法通过引发异常而退出,则要执行的通知
- After (finally) advice 无论连接点退出方式如何(正常或者异常返回),都要执行的通知
- Around advice Around 环绕连接点(如方法调用) 的通知。这是最有力的通知。around通知可以在方法调用前后执行自定义行为。它还负责通过返回值或引发异常来选择是继续到连接点还是快捷地执行通知的方法
概念理解后,我们就是要怎么开始编写我们的aop:
spring aop + aspectj 结合:
1. 开启aspectj
@Configuration @EnableAspectJAutoProxy public class AppConfig { }
2. 定义一个切面
package org.xyz; import org.aspectj.lang.annotation.Aspect; @Aspect public class DemoAspect{ }
3. 在切面中加入切入点
package org.xyz; import org.aspectj.lang.annotation.*; @Aspect public class DemoAspect { @Pointcut("execution(* org.xyz.service.*.*(..))") private void test() {} }
4. 在切面中加入通知
package org.xyz; import org.aspectj.lang.annotation.*; @Aspect public class DemoAspect { @Pointcut("execution(* org.xyz.service.*.*(..))") private void testExecution() {} @Before("testExecution()") public void beforeLog() { System.out.println("----before----"); } }
这样就完成了一个aop切面的简单实现
PointCut 中有表达式区别:
- execution 用于匹配方法执行连接点(具体到类中的方法,方法参数)
- within 限制匹配到特定类型中的连接点(只能具体到类)
- this 将匹配限制为连接点,其中bean引用(aop代理)是给定类型的实例 (代理对象)
- target 限制匹配到连接点,其中目标对象(要代理的应用程序对象)是给定类型的实例 (目标对象,原对象)
- args 限制到匹配到连接点,其中参数是给定类型的实例
- @target 限制到匹配到连接点, 其中执行对象的类具有给定类型的注解
- @args 限制到匹配到连接点,其中传递的实际参数的运行时类型具有给定类型的注解
- @within 限制与具有给定注解的类型中的连接点匹配
- @annotation 限制匹配到连接点的主题,具有给定注解的连接点
例:
execution
package org.xyz; import org.aspectj.lang.annotation.*; @Aspect public class DemoAspect { @Pointcut("execution(* org.xyz.service.*.*(..))") private void testExecution() {} @Before("testExecution()") public void beforeLog() { System.out.println("----before----"); } } package org.xyz.service.login import org.springframework.stereotype.Service; @Service public class LoginService implements ILoginService { public void login() { System.out.println("login"); } public void logout() { System.out.println("logout"); } } 执行: loginService.login(); loginService.logout(); 输出: ----before---- login ----before---- logout
within :
package org.xyz; import org.aspectj.lang.annotation.*; @Aspect public class DemoAspect { @Pointcut("within(* org.xyz.service.*.*)") private void testWithin() {} @Before("testWithin()") public void beforeLog() { System.out.println("----testWithin----"); } } package org.xyz.service.login import org.springframework.stereotype.Service; @Service public class LoginService implements ILoginService { public void login() { System.out.println("login"); } public void logout() { System.out.println("logout"); } } 执行: loginService.login(); loginService.logout(); 输出: ----testWithin---- login ----testWithin---- logout
args :
package org.xyz; import org.aspectj.lang.annotation.*; @Aspect public class DemoAspect { @Pointcut("args(java.lang.String)") private void testArgs() {} @Before("testArgs()") public void beforeLog() { System.out.println("----testArgs----"); } } package org.xyz.service.login import org.springframework.stereotype.Service; @Service public class LoginService implements ILoginService { public void login() { System.out.println("login"); } public void logout(String str) { System.out.println("logout"); } } 执行: loginService.login(); loginService.logout(); 输出: login ----testArgs---- logout
this:
package org.xyz; import org.aspectj.lang.annotation.*; @Aspect public class DemoAspect { @Pointcut("this(org.xyz.service.login.LoginService)") private void testThis() {} @Before("testThis()") public void beforeLog() { System.out.println("----testThis----"); } } package org.xyz.service.login import org.springframework.stereotype.Service; @Service public class LoginService implements ILoginService { public void login() { System.out.println("login"); } public void logout() { System.out.println("logout"); } } 执行: loginService.login(); loginService.logout(); 输出: login logout
target:
package org.xyz; import org.aspectj.lang.annotation.*; @Aspect public class DemoAspect { @Pointcut("target(org.xyz.service.login.LoginService)") private void testTarget() {} @Before("testTarget()") public void beforeLog() { System.out.println("----testTarget----"); } } package org.xyz.service.login import org.springframework.stereotype.Service; @Service public class LoginService implements ILoginService { public void login() { System.out.println("login"); } public void logout() { System.out.println("logout"); } } 执行: loginService.login(); loginService.logout(); 输出: ----testTarget---- login ----testTarget---- logout