|  | 本文参考《精通Spring:JavaWeb开发技术详解》,作者:孙卫琴,清华大学出版社出版 
 Spring AOP依赖AspectJ软件包来实现。AspectJ软件包由Eclipse公司提供,它的下载网址为:
 https://www.eclipse.org/aspectj/downloads.php
 
 把AspectJ软件包的类库文件拷贝到helloapp/WEB-INF/lib目录下。
 
 org.aspectj.lang.JoinPoint类,以及@Aspect和@Poincut等注解都来自于AspectJ类库。
 
 在本范例中,把输出日志的代码块作为增强代码块。需要插入该增强代码块的原始方法是控制器类中所有用@LogAnnotation注解标识的请求处理方法。@LogAnnotation注解是自定义的注解,例程1是它的源程序
 
 例程1 LogAnnotation.java
 | package mypack; import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 //指定注解可用来标识类的方法
 @Target({ElementType.METHOD})
 
 //指定注解的生命周期
 @Retention(RetentionPolicy.RUNTIME)
 public @interface LogAnnotation {
 //为注解定义了一个desc属性,指定原始方法的描述信息
 String desc() default "无描述信息";
 }
 | 
 以下例程2的LogTesterController类的logtest()请求处理方法用@LogAnnotation注解来标识。
 
 例程2 LogTesterController.java
 
 
 | @Controller public class LogTesterController{
 @RequestMapping("/logtest")
 @LogAnnotation(desc="logtest():测试日志方法")
 public String logtest(
 @RequestParam(required=false,defaultValue="1")int num,
 Modelmodel)  {
 
 System.out.println("from logtest():begin");
 model.addAttribute("output",100/num);
 System.out.println("from logtest():end");
 
 return"result";
 }
 }
 | 
 以下例程3的SystemLogAscpect类是切面类,它有一个切点“logPointCut()”,这个切点指定需要增强功能的原始方法为所有用@LogAnnotation注解标识的方法。
 
 例程3 SystemLogAspect.java
 
 
 | @Aspect @Component
 public class SystemLogAspect {
 //日志记录对象
 private static final Logger logger = LoggerFactory
 .getLogger(SystemLogAspect.class);
 
 /** 声明切点:所有用LogAnnotation注解标识的方法 */
 @Pointcut("@annotation(mypack.LogAnnotation)")
 public void logPointCut() {}
 
 /** 声明原始方法执行前的增强代码块  */
 @Before(value = "logPointCut()")
 public void doBefore(JoinPoint joinPoint) {
 System.out.println("from SystemLogAspect.doBefore()");
 }
 
 /** 声明原始方法正常退出后的增强代码块  */
 @AfterReturning(value = "logPointCut()")
 public void doAfter(JoinPoint joinPoint) {
 System.out.println("from SystemLogAspect.doAfter()");
 
 handleLog(joinPoint, null);
 }
 
 /** 声明原始方法出现异常时的增强代码块 */
 @AfterThrowing(value = "logPointCut()",throwing = "e")
 public void doError(JoinPoint joinPoint, Exception e) {
 System.out.println("from SystemLogAspect.doError()");
 handleLog(joinPoint, e);
 }
 
 /** 输出日志*/
 private void handleLog(JoinPoint joinPoint,Exception e) {
 //从joinPoint获得LogAnnotation注解
 LogAnnotation logAnnotation = getLogAnnotation(joinPoint);
 
 if(logAnnotation == null)
 return;
 
 HttpServletRequest request =
 ((ServletRequestAttributes) RequestContextHolder
 .getRequestAttributes())
 .getRequest();
 
 String ip=request.getRemoteAddr();
 
 //获得LogAnnotation注解所标识的原始方法的描述信息
 String desc = logAnnotation.desc();
 
 if(e==null)
 logger.info(desc+";IP:"+ip);
 else
 logger.error(desc+";IP:"+ip+";异常:"+e.getMessage());
 }
 
 /** 获得原始方法的LogAnnotation注解*/
 private static LogAnnotation getLogAnnotation(JoinPoint joinPoint) {
 
 //获得连接点的原始方法签名
 MethodSignature methodSignature =
 (MethodSignature) joinPoint.getSignature();
 
 //获得连接点的原始方法
 Method method = methodSignature.getMethod();
 
 if(method!= null)
 return method.getAnnotation(LogAnnotation.class);
 else
 return null;
 }
 }
 | 
 SystemLogAspect类用@Component注解来标识,表明它属于Spring MVC的Bean组件,Spring MVC框架会自动创建SystemLogAspect Bean组件。
 
 在Spring MVC的配置文件中,需要配置AspectJ自动代理,来启用AOP的代码增强功能:
 
 
 
 通过浏览器访问
 http://localhost:8080/helloapp/logtest,
 LogTesterController类的logtest()方法正常执行,在Tomcat控制台会输出logtest()方法的打印信息,以及SystemLogAspect切面类的增强代码块输出的日志信息:
 
 
 | from SystemLogAspect.doBefore() from logtest():begin
 from logtest():end
 from SystemLogAspect.doAfter()
 INFO [http-nio-8080-exec-9] mypack.SystemLogAspect(handleLog:63)
 - logtest():测试日志方法;IP:0:0:0:0:0:0:0:1​
 | 
 从以上打印结果可以看出,执行logtest()方法以及SystemLogAspect类的增强代码块的先后循序如下:
 
 (1)SystemLogAspect.doBefore()
 (2)LogTesterController.logtest()
 (3)SystemLogAspect.doAfter()
 
 通过浏览器访问
 http://localhost:8080/helloapp/logtest?num=0,
 LogTesterController类的logtest()方法会抛出ArithmeticException异常,在Tomcat控制台打印以下信息:
 
 
 | from SystemLogAspect.doBefore() from logtest():begin
 from SystemLogAspect.doError()
 ERROR [http-nio-8080-exec-1] mypack.SystemLogAspect(handleLog:65)
 - logtest():测试日志方法;IP:0:0:0:0:0:0:0:1;异常:/by zero
 | 
 从以上打印结果可以看出,执行logtest()方法以及SystemLogAspect类的增强代码块的先后循序如下:
 (1)SystemLogAspect.doBefore()
 (2)LogTesterController.logtest()
 (3)SystemLogAspect.doError()
 
 
 程序猿的技术大观园:www.javathinker.net
 |  |