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

 

对应的中文:

任意公共方法的执行: 
execution(public * *(..)) 
任何一个以“set”开始的方法的执行: 
execution(* set*(..)) 
AccountService 接口的任意方法的执行: 
execution(* com.xyz.service.AccountService.*(..)) 
定义在service包里的任意方法的执行: 
execution(* com.xyz.service.*.*(..)) 
定义在service包或者子包里的任意方法的执行: 
execution(* com.xyz.service..*.*(..)) 
在service包里的任意连接点(在Spring AOP中只是方法执行) : 
within(com.xyz.service.*) 
在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) : 
within(com.xyz.service..*) 
实现了 AccountService 接口的代理对象的任意连接点(在Spring AOP中只是方法执行) : 
this(com.xyz.service.AccountService) 
'this'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得代理对象可以在通知体内访问到的部分。 
实现了 AccountService 接口的目标对象的任意连接点(在Spring AOP中只是方法执行) : 
target(com.xyz.service.AccountService) 
'target'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得目标对象可以在通知体内访问到的部分。 
任何一个只接受一个参数,且在运行时传入的参数实现了 Serializable 接口的连接点 (在Spring AOP中只是方法执行) 
args(java.io.Serializable) 
'args'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得方法参数可以在通知体内访问到的部分。 请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable)): args只有在动态运行时候传入参数是可序列化的(Serializable)才匹配,而execution 在传入参数的签名声明的类型实现了 Serializable 接口时候匹配。 
有一个 @Transactional 注解的目标对象中的任意连接点(在Spring AOP中只是方法执行) 
@target(org.springframework.transaction.annotation.Transactional) 
'@target' 也可以在binding form中使用:请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。 
任何一个目标对象声明的类型有一个 @Transactional 注解的连接点(在Spring AOP中只是方法执行) 
@within(org.springframework.transaction.annotation.Transactional) 
'@within'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。 
任何一个执行的方法有一个 @Transactional annotation的连接点(在Spring AOP中只是方法执行) 
@annotation(org.springframework.transaction.annotation.Transactional) 
'@annotation' 也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。 
任何一个接受一个参数,并且传入的参数在运行时的类型实现了 @Classified annotation的连接点(在Spring AOP中只是方法执行) 
@args(com.xyz.security.Classified)

第一注解:

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

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

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

  4. @AfterThrowing – 异常时执行

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

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

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

放在spring-servlet.xml(配置MVC的XML)中

 

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

 

代码下载:http://pan.baidu.com/s/1gdeopW3

项目截图

 

首先是Maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
< 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配置,基本无内容

1
2
3
4
<!-- 配置扫描路径 -->
     < 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配置

1
2
3
4
5
6
7
8
9
<!-- 最重要:::如果放在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配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<? 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

1
2
3
4
5
6
7
8
9
10
11
12
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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;
     }
     
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

结果如下:

 

转载请注明来源:http://www.xdemo.org/springmvc-aop-annotation/ 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值