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

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

第一注解

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

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

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

  4. @AfterThrowing – 异常时执行

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

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

<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依赖

<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

结果如下:

 

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

posted @ 2017-09-06 16:25  李慕白520  阅读(474)  评论(0编辑  收藏  举报