SpringMVC利用AOP实现自定义注解记录日志

时间:2021-04-10 21:59:45

http://www.xdemo.org/springmvc-aop-annotation/

本文抛砖引玉,并没有详细的介绍更全面的内容,通过一个例子让初次使用的人能够快速入门,简单的介绍一下。

第一注解

  1. @Before – 目标方法执行前执行

  2. @After – 目标方法执行后执行

  3. @AfterReturning – 目标方法返回后执行,如果发生异常不执行

  4. @AfterThrowing – 异常时执行

  5. @Around – 在执行上面其他操作的同时也执行这个方法

第二,SpringMVC如果要使用AOP注解,必须将

< aop:aspectj-autoproxy  proxy-target-class = "true" />

放在spring-servlet.xml(配置MVC的XML)中SpringMVC利用AOP实现自定义注解记录日志


第三execution表达式请参考Spring官网http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html


代码下载:http://pan.baidu.com/s/1gdeopW3SpringMVC利用AOP实现自定义注解记录日志

项目截图

SpringMVC利用AOP实现自定义注解记录日志


首先是Maven依赖

< properties >
< springframework >4.0.5.RELEASE</ springframework >
< aspectj >1.8.5</ aspectj >
< servlet >3.1.0</ servlet >
</ properties >
< dependencies >
<!-- servlet -->
< dependency >
< groupId >javax.servlet</ groupId >
< artifactId >javax.servlet-api</ artifactId >
< version >${servlet}</ version >
< scope >compile</ scope >
</ dependency >
<!-- Spring web mvc -->
< dependency >
< groupId >org.springframework</ groupId >
< artifactId >spring-webmvc</ artifactId >
< version >${springframework}</ version >
</ dependency >
<!-- Spring AOP -->
< dependency >
< groupId >org.springframework</ groupId >
< artifactId >spring-aop</ artifactId >
< version >${springframework}</ version >
</ dependency >
< dependency >
< groupId >org.aspectj</ groupId >
< artifactId >aspectjrt</ artifactId >
< version >${aspectj}</ version >
</ dependency >
< dependency >
< groupId >org.aspectj</ groupId >
< artifactId >aspectjweaver</ artifactId >
< version >${aspectj}</ version >
</ dependency >
</ dependencies >

spring-context.xml配置,基本无内容

<!-- 配置扫描路径 -->
< context:component-scan  base-package = "org.xdemo.example.springaop" >
< context:exclude-filter  type = "annotation"  expression = "org.springframework.stereotype.Controller"  />
</ context:component-scan >

spring-mvc.xml配置

<!-- 最重要:::如果放在spring-context.xml中,这里的aop设置将不会生效 -->
     < aop:aspectj-autoproxy  proxy-target-class = "true" />
<!-- 启用MVC注解 -->
< mvc:annotation-driven  />
<!-- 指定Sping组件扫描的基本包路径 -->
< context:component-scan  base-package = "org.xdemo.example.springaop" >
< context:include-filter  type = "annotation"  expression = "org.springframework.stereotype.Controller" />
</ context:component-scan >

Web.xml配置

<? xml  version = "1.0"  encoding = "UTF-8" ?>
< web-app  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"  xmlns = "http://java.sun.com/xml/ns/javaee"  xmlns:web = "http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  version = "3.0" >
< display-name >Archetype Created Web Application</ display-name >
<!-- WebAppRootKey -->
< context-param >
< param-name >webAppRootKey</ param-name >
< param-value >org.xdemo.example.springaop</ param-value >
</ context-param >
<!-- Spring Context -->
< context-param >
< param-name >contextConfigLocation</ param-name >
< param-value >classpath:spring-context.xml</ param-value >
</ context-param >
< listener >
< listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class >
</ listener >
<!-- SpringMVC -->
< servlet >
< servlet-name >SpringMVC</ servlet-name >
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
< init-param >
< param-name >contextConfigLocation</ param-name >
< param-value >classpath:spring-mvc.xml</ param-value >
</ init-param >
< load-on-startup >1</ load-on-startup >
</ servlet >
< servlet-mapping >
< servlet-name >SpringMVC</ servlet-name >
< url-pattern >/</ url-pattern >
</ servlet-mapping >
</ web-app >

注解Log

package  org.xdemo.example.springaop.annotation;
import  java.lang.annotation.ElementType;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
import  java.lang.annotation.Target;
@Retention (RetentionPolicy.RUNTIME)
@Target ({ ElementType.METHOD })
public  @interface  Log {
String name()  default  "" ;
}

日志AOP,写法一LogAop_1

package  org.xdemo.example.springaop.aop;
import  java.lang.reflect.Method;
import  java.util.UUID;
import  org.aspectj.lang.JoinPoint;
import  org.aspectj.lang.ProceedingJoinPoint;
import  org.aspectj.lang.annotation.After;
import  org.aspectj.lang.annotation.Around;
import  org.aspectj.lang.annotation.Aspect;
import  org.aspectj.lang.annotation.Before;
import  org.aspectj.lang.reflect.MethodSignature;
import  org.springframework.stereotype.Component;
import  org.xdemo.example.springaop.annotation.Log;
@Aspect
@Component
public  class  LogAop_1 {
ThreadLocal<Long> time= new  ThreadLocal<Long>();
ThreadLocal<String> tag= new  ThreadLocal<String>();
/**
  * 在所有标注@Log的地方切入
  * @param joinPoint
  */
@Before ( "@annotation(org.xdemo.example.springaop.annotation.Log)" )
public  void  beforeExec(JoinPoint joinPoint){
time.set(System.currentTimeMillis());
tag.set(UUID.randomUUID().toString());
info(joinPoint);
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println(method.getAnnotation(Log. class ).name()+ "标记" +tag.get());
}
@After ( "@annotation(org.xdemo.example.springaop.annotation.Log)" )
public  void  afterExec(JoinPoint joinPoint){
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println( "标记为" +tag.get()+ "的方法" +method.getName()+ "运行消耗" +(System.currentTimeMillis()-time.get())+ "ms" );
}
@Around ( "@annotation(org.xdemo.example.springaop.annotation.Log)" )
public  void  aroundExec(ProceedingJoinPoint pjp)  throws  Throwable{
System.out.println( "我是Around,来打酱油的" );
pjp.proceed();
}
private  void  info(JoinPoint joinPoint){
System.out.println( "--------------------------------------------------" );
System.out.println( "King:\t" +joinPoint.getKind());
System.out.println( "Target:\t" +joinPoint.getTarget().toString());
Object[] os=joinPoint.getArgs();
System.out.println( "Args:" );
for ( int  i= 0 ;i<os.length;i++){
System.out.println( "\t==>参数[" +i+ "]:\t" +os[i].toString());
}
System.out.println( "Signature:\t" +joinPoint.getSignature());
System.out.println( "SourceLocation:\t" +joinPoint.getSourceLocation());
System.out.println( "StaticPart:\t" +joinPoint.getStaticPart());
System.out.println( "--------------------------------------------------" );
}
}

日志AOP,写法二LogAop_2

package  org.xdemo.example.springaop.aop;
import  java.lang.reflect.Method;
import  java.util.UUID;
import  org.aspectj.lang.JoinPoint;
import  org.aspectj.lang.ProceedingJoinPoint;
import  org.aspectj.lang.annotation.After;
import  org.aspectj.lang.annotation.Around;
import  org.aspectj.lang.annotation.Aspect;
import  org.aspectj.lang.annotation.Before;
import  org.aspectj.lang.annotation.Pointcut;
import  org.aspectj.lang.reflect.MethodSignature;
import  org.springframework.stereotype.Component;
import  org.xdemo.example.springaop.annotation.Log;
@Aspect
@Component
public  class  LogAop_2 {
ThreadLocal<Long> time= new  ThreadLocal<Long>();
ThreadLocal<String> tag= new  ThreadLocal<String>();
@Pointcut ( "@annotation(org.xdemo.example.springaop.annotation.Log)" )
public  void  log(){
System.out.println( "我是一个切入点" );
}
/**
  * 在所有标注@Log的地方切入
  * @param joinPoint
  */
@Before ( "log()" )
public  void  beforeExec(JoinPoint joinPoint){
time.set(System.currentTimeMillis());
tag.set(UUID.randomUUID().toString());
info(joinPoint);
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println(method.getAnnotation(Log. class ).name()+ "标记" +tag.get());
}
@After ( "log()" )
public  void  afterExec(JoinPoint joinPoint){
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
System.out.println( "标记为" +tag.get()+ "的方法" +method.getName()+ "运行消耗" +(System.currentTimeMillis()-time.get())+ "ms" );
}
@Around ( "log()" )
public  void  aroundExec(ProceedingJoinPoint pjp)  throws  Throwable{
System.out.println( "我是Around,来打酱油的" );
pjp.proceed();
}
private  void  info(JoinPoint joinPoint){
System.out.println( "--------------------------------------------------" );
System.out.println( "King:\t" +joinPoint.getKind());
System.out.println( "Target:\t" +joinPoint.getTarget().toString());
Object[] os=joinPoint.getArgs();
System.out.println( "Args:" );
for ( int  i= 0 ;i<os.length;i++){
System.out.println( "\t==>参数[" +i+ "]:\t" +os[i].toString());
}
System.out.println( "Signature:\t" +joinPoint.getSignature());
System.out.println( "SourceLocation:\t" +joinPoint.getSourceLocation());
System.out.println( "StaticPart:\t" +joinPoint.getStaticPart());
System.out.println( "--------------------------------------------------" );
}
}

用到的一个用户类User

package  org.xdemo.example.springaop.bean;
public  class  User {
private  String name;
public  String getName() {
return  name;
}
public  void  setName(String name) {
this .name = name;
}
}

一个测试的Controller

package  org.xdemo.example.springaop.controller;
import  javax.annotation.Resource;
import  org.springframework.stereotype.Controller;
import  org.springframework.web.bind.annotation.RequestMapping;
import  org.springframework.web.bind.annotation.ResponseBody;
import  org.xdemo.example.springaop.annotation.Log;
import  org.xdemo.example.springaop.bean.User;
import  org.xdemo.example.springaop.service.IUserService;
@Controller
@RequestMapping ( "/aop" )
public  class  SpringController {
@Resource  IUserService userService;
@Log (name= "您访问了aop1方法" )
@ResponseBody
@RequestMapping (value= "aop1" )
public  String aop1(){
return  "AOP" ;
}
@Log (name= "您访问了aop2方法" )
@ResponseBody
@RequestMapping (value= "aop2" )
public  String aop2(String string)  throws  InterruptedException{
Thread.sleep(1000L);
User user= new  User();
user.setName(string);
userService.save(user);
return  string;
}
}

一个测试的接口实现类(接口类略

package  org.xdemo.example.springaop.service;
import  org.springframework.stereotype.Service;
import  org.xdemo.example.springaop.annotation.Log;
import  org.xdemo.example.springaop.bean.User;
@Service
public  class  UserServiceImpl  implements  IUserService {
@Log (name =  "您访问了保存用户信息" )
public  void  save(User user) {
System.out.println(user.getName());
}
}

在地址栏输入地址测试http://localhost:8080/springaop/aop/aop2?string=sxxxxx

结果如下:SpringMVC利用AOP实现自定义注解记录日志

SpringMVC利用AOP实现自定义注解记录日志


转载请注明来源:http://www.xdemo.org/springmvc-aop-annotation/ SpringMVC利用AOP实现自定义注解记录日志