spring中的环绕通知:它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
1、 创建maven的jar工程,导入依赖坐标
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> </dependencies>
2、 编写业务层的接口
public interface IAccountService { /** * 模拟保存账户 */ void saveAccount(); }
3、编写业务层接口的实现类:
public class AccountServiceImpl implements IAccountService{ @Override public void saveAccount() { System.out.println("执行了保存"); // int i=1/0; } }
4、 创建一个具有公共代码的类:
public class Logger { public Object aroundPringLog(ProceedingJoinPoint pjp){ Object rtValue = null; try{ Object[] args = pjp.getArgs();//得到方法执行所需的参数 System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置"); rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法) System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置"); return rtValue; }catch (Throwable t){ System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常"); throw new RuntimeException(t); }finally { System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终"); } } }
Spring框架为我们提供了一个接口ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
写在proceed之前表示前置通知,写在proceed之后表示后置通知,写在catch中表示异常通知,写在finally中表示最终通知。
之前的四种通知类型,都是通过配置的方式来指定增强的代码什么时候来执行。现在的环绕通知是使用代码控制的方式来指定增强的代码何时执行。即可以通过配置来实现也可以通过编码来实现。
5、编写配置文件bean.xml
<?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 http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置srping的Ioc,把service对象配置进来--> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean> <!-- 配置Logger类 --> <bean id="logger" class="com.itheima.utils.Logger"></bean> <!--配置AOP--> <aop:config> <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut> <!--配置切面 --> <aop:aspect id="logAdvice" ref="logger"> <!-- 配置环绕通知 详细的注释请看Logger类中--> <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around> </aop:aspect> </aop:config> </beans>
创建logger对象是因为配置切面时需要引用logger对象,如果使用注解的AOP,则不需要@Component注解。
6、测试:
public class AOPTest { public static void main(String[] args) { //1.获取容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.获取对象 IAccountService as = (IAccountService)ac.getBean("accountService"); //3.执行方法 as.saveAccount(); } }
结果: