ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 步骤 1. 导入AOP约束(命名空间). 2. 配置目标对象. 3. 配置通知对象. 4. 配置将通知织入目标对象. ## 步骤 ``` ~~~ <!-- spring 中基于XML的AOP配置步骤 1.把通知Bean也交给spring来管理. 2.使用aop:config标签表名开始AOP的配置. 3.使用aop:aspect标签表名开始AOP的配置. id属性:是给切面提供一个唯一标识. ref属性:是指定通知类bean的ID. 4.在aop:aspect标签的内部使用对应标签来配置通知的类型. 我们现在示例是让通知类的方法在切入点方法执行之前执行,所以是前置通知. aop:before :表示配置前置通知. method属性:用于指定通知类中哪个方法是前置通知. pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强 --> ~~~ ``` ## 代码 目标类: ~~~ public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("save"); } @Override public void delete() { System.out.println("delete"); } @Override public void update() { System.out.println("update"); } @Override public void get() { System.out.println("get"); } @Override public String toString() { return "UserServiceImpl{}"; } } ~~~ 通知类: ~~~ public class MyAdvice { //前置通知:目标方法运行之前调用 public void before() { System.out.println("前置通知"); } //后置通知:如果出现异常不会调用 public void afterRunning() { System.out.println("后置通知,异常不调用"); } //环绕通知:在目标方法之前和之后都调用 public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕通知之前"); //调用目标方法 Object proceed = pjp.proceed(); System.out.println("环绕通知之后"); return proceed; } //异常拦截通知:如果出现异常就会调用 public void afterException() { System.out.println("异常通知"); } //后置通知:无论是否出现异常都会调用 public void after() { System.out.println("后置通知,异常调用"); } } ~~~ 配置文件: ~~~ <?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--配置目标对象--> <bean name="userServiceTarget" class="com.like.serviceImpl.UserServiceImpl"/> <!--配置通知对象--> <bean name="myAdvice" class="com.like.aspect.MyAdvice"/> <aop:config> <!--配置切入点 public void com.like.serviceImpl.UserServiceImpl.save() //完整写法 void com.like.serviceImpl.UserServiceImpl.save() //省略public * com.like.serviceImpl.UserServiceImpl.save() //不对返回值做要求 * com.like.serviceImpl.UserServiceImpl.*() //所有方法,必须是空参 * com.like.serviceImpl.UserServiceImpl.*(..) //所有方法,任意参数,可以没参数 * ..UserServiceImpl.*(..) //当前包及其子包 * com.like.serviceImpl.*ServiceImpl.*(..) //所有方法,ServiceImpl后缀的类 * com.like.serviceImpl.*ServiceImpl.*(int) //指定int类型 * com.like.serviceImpl.*ServiceImpl.*(*) //任意类型,但是必须有参数 * com.like.serviceImpl..*ServiceImpl.*(..) //所有方法,ServiceImpl后缀的类还有它的子包 --> <aop:pointcut id="pc" expression="execution( * com.like.serviceImpl.*ServiceImpl.*(..))"/> <!--配置切面, id是切面的唯一标识.ref是通知类的引用--> <aop:aspect id="myAdvicexxxx" ref="myAdvice"> <!--指定名为before方法作为前置通知--> <aop:before method="before" pointcut-ref="pc"/> //这里是共用一个切入点了,如果使用ponitcut属性可以单独制定切入点 <!--指定名为afterRunning方法作为后置通知--> <aop:after-returning method="afterRunning" pointcut-ref="pc"/> <!--指定名为around方法作为环绕通知--> <aop:around method="around" pointcut-ref="pc"/> <!--指定名为afterException方法作为异常通知--> <aop:after-throwing method="afterException" pointcut-ref="pc"/> <!--指定名为after方法作为最终通知(有异常也通知)--> <aop:after method="after" pointcut-ref="pc"/> </aop:aspect> </aop:config> </beans> ~~~ 调用: ~~~ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userServiceTarget"); //如果符合要求,获取到的就是代理对象.是无法获取被代理对象的 System.out.println(userService); ~~~ ## 通用化切入点表达式 所有切面都能使用. 但是必须在所有切面之前. ~~~ <aop:config> <aop:pointcut id="advice" expression="execution(* com.like.service.impl.*ServiceImpl.*(..))"/> <aop:aspect ref="logger"> <aop:around method="around" pointcut-ref="advice"/> </aop:aspect> </aop:config> ~~~ ## 单个切面使用 ~~~ <aop:config> <aop:aspect ref="logger"> <aop:pointcut id="ad1" expression="execution(* com.like.service.impl.*ServiceImpl.*(..))"/> <aop:around method="around" pointcut-ref="ad1"/> </aop:aspect> </aop:config> ~~~ ## 单个方法切入点表达式 ~~~ <aop:config> <aop:aspect ref="logger"> <aop:around method="around" pointcut="execution(* com.like.service.impl.*ServiceImpl.*(..))"/> </aop:aspect> </aop:config> ~~~ ## 注解方式 ~~~ <?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--配置目标对象--> <bean id="userServiceTarget" class="com.like.serviceImpl.UserServiceImpl"/> <!--配置将通知织入目标对象--> <bean id="myAdvice" class="com.like.aspect.MyAdvice"/> <!--开启使用注解完成织入--> <aop:aspectj-autoproxy/> </beans> ~~~ ~~~ package com.like.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; //用该注解表示是通知类 @Aspect public class MyAdvice { @Pointcut("execution( * com.like.serviceImpl.*ServiceImpl.*(..))") public void pc(){} //指定该方法是前置通知,并指定切入点 @Before("execution( * com.like.serviceImpl.*ServiceImpl.*(..))") public void before() { System.out.println("前置通知"); } //后置通知:如果出现异常不会调用 @AfterReturning("MyAdvice.pc()") //这是简写方法,这样讲就不用为每个通知都指定范围了 public void afterRunning() { System.out.println("后置通知,异常不调用"); } //环绕通知:在目标方法之前和之后都调用 @Around("execution( * com.like.serviceImpl.*ServiceImpl.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕通知之前"); //调用目标方法 Object proceed = pjp.proceed(); System.out.println("环绕通知之后"); return proceed; } //异常拦截通知:如果出现异常就会调用 @AfterThrowing("execution( * com.like.serviceImpl.*ServiceImpl.*(..))") public void afterException() { System.out.println("异常通知"); } //最终通知:无论是否出现异常都会调用 @After("execution( * com.like.serviceImpl.*ServiceImpl.*(..))") public void after() { System.out.println("后置通知,异常调用"); } } ~~~ ## 注意 后置通知和一场通知最终只能执行一个.