SpringMVC使⽤AOP实现审计⽇志
先定⼀个注解,⽤于在Controller⽅法上记录每个⽅法的⽤途。
1. package com.zjf.spring.annotation;
2. import java.lang.annotation.Documented;
3. import java.lang.annotation.ElementType;
4. import java.lang.annotation.Retention;
5. import java.lang.annotation.RetentionPolicy;
6. import java.lang.annotation.Target;
7.
8. /**
9. * 定义注解
10. *
11. @Target : ⽤来说明该注解可以被声明在那些元素之前。
12.
13. ElementType.TYPE:说明该注解只能被声明在⼀个类前。
14.
15. ElementType.FIELD:说明该注解只能被声明在⼀个类的字段前。
16.
17. ElementType.METHOD:说明该注解只能被声明在⼀个类的⽅法前。
18.
19. ElementType.PARAMETER:说明该注解只能被声明在⼀个⽅法参数前。
20.
21. ElementType.CONSTRUCTOR:说明该注解只能声明在⼀个类的构造⽅法前。
22.
23. ElementType.LOCAL_VARIABLE:说明该注解只能声明在⼀个局部变量前。
24.
25. ElementType.ANNOTATION_TYPE:说明该注解只能声明在⼀个注解类型前。
26.
27. ElementType.PACKAGE:说明该注解只能声明在⼀个包名前。
28. */
29. @Target({ElementType.METHOD})
30.
31.
32. /**
33. @Retention :⽤来说明该注解类的⽣命周期。它有以下三个参数:
34.
35. RetentionPolicy.SOURCE : 注解只保留在源⽂件中
36.
37. RetentionPolicy.CLASS : 注解保留在class⽂件中,在加载到JVM虚拟机时丢弃
springmvc的注解有哪些38.
39. RetentionPolicy.RUNTIME : 注解保留在程序运⾏期间,此时可以通过反射获得定义在某个类上的所有注解。
40. */
41. @Retention(RetentionPolicy.RUNTIME)
42. /**
43. Annotation(注解)是JDK5.0及以后版本引⼊的。它可以⽤于创建⽂档,跟踪代码中的依赖性,甚⾄执⾏基本编译时检查。
44. 注解是以'@注解名'在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。
45. 它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(⽤来描述数据的数据)的访问。
46. 另外,你可以在编译时选择代码⾥的注解是否只存在于源代码级,或者它也能在class⽂件中出现。
47. */
48. /*
49. * 注解名字 LogAnnotation
50. */
51. public @interface LogAnnotation {
52. //为LogAnnotation定义了⼀个desc属性⽤于描述⽅法的description 在记录甚⾄⽇志的时候获取
53. String desc() default "⽆描述信息";
54. }
定义切⾯:
1. package com.zjf.spring.log;
2.
3. import flect.Method;
4.
5. import javax.servlet.http.HttpServletRequest;
6.
7.
8.
9. import org.aspectj.lang.JoinPoint;
10. import org.aspectj.lang.Signature;
11. import org.aspectj.lang.annotation.AfterReturning;
12. import org.aspectj.lang.annotation.AfterThrowing;
13. import org.aspectj.lang.annotation.Aspect;
14. import org.aspectj.lang.annotation.Pointcut;
15. import org.flect.MethodSignature;
16. import org.slf4j.Logger;
17. import org.slf4j.LoggerFactory;
18. import org.springframework.stereotype.Component;
19. import org.t.request.RequestContextHolder;
20. import org.t.request.ServletRequestAttributes;
21.
22. import com.zjf.spring.annotation.LogAnnotation;
23.
24. /**
25. *
26. * @Aspect⽣命这个类是⼀个切⾯
27. *
28. */
29. @Aspect
30. @Component
31. public class SystemLogAspect {
32. // 注⼊Service⽤于把⽇志保存数据库
33.
34. // 本地异常⽇志记录对象
35. private static final Logger logger = LoggerFactory
36. .getLogger(SystemLogAspect.class);
37.
38. // Controller层切点通过注解进⾏切点凡是⽣命了LogAnnotation注解的⽅法都要进⼊这个切⾯
39. @Pointcut("@annotation(com.zjf.spring.annotation.LogAnnotation)")
40. public void controllerAspect() {
41.
42. }
43.
44. /**
45. *
46. * ⽅法操作成功会进⼊@AfterReturning
47. * @param joinPoint 代表会记录切点的信息就是代码运⾏到切点是的变量环境
48. * 可以从joinPoint获取使⽤的LogAnnotation信息
49. * 切点
50. */
51. @AfterReturning(pointcut = "controllerAspect()")
52. public void doBefore(JoinPoint joinPoint) {
53. handleLog(joinPoint, null);
54. }
55.
56. /**
57. * ⽅法执⾏中出现了异常会出现在@AfterThrowing中
58. */
59. @AfterThrowing(value = "controllerAspect()", throwing = "e")
60. public void doAfter(JoinPoint joinPoint, Exception e) {
61. handleLog(joinPoint, e);
62. }
63.
64. private void handleLog(JoinPoint joinPoint,Exception e) {
65. try {
66. //从joinPoint获得LogAnnotation注解
67. LogAnnotation controllerLog = giveController(joinPoint);
68. if(controllerLog == null)
69. {
70. return;
71. }
72. //获取request
73. HttpServletRequest request = ((ServletRequestAttributes) RequestAttributes()).getRequest();
74. //通过request获取session 然后获取⽤户信息
75. //通过request获取ip
76.
77. //处理设置注解上的参数也就是⽅法的描述
78. String desc = controllerLog.desc();
79. System.out.println(desc);
80. //保存数据库
81.
82. } catch (Exception exp) {
83. //记录本地异常⽇志
84. ("==前置通知异常==");
85. ("异常信息:{}", Message());
86. exp.printStackTrace();
87. }
88. }
89.
90. /**
91. * 是否存在注解,如果存在就记录⽇志
92. * @param joinPoint
93. * @param controllerLog
94. * @return
95. * @throws Exception
96. */
97. private static LogAnnotation giveController(JoinPoint joinPoint) throws Exception
98. {
99. /*
100. * JoinPoint可以获取什么:
101. l java.lang.Object[] getArgs():获取连接点⽅法运⾏时的⼊参列表;
102. l Signature getSignature() :获取连接点的⽅法签名对象;
103. l java.lang.Object getTarget() :获取连接点所在的⽬标对象;
104. l java.lang.Object getThis() :获取代理对象本⾝;
105. */
106. Signature signature = Signature();
107. /*
108. * MethodSignature可以获取什么:
109. Class getReturnType(); 获取⽅法的返回类型
110. Method getMethod(); 获取⽅法本⾝
111. */
112. MethodSignature methodSignature = (MethodSignature) signature;
113. /**
114. * Method可以获取⽅法上的各种信息⽐如⽅法名称⽅法参数注解参数上的注解等。
115. */
116. Method method = Method();
117.
118. if(method != null)
119. {
120. Annotation(LogAnnotation.class);
121. }
122. return null;
123. }
124. }
声明:aop:aspectj-autoproxy
关于aop:aspectj-autoproxy:
通过aop命名空间的<aop:aspectj-autoproxy />声明⾃动为spring容器中那些配置@aspectJ切⾯的bean创建代理,织⼊切⾯。当
然,spring 在内部依旧采⽤AnnotationAwareAspectJAutoProxyCreator进⾏⾃动代理的创建⼯作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了
<aop:aspectj-autoproxy />有⼀个proxy-target-class属性,默认为false,表⽰使⽤jdk动态代理织⼊增强,当配为<aop:aspectj-
autoproxy poxy-target-class="true"/>时,表⽰使⽤CGLib动态代理技术织⼊增强。不过即使proxy-target-class设置为false,如果⽬标类没有声明接⼝,则spring将⾃动使⽤CGLib动态代理。
1. <aop:aspectj-autoproxy />
在Controller⽅法中加⼊注解:
1. @RequestMapping(value="/test1")
2. @LogAnnotation(desc="test1⽅法")
3. public String test1(HttpServletRequest request)
4. {
5. request.setAttribute("att1", "val1");
6. return "test1";
7. }
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论