上一篇泛泛的讲了很多关于AOP和代理的理解,实现原理,动态和静态代理的比较,如何选择等。这篇讲到如何实践。
Spring的AOP很容易使用,查看Spring文档即可。
http://docs.spring.io/spring/docs/5.0.0.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#aop
我这里要用Spring AOP解决下面几个问题,第一,我想在系统入口,也就是RESTful的Controller的每个方法调用前和调用后分别答应一句log----“进入xyz方法”,“离开xyz方法”。第二个想要实现的功能是,我想在每个DAO的方法执行完成后知道它的执行时间---打印执行时间,这对优化性能很有帮助。第三个想要实现的功能是,我要在所有service类的方法发生异常时发送一封邮件给管理员。
这分别要用到这些advice类型:第一个功能,可以用两个方法来实现,一个Before advice,一个After advice;第二个功能可以用Around advice;第三个功能可以用After throwing advice;
这篇不想总结知识,只想贴代码,所以不解释名词,下一篇再做总结,其实Spring参考文档都说的很清楚也很好理解。
首先是需要引入的jar包,我引入了以下两个包:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
然后,如果配置Spring AOP在代码中的使用,enable AOP support
我使用的是java 源码配置的方式,需要在一个声明了@Configuration的类上声明@EnableAspectJAutoProxy,这里我新建了一个类:
@Configuration
@EnableAspectJAutoProxy
public class CommonConfiguration {
}
然后就是定义相关的Aspect,这里为每个要解决的问题定义一个Aspect类,第一个问题的解决:
注意如果是用的自动扫描Bean的配置,一定要有@Component,如果手动配置Bean则只需要@Aspect
@Aspect
@Component
public class ControllerLogAspect {
private static Logger logger = Logger.getLogger(RentingRestController.class);
@Before("execution(* com.viking.renting.rest.api.*.*(..))")
public void logMethodStart(JoinPoint point) {
String methodName = point.getSignature().getName();
logger.info("======= entering method " + methodName + "========");
}
@After("execution(* com.viking.renting.rest.api.*.*(..))")
public void logMethodEnd(JoinPoint point) {
String methodName = point.getSignature().getName();
logger.info("======= leaving method " + methodName + "========");
}
}
第二个问题的解决:
@Aspect
@Component
public class DaoLogAspect {
private static Logger logger = Logger.getRootLogger();
@Around("execution(* com.viking.renting.dao.*.*(..))")
public Object calculateMethodCostTime(ProceedingJoinPoint pjp) throws Throwable {
Object target = pjp.getTarget();
String methodName = pjp.getSignature().getName();
logger.info("*** entering " + target.getClass().getName() + ": " + methodName);
long startTime = System.currentTimeMillis();
Object retVal = pjp.proceed();
logger.info("*** leaving " + target.getClass().getName() + ": " + methodName + ", cost time:" + (System.currentTimeMillis() - startTime));
return retVal;
}
}
第三个问题的解决:
@Aspect
@Component
public class ServiceExceptionAspect {
private static Logger logger = Logger.getRootLogger();
@AfterThrowing("execution(* com.viking.renting.service.*.*(..))")
public void sendEmailWhenException(JoinPoint point) {
Object target = point.getTarget();
String methodName = point.getSignature().getName();
logger.error("exception happened in:" + target.getClass().getName() + ":" + methodName +" sending email to admin.");
}
}
代码中用到的知识点将在下一篇总结。