|
本文参考《精通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.javapackage 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
|
|