`

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/ 

分享到:
评论

相关推荐

    Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源

    本项目“Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源”正是针对这一需求提供的一种解决方案。下面将详细介绍这个项目中的关键技术点和实现原理。 首先,Spring框架是Java企业级应用开发的核心...

    springMVC AOP拦截拦截Controller等实现日志管理

    在这个场景中,我们将讨论如何利用AOP来实现Controller的日志管理,以捕获并记录应用程序中的异常。 首先,我们需要了解Spring AOP的基础概念。AOP允许我们定义“切面”,这些切面是关注点的模块化,如日志记录。切...

    springMVC自定义注解,用AOP来实现日志记录的方法

    SpringMVC自定义注解与AOP实现日志记录的方法 在本文中,我们将探讨如何使用SpringMVC自定义注解与AOP(Aspect-Oriented Programming)来实现日志记录的方法。该方法可以在项目中记录业务操作的日志,并提取关键...

    springmvc log4j2 logback 注解 jackson 日志脱敏实现源码

    本资源包含的是关于`SpringMVC`、`Log4j2`、`Logback`以及`Jackson`的日志脱敏实现源码,提供了多种实现方式,旨在帮助开发者在保障信息安全的同时,充分利用日志进行系统分析。 1. **基于正则表达式的日志脱敏实现...

    简单的SpringMVC加注解AOP,改变传进的值

    接下来,我们讨论"AOP和自定义注解"。AOP的核心思想是将那些分散在多个类中的横切关注点(如日志、事务管理、安全检查等)抽取出来,形成独立的模块,这样可以降低代码的耦合度,提高可维护性。在Spring中,我们可以...

    SpringMVC-Aop demo

    这个项目旨在帮助开发者理解如何通过注解来配置和实现AOP,以便进行日志记录、事务管理或其他跨功能的需求。下面我们将详细探讨SpringMVC与AOP的结合以及其核心概念。 AOP是一种编程范式,允许我们定义关注点(如...

    Spring MVC AOP通过注解方式拦截Controller等实现日志管理demo版本2

    本项目"Spring MVC AOP通过注解方式拦截Controller等实现日志管理demo版本2"是基于注解的AOP实践,旨在帮助开发者了解如何利用AOP来记录应用程序中的关键操作日志。以下是关于这个主题的详细解释: 1. **Spring AOP...

    使用使用切面的方式记录日志springMvc + hibernate

    在代码实现上,我们需要创建自定义的切面类,继承自Spring的AspectJExpressionPointcutAdvisor或实现MethodBeforeAdvice接口,然后在Controller方法中使用@Autowired注解注入需要记录日志的服务。 总结来说,本项目...

    自定义的springMVC

    - **拦截器(Interceptor)**:自定义拦截器可以实现全局的功能,比如权限验证、日志记录、性能统计等。通过实现HandlerInterceptor接口并将其注册到SpringMVC配置中,即可在请求处理前后执行自定义逻辑。 - **...

    SpringMVC+Hibernate实现增删改

    5. **Interceptor**: 拦截器允许在请求处理前后进行预处理和后处理,例如权限验证、日志记录等。 6. **ModelAndView**: 用于将模型数据和视图名称一起返回给DispatcherServlet。 **Hibernate框架** Hibernate是一个...

    java分页 动态代理 aop实现

    AOP是Spring框架的核心特性之一,它允许我们将关注点(如日志、事务管理、安全检查等)从主业务逻辑中分离出来,实现代码的解耦。Spring AOP主要通过两种方式实现: 1. 声明式AOP:基于注解的AOP,通过在方法上添加...

    springboot学习、springmvc、mybatis、注解、拦截器.zip

    注解的学习主要在于理解不同注解的作用,例如@Controller、@Service、@Autowired等,并掌握如何自定义注解和使用元注解。 最后,学习拦截器,你需要知道如何注册拦截器,实现拦截器的preHandle、postHandle和...

    spring_aop_拦截实例

    在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员定义横切关注点,如日志、事务管理、性能监控等,并将它们模块化为可重用的组件,称为切面。本实例主要探讨如何在Spring AOP中实现拦截器。 ...

    SpringMVC面试专题及答案.zip

    9. **AOP(面向切面编程)**:SpringMVC与Spring AOP紧密集成,可以方便地实现事务管理、日志记录等功能,提高代码的可维护性和可复用性。 10. **RESTful风格**:SpringMVC支持创建RESTful API,通过@...

    SpringMVC完整使用教程

    SpringMVC 可以结合 Spring 的 AOP(面向切面编程)来实现全局行为,如日志记录、权限控制等。另外,`HandlerInterceptor` 实现类可以自定义拦截器,对请求处理流程进行扩展。 综上所述,SpringMVC 提供了一个强大...

    springmvc框架源码.zip

    8. **AOP(面向切面编程)**:SpringMVC利用Spring的AOP功能实现拦截器(Interceptor),可以在请求处理前后执行自定义逻辑,如日志记录、权限检查等。 9. **异常处理**:SpringMVC提供了一套优雅的异常处理机制,...

    Spring 与Ehcache实现基于方法的缓存

    本篇文章将详细探讨如何在Spring框架中集成并实现基于方法的缓存机制,利用Ehcache来优化数据访问。 首先,我们需要理解Spring的AOP概念,AOP允许我们定义横切关注点,如日志、事务管理或,正如在这个案例中,缓存...

    SpringMVC jar包

    8. **AOP(面向切面编程)**:SpringMVC利用AOP进行事务管理和日志记录等,使得这些跨切面的职责可以与核心业务逻辑分离。 9. **IoC(控制反转)**:SpringMVC使用IoC容器管理对象及其依赖关系,允许在运行时注入...

Global site tag (gtag.js) - Google Analytics