用aspectJ 做了一次日志

1、

<aspectj.version>1.7.4.RELEASE</aspectj.version>

	<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${aspectj.version}</version>
		</dependency>
		
 		<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
          	<version>${aspectj.version}</version>
        </dependency>

 注意:如果JDK1.7的 必须这里也是1.7+

 

 

2、

<aop:config proxy-target-class="true"></aop:config>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
    
    <aop:aspectj-autoproxy proxy-target-class="true"/>

 注意:必须在spring-mvc.xml里面,且有两个aop配置,下面那个是必须的,上面那个可能不是必须的(上面那个应该是spring aop的,如果有aspectJ了,可以不需要)

 

3、AOP类

 

package com.kingen.aop;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.kingen.bean.Log;
import com.kingen.bean.User;
import com.kingen.service.log.LogService;
import com.kingen.util.Constants;
import com.kingen.util.DateUtils;
import com.kingen.util.SpringContextHolder;
import com.kingen.util.StringUtils;
import com.kingen.util.UserUtils;

/**
 * 日志AOP
 * 
 * @author wj
 * @date 2016-11-16
 *
 */
@Aspect
@Component
public class LogAOP {

	private static LogService logService = SpringContextHolder.getBean(LogService.class);

	// 本地异常日志记录对象
	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 在所有标注@LogAnnotation的地方切入
	 * 
	 * @param joinPoint
	 */
	@Pointcut("@annotation(com.kingen.aop.LogAnnotation)")
	public void logAspect() {
	}

	// @Around(value = "aApplogic() && @annotation(annotation) &&args(object,..)
	// ", argNames = "annotation,object")
	// public Object around(ProceedingJoinPoint pj,
	// LogAnnotation annotation, Object object) throws Throwable {
	// System.out.println("moduleName:"+annotation.moduleName());
	// System.out.println("option:"+annotation.option());
	// pj.proceed();
	// return object;
	// }

	/**
	 * 前置通知 用于拦截Controller层记录用户的操作
	 * 
	 * @param joinPoint
	 *            切点
	 * @throws Exception
	 */
//	@Around(value = "logAspect() && @annotation(annotation) &&args(object,..) ", argNames = "annotation,object")
//	public void doAround(ProceedingJoinPoint joinPoint, LogAnnotation annotation, Object object) {
	//用@Around 会导致controller不执行,不返回页面
	
//	 @After(value = "logAspect() && @annotation(annotation) &&args(object,..) ", argNames = "annotation,object")
//	 public void doAfter(JoinPoint joinPoint, LogAnnotation annotation, Object object) {
	
	 @AfterReturning(value = "logAspect() && @annotation(annotation) &&args(object,..) ", argNames = "", returning = "retVal")
	 public void doAfterReturning(JoinPoint joinPoint, LogAnnotation annotation, Object object,  String retVal) {

		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		try {
			// String title = getAnnotationValue(joinPoint);
			String title = getAnnotationValue(annotation);
			saveLog(request, title);
		} catch (Exception e) {
			e.printStackTrace();
			// 记录本地异常日志
			logger.error("==异常通知异常==");
			logger.error("异常信息:{}", e.getMessage());
		}
	}

	/**
	 * 异常通知 用于拦截service层记录异常日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	// 方法  catch住异常的话,这里执行不到
//	@AfterThrowing(pointcut = "logAspect()", throwing = "e")
	@AfterThrowing(value = "logAspect() && @annotation(annotation) &&args(..) " , throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint,  LogAnnotation annotation, Exception e) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();

		try {

//			String title = getAnnotationValue(joinPoint);
			String title = getAnnotationValue(annotation);
			saveLog(request, title, e);
		} catch (Exception ex) {
			// 记录本地异常日志
			logger.error("==异常通知异常==");
			logger.error("异常信息:{}", ex.getMessage());
		}

	}

	public static void saveLog(HttpServletRequest request, String title) {
		saveLog(request, title, null);
	}

	/**
	 * 保存日志
	 */
	@Transactional
	public static void saveLog(HttpServletRequest request, String title, Exception ex) {
		User user = UserUtils.getCurrentUser();
		if (user != null && user.getUserId() != null) {
			Log log = new Log();
			log.setCreateDate(DateUtils.getDateTime());
			log.setTitle(title);
			log.setType(ex == null ? Log.TYPE_ACCESS : Log.TYPE_EXCEPTION);
			log.setRemoteAddr(StringUtils.getRemoteAddr(request));
			log.setUserAgent(user.getUsername());
			// log.setUserAgent(request.getHeader("user-agent"));
			log.setRequestUri(request.getRequestURI());
			log.setParams(request.getParameterMap());
			// 如果有异常,设置异常信息
			log.setException(ex == null ? null : ex.getMessage());
//			log.setException(ex == null ? null : Exceptions.getStackTraceAsString(ex));
			log.setStatus(ex == null ? Constants.StatusEnum.Success.getIndex() : Constants.StatusEnum.Fail.getIndex());
			// log.setMethod(request.getMethod());
			// 异步保存日志
			// new SaveLogThread(log, handler, ex).start();
			logService.saveLog(log);
		}
	}

	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * 
	 * @param joinPoint
	 *            切点
	 * @return 方法描述
	 * @throws Exception
	 */
	@Deprecated
	public static String getAnnotationValue(JoinPoint joinPoint) throws Exception {
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Class targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		String description = "";
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					String moduleName = method.getAnnotation(LogAnnotation.class).moduleName();
					String option = method.getAnnotation(LogAnnotation.class).option();
					Assert.hasText(moduleName, "模块名字不应为空");
					Assert.hasText(option, "操作名字不应为空");
					description = moduleName + "-" + option;
					break;
				}
			}
		}
		return description;
	}

	public static String getAnnotationValue(LogAnnotation anno) throws Exception {
		String moduleName = anno.moduleName();
		String option = anno.option();
		Assert.hasText(moduleName, "模块名字不应为空");
		Assert.hasText(option, "操作名字不应为空");
		String description = moduleName + "-" + option;
		return description;
	}
}

 注意这里 @After和 @AfterReturning的区别,总的来说,就是 @After 是无论如何都会执行的,不管有没有异常抛出(这样会导致,在有异常的时候,记录两次日志,after一次、throwing一次);@AfterReturning 在有异常的情况下,不会执行到,因为没有renturn,在retrun之前就throw了。

http://stackoverflow.com/questions/4304676/why-is-afterreturning-only-executed-after-afterthrowing-on-exception 写道


If you want to execute a code after method regardless if there was an exception thrown or not, you need to use @After instead.

 

http://stackoverflow.com/questions/11859568/how-to-use-one-of-after-and-afterthrowing-in-aspectj/11859621#11859621 写道
Change the @After to an @AfterReturning

 

http://stackoverflow.com/questions/16522635/spring-and-aop-after-works-but-not-afterreturning 写道
if there is a exception thrown within pointcut methodAnnotatedWithMyService() then @AfterReturning will not be called.. but a @After will be called..

from http://static.springsource.org/spring/docs/2.0.x/reference/aop.html

@AfterReturning advice runs when a matched method execution returns normally

 

 

http://stackoverflow.com/questions/38202051/spring-aop-after-or-afterreturning-which-advice-will-invoked-first 写道
Invocation of the advices of different type applied on the same jointpoint(core business related modules) as follows :

1.Around

2.Before and/or After

3.AfterReturning or AfterThrowing
Suppose we applied all five types of advices on the same jointpoint then the flow will be like :

Around type advice will be invoked and code before pjp.proceed() of Around type advice will be executed where pjp is the reference variable of ProceedingJoinPoint interface.
Before type advice will be invoked and executed fully.
code inside jointpoint will be executed fully.
Code after pjp.proceed() of Around type advice will be executed if jointpoint executes successfully otherwise skip this step and go to step 5. If it's modified return value then this new return value will be effected to the followings advice or method invocation.
After type advice will be invoked and executed fully.
AfterReturning type advice will be invoked and executed fully if jointpoint executes successfully else if jointpoint throws any error then AfterThrowing type advice will be invoked and executed fully.

 

 

 

4、poitcut用注解

package com.kingen.aop;  
   
import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  
 /**
  * 日志注解
  * @author wj
  *
  */
@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.METHOD})  
public @interface LogAnnotation {  
    //模块名  
    String moduleName();  
    //操作内容  
    String option();  
}  

 

5、使用

 

	@RequestMapping(value="/")
	@LogAnnotation(moduleName="用户管理",option="查看")
	@RequiresPermissions("user:view")
	public String execute(HttpServletResponse response) throws Exception{
		try{
			service.testException();
		}catch(Exception e){
			e.printStackTrace();
                        logger.error(e.getMessage());
			throw new Exception("test");
		}
		return "account/tmanageruser"; 
	}

 注意:我的需求是,当正常执行就插入成功日志,如果有异常就插入失败日志,这里controller层的,在catch住后又throw了,可以满足。当然不能用@After了,只能用@AfterReturning 和 @AfterThrowing

 

 

-----------

 

 advisor 是管理point cut 和 advice(@before、@AfterReturing…)的容器  

@After 不管怎样都会执行,方法肯定会结束啊
@Afterreturning 返回值时执行、有异常当然没有返回值、当然不执行!
@Afterthrowing 异常抛出!时执行,别catch住了 (可以再抛)  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP(面向切面编程)主要应用于解决横切关注点的问题,例如日志记录、安全控制、事务管理等。其中,一个常见的应用场景是在业务方法执行前后,记录日志信息。 举个例子,假设我们有一个UserService接口,其中有一个updateUser()方法用于更新用户信息。我们希望在方法执行前后,记录一些日志信息,例如方法名、参数、执行时间等。这时,我们可以使用Spring AOP来实现。 首先,定义一个切面类,其中包含一个前置通知和一个后置通知,分别用于在方法执行前后执行相应操作。示例代码如下: ```java @Component @Aspect public class LoggingAspect { private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class); @Before("execution(* com.example.service.UserService.updateUser(..))") public void logBefore(JoinPoint joinPoint) { logger.info("Before method: {}", joinPoint.getSignature().getName()); logger.info("Arguments: {}", Arrays.toString(joinPoint.getArgs())); } @AfterReturning(value = "execution(* com.example.service.UserService.updateUser(..))", returning = "result") public void logAfter(JoinPoint joinPoint, Object result) { logger.info("After method: {}", joinPoint.getSignature().getName()); logger.info("Result: {}", result); } } ``` 其中,@Aspect注解表示该类为切面类,@Before和@AfterReturning注解分别表示前置通知和后置通知。这里使用了Spring AOP提供的切点表达式来匹配UserService接口的updateUser()方法。 然后,在Spring配置文件中声明该切面类,并启用AOP功能。示例代码如下: ```xml <context:component-scan base-package="com.example.service" /> <aop:aspectj-autoproxy /> <bean class="com.example.aspect.LoggingAspect" /> ``` 最后,在业务逻辑中调用UserService的updateUser()方法时,Spring AOP会自动调用LoggingAspect中定义的前置通知和后置通知,记录相应的日志信息。 通过这种方式,我们可以将横切关注点与业务逻辑分离,提高代码的可维护性和可重用性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值