💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 1. 在Springboot中,可以按以下步骤面向切面设计程序: ## 1.1. 定义切面 (Aspect)类并添加`@Aspect`注解,标识该类是一个切面类。 ``` @Aspect public class MyAspect { } ``` ## 1.2. 在切面类中定义切入点 (Pointcut)方法,使用@Pointcut注解标识,指明该方法是一个切入点方法。 ``` @Aspect public class MyAspect { @Pointcut("execution(* com.example.demo.controller.*.*(..))") public void pointcut() {} } ``` ## 1.3. 在切面类中定义通知 (Advice)方法,并通过注解指定切入点方法,标识该通知方法将要织入的切入点。支持前置通知(@Before)、后置通知(@After)、返回通知(@AfterReturning)、异常通知(@AfterThrowing)和环绕通知(@Around)。 ``` // 定义切面 @Aspect public class MyAspect { // 定义切入点 @Pointcut("execution(* com.example.demo.controller.*.*(..))") public void pointcut() {} // 定义通知 @Before("pointcut()") public void before() { System.out.println("Before advice"); } } ``` ## 1.4. 将切面类加入到Spring Ioc容器中。 可以使用@Component注解、配置类中@Bean方法或者<aop:aspectj-autoproxy />自动代理形式加入。 ``` @Component @Aspect public class MyAspect { } ``` ## 1.5. JDK动态代理或CGLIB为目标对象生成代理对象 Spring会通过JDK动态代理或CGLIB为目标对象生成代理对象,并在代理对象中织入切面,实现对目标方法的增强。 ## 1.6. 指定切面执行的顺序(如果有多个切面)。 可以使用@Order注解或者在配置类中通过@Bean的order属性指定顺序。 ``` @Aspect @Order(1) public class MyAspect1 { } @Aspect @Order(2) public class MyAspect2 { } ``` 以上就是在Springboot中面向切面设计程序的步骤和方式。通过切面、通知和切入点,可以实现`日志记录、权限校验、事务处理等横切功能,降低程序耦合,提高程序扩展性和维护性。` ## 1.7. 其他要点: 除上面提到的面向切面设计的基本步骤外,在Springboot中还有一些其他要点: ***** 1). **基于注解的切面(@Aspect)与基于XML的切面`(<aop:aspectj-autoproxy />)`可以混合使用**,Spring会自动将它们组合在一起。 2). 可以使用`AspectJ`切入点表达式语言,它比`Spring AOP`的表达式语言**更强大**,支持更复杂的切入点匹配。 3). 切入点表达式可以**匹配**方法入参,返回值类型,方法抛出的异常等。 4). 可以在通知方法中**获取织入点**方法的入参,返回值等信息。通过`JoinPoint`参数。 5). 可以在通知方法中**阻止织入点**方法的执行。仅在环绕通知中通过控制`proceed()`方法的调用来实现。 6). Spring AOP默认只会代理public方法。如果需要代理非public方法,需要设置`proxy-target-class="true"`。 7). 可以在`spring.aop.*`下设置一些AOP相关的属性,如是否使用CGLIB代理等。 8). 可以**自定义切面**,通过实现`MethodInterceptor`接口并注册到`Spring Ioc`容器来实现。 9). 目前主流的AOP框架有`AspectJ、Spring AOP`等。AspectJ性能更好,但是Spring AOP更简单易用,两者可以很好结合。 ``` @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) // 使用CGLIB代理 public class AopConfig { } @Aspect public class MyAspect { @Pointcut(...) public void pointcut() {} @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // Before advice Object result = pjp.proceed(); // 调用织入点方法 // After advice return result; } } ``` 综上,Springboot提供了基于注解和`XML`的方式来方便地面向切面设计程序,通过切面、通知、切入点的组合,使横切关注点如日志、事务、权限等与业务逻辑解耦,实现高内聚低耦合的单元,增强程序扩展性和维护性。 # 2. Spring AOP组成部分 ## 2.1. 切面(Aspect): 通知和切入点的结合。 ## 2.2. 切入点(Pointcut): 用于定义需要应用通知的连接点集合。Spring支持模糊匹配包、类型和方法。 ## 2.3. 通知(Advice): 通知方式:Before、After、After-returning、After-throwing、Around。 ## 2.4. 织入(Weaving): 将切面应用到目标对象并创建代理的过程。Spring AOP使用JDK动态代理和CGLIB来进行织入。 ## 2.5. 目标对象(Target Object): 需要应用通知的对象。 |Spring AOP的主要组成部分|说明|业务代码实现流程|技术边界| |:--:|:--:|:--:|:--:| |切面(Aspect)|通知和切入点的结合。|-|@Aspect<br>public class MyAspect{...}|将切面标注为@Aspect |切入点(Pointcut)|用于定义需要应用通知的连接点集合。Spring支持模糊匹配包、类型和方法。|<aspectj>pointcut expression</aspectj>|表达式的编写难度较大,定制性不强| |通知(Advice)| |前置通知(Before)|在切入点方法执行前执行。|@Before("pointcut expression")<br>public void before(){...}|与切入点表达式绑定 |后置通知(After)|在切入点方法执行后执行。|@After("pointcut expression")<br>public void after(){...}|与切入点表达式绑定 |返回通知(After-returning)|在切入点方法成功执行后执行。|@AfterReturning("pointcut expression")<br>public void afterReturning(){...}|与切入点表达式绑定 |异常通知(After-throwing)|在切入点方法抛出异常后执行。|@AfterThrowing("pointcut expression")<br>public void afterThrowing(){...}|与切入点表达式绑定 |环绕通知(Around)|在切入点方法执行前后执行,并决定是否执行切入点方法。|@Around("pointcut expression")<br>public void around(ProceedingJoinPoint pjp){...}|需要手动调用ProceedingJoinPoint的proceed()方法执行切入点方法 |织入(Weaving)|将切面应用到目标对象并创建代理的过程。Spring AOP使用JDK动态代理和CGLIB来进行织入。|-|Spring AOP 在运行时通过JDK动态代理或CGLIB为目标对象创建代理来织入切面|需要目标对象实现接口或为非final类 |目标对象(Target Object)|需要应用通知的对象。|-|无特殊要求|无特殊要求 # 3. AspectJ 组成部分 |组成部分|说明| |:--|:--| |Aspect|切面,用来定义切点和通知| |Pointcut|切点,匹配连接点的表达式| |Advice|通知,在切点匹配的连接点执行的动作| |Joint point|连接点,程序执行的某个点| |Weaving|织入,将Aspect应用到目标对象并创建代理的过程| ## 3.1 使用场景 |场景|示例| |:--|:--| |**日志记录**|**在方法执行前后打印日志**| |性能监控|记录方法执行时间| |事务管理|根据方法注解开启事务| |异常处理|捕获方法抛出的异常| |权限控制|检查用户权限后执行方法| ## 3.2 代码示例 ``` public aspect LoggingAspect { pointcut methodExecution() : execution(* *(..)); before() : methodExecution() { System.out.println("方法执行前..."); } after() : methodExecution() { System.out.println("方法执行后..."); } } ``` **在上例中定义了一个LoggingAspect,在所有方法执行前后打印日志。** ## 3.3 技术边界 |特征|支持|说明| |:--|:--|:--| |AOP面向切面|是|AspectJ是AOP的代表框架| |静态织入|是|在编译时将Aspect织入目标类| |动态织入|是|在运行时将Aspect织入目标类| |基于代理|是|使用JDK动态代理或CGLIB创建目标类代理| |基于字节码|是|使用ASM或AspectWerkz工具修改目标类字节码| |多语言|否|AspectJ是Java语言的AOP框架| > AspectJ是一款功能强大、具有代表性的AOP框架,它不仅展示了AOP编程模型的威力,也推动了AOP思想在企业应用中的采用和发展。但是,AspectJ仅限于Java平台,若要实现跨语言的AOP尚需其他解决方案。