1.IAccountService接口和实现类
package com.service; /** * 账户业务层的接口 */ public interface IAccountService { public void saveAccount() ; }
package com.service.impl; import com.service.IAccountService; import org.springframework.stereotype.Service; /** * 账户的业务层实现类 */ @Service("accountService") public class AccountServiceImpl implements IAccountService{ public void saveAccount() { System.out.println("执行了保存"); // int i=1/0; } }
2.Logger类
package com.utils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component("logger") @Aspect//表示当前类是一个切面类 public class Logger { @Pointcut("execution(* com.service.impl.*.*(..))") private void pt1(){} /** * 前置通知 */ @Before("pt1()") public void beforePrintLog(){ System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。"); } /** * 后置通知 */ @AfterReturning("pt1()") public void afterReturningPrintLog(){ System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。"); } /** * 异常通知 */ @AfterThrowing("pt1()") public void afterThrowingPrintLog(){ System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。"); } /** * 最终通知 */ @After("pt1()") public void afterPrintLog(){ System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。"); } /** * 环绕通知 */ // @Around("pt1()") 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方法开始记录日志了。。。最终"); } }
3.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" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置spring创建容器时要扫描的包--> <context:component-scan base-package="com"></context:component-scan> <!-- 配置spring开启注解AOP的支持 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
4测试
import com.service.IAccountService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; 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(); } }
5结果
6.顺序问题
发现这里最终放在了后置的前面,这个是spring的bug,想要解决只能写环绕通知
7.基本注解
@Aspect//表明当前类是一个切面类
切入点表达式
@Pointcut(“execution(* com.service.impl..(…))”)
private void pt1(){}
@Before(“pt1()”) 前置通知
@AfterReturning(“pt1()”)后置通知
@AfterThrowing(“pt1()”)异常通知
@After(“pt1()”)最终通知
@Around(“pt1()”)环绕通知