定义切面类
package world.xuewei.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; /** * 自定义切面类 * * @author 薛伟 * @since 2023/10/23 9:45 */ @Aspect public class MyAspect { /** * 定义切入点方法,方法体内编写额外功能 * 注解 @Around:用于定义切入点,编写切入点表达式 */ @Around(value = "execution(* *(..))") public Object around(ProceedingJoinPoint joinPoint) { // 在此处编写前置操作 System.out.println("Before"); Object result = null; try { result = joinPoint.proceed(); } catch (Throwable e) { // 在此处编写异常操作 System.out.println("Exception"); } // 在此处编写后置操作 System.out.println("After"); // 可以在此处编写新的返回值并返回 return result; } }
Spring 配置文件
<?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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 开启 AOP 注解驱动开发 --> <aop:aspectj-autoproxy/> <!-- 注册原始对象 --> <bean id="userService" class="world.xuewei.proxy.UserServiceImpl"/> <!-- 注册自定义切面类 --> <bean id="around" class="world.xuewei.aspect.MyAspect"/> </beans>
切入点复用
package world.xuewei.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; /** * 自定义切面类 * * @author 薛伟 * @since 2023/10/23 9:45 */ @Aspect public class MyAspect { /** * 单独定义切入点,只需要关注注解 */ @Pointcut("execution(* *(..))") public void p1() { } /** * 定义切入点方法,方法体内编写额外功能 * 注解 @Around:用于定义切入点,编写切入点表达式 */ @Around(value = "p1()") public Object around(ProceedingJoinPoint joinPoint) { // 在此处编写前置操作 System.out.println("Before"); Object result = null; try { result = joinPoint.proceed(); } catch (Throwable e) { // 在此处编写异常操作 System.out.println("Exception"); } // 在此处编写后置操作 System.out.println("After"); // 可以在此处编写新的返回值并返回 return result; } @Around(value = "p1()") public Object around1(ProceedingJoinPoint joinPoint) { // 在此处编写前置操作 System.out.println("Before"); Object result = null; try { result = joinPoint.proceed(); } catch (Throwable e) { // 在此处编写异常操作 System.out.println("Exception"); } // 在此处编写后置操作 System.out.println("After"); // 可以在此处编写新的返回值并返回 return result; } }
强制使用 Cglib 动态代理
<aop:aspectj-autoproxy proxy-target-class="true"/>
坑:代理方法调用
在同一个业务类中,进行业务方法间的调用时,只有最外层的方法才是通过代理对象调用的(加入了额外功能),内部调用的本类的其他方法都是通过原始对象调用,如果想要让内部的方法也通过代理对象调用,那么就需要实现 ApplicationContextAware 接口。
package world.xuewei.proxy; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 用户服务实现 * * @author 薛伟 * @since 2023/10/18 17:49 */ public class UserServiceImpl implements UserService, ApplicationContextAware { private ApplicationContext context; @Override public void register() { System.out.println("UserServiceImpl.register"); UserService p = context.getBean(、"userService", UserService.class); p.login(); } @Override public void login() { System.out.println("UserServiceImpl.login"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; } }