`

用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
分享到:
评论
2 楼 czsmosquito 2016-11-17  
1 楼 czsmosquito 2016-11-17  
引用

相关推荐

    android 实现AOP 使用Aspectj Kotlin版Demo.zip

    FastClickAop通常通过AOP来实现,当用户连续点击时,确保按钮在一定时间内只能响应一次点击事件,防止重复操作。 使用AspectJ与Kotlin结合实现AOP,主要步骤如下: 1. 引入AspectJ库:在项目build.gradle文件中...

    用aspectj拦截mybatis mapper的一种可行方案

    如果没有找到特定的注解,或者注解不存在,那么只执行一次原方法并返回结果。 通过这种方式,我们利用AspectJ在MyBatis的Mapper接口方法执行时插入自定义逻辑,实现了对Mapper方法的拦截和扩展。这种方案对于需要在...

    LoggingWithAspectJ-1.0.zip

    通过AOP,我们可以编写一次日志代码,然后在整个应用程序中自动应用这些日志,而无需在每个函数或类中重复日志语句。这极大地提高了代码的可读性和可维护性。 AspectJ提供了字节码级别的编织能力,使得日志切面可以...

    permissionDemo.zip

    在Android开发中,从6.0(API Level 23)版本开始,系统引入了运行时权限管理机制,即应用在需要使用某些敏感权限时,不再像以前那样在安装时一次性全部申请,而是需要在运行时根据实际需要动态地向用户请求。...

    aopalliance和aspectjrt和aspectjweaver1_6_8

    例如,Spring AOP和AspectJ都支持AOPalliance的接口,这样开发者可以编写一次拦截器,然后在不同的AOP框架中重用。 接下来,AspectJ RT(Runtime)是AspectJ的核心运行时库,它提供了实现切面功能的基础结构。...

    MyAspectJ.zip

    在Android 6.0(API级别23)及以上版本,应用需要在运行时动态请求权限,而不是在安装时一次性获取所有权限。AspectJ可以让我们在不侵入主要业务逻辑的情况下,插入这些权限检查,提升代码的可维护性。 下面详细...

    Spring使用AOP的三个jar包

    Spring的AOP框架就是基于这些接口构建的,这样开发者可以编写一次拦截器,就可以在多个AOP框架中复用。 这三个jar包在Spring AOP中的角色如下: 1. `aspectjrt.jar`:提供AspectJ的运行时支持,用于实现基于...

    aspectjweaver-1.6.8_2-source-release.tar.gz

    AspectJ Weaver,作为Java世界中的一个强大切面编程(AOP)工具,为开发者提供了在运行时动态编织代码的能力,使得我们可以更优雅地实现横切关注点,如日志、事务管理等。本篇将详细介绍其1.6.8_2源码发布版的主要特点...

    aspectjrt-1.6.8_1-source-release.tar.gz

    AspectJ是一个强大的面向切面编程(AOP)的Java扩展,它允许程序员在不干扰核心业务逻辑的情况下,添加系统级别的关注点,如日志、事务管理等。"aspectjrt-1.6.8_1"是该库的一个特定版本,其中"rt"代表运行时...

    spring定时器的动态设置

    - `@Scheduled(fixedDelay = 5000)`:上一次执行结束到下一次开始执行的时间间隔为5秒。 2. **动态配置定时任务**: - 如果需要动态改变定时任务的执行时间,可以通过修改配置文件或数据库中的cron表达式来实现。...

    Advanced-Programming-Practices:使用Java,AspectJ,C,Common Lisp和CLOS进行面向对象,面向方面,过程和函数式编程

    **标题解析:** "Advanced-Programming-Practices:使用Java,AspectJ,C,Common...综上所述,这个项目为学习者提供了一次全面的编程语言和范式探索之旅,有助于他们成长为多面手程序员,具备解决各种复杂问题的能力。

    AopDemo.rar

    在安卓应用开发中,为了提升用户体验和优化代码结构,开发者常常会使用面向切面编程(Aspect-Oriented Programming,简称AOP)来处理一些横切关注点,如日志记录、异常处理、性能监控等。本示例"AopDemo"正是展示了...

    aspectjrt-1.5.3.jar.zip

    面向切面编程是一种编程范式,旨在提高软件的模块化程度,通过将关注点分离,使业务逻辑和系统横切关注点(如日志、事务管理、权限控制等)得以独立。AspectJ是Java平台上最成熟的AOP实现之一,提供了一套完整的...

    spring4.0 jar包

    "第一次传"可能是指这是上传者首次分享这个资源,而"想免费的,不过上传资源至少一分"则可能是在某种平台上分享资源的规定,需要支付一点费用。 标签"fi"可能是错误或者不明确的,通常在IT领域,标签更可能与技术...

    spring AOP依赖三个jar包

    Spring AOP,即Spring的面向切面编程模块,是Spring框架的重要组成部分,它允许开发者在不修改源代码的情况下,对程序进行横切关注点的处理,如日志、事务管理等。实现这一功能,主要依赖于三个核心的jar包:aop...

    OkAspectj:有人想要Android面向切面编程,今天他来了!轻松完成各种骚操作,登录状态拦截,日志拦截,权限拦截,轻松搞定!

    第一次发布 快速对指定函数进行切面拦截: 注解完全自定义 拦截规则自定义 无需手动编写切面代码,APT自动生成切面文件 支持组件化 Installation: 1.project.gradle buildscript { repositories { google() ...

    aspectjrt-1.0.5.jar.zip

    1. **日志记录**:开发者可以定义一个切面来统一处理所有类的日志记录,无需在每个方法中插入日志代码,提高了代码的整洁性和可维护性。 2. **事务管理**:在业务逻辑中,事务管理通常是横切关注点。AspectJRT使得...

    aopalliance源码

    `MethodInvocation`接口则代表了对目标方法的一次调用,它包含了关于方法的信息,如方法名、参数等,以及调用的能力。通过实现这些接口,开发者可以创建自己的拦截器,实现在方法调用前后的扩展逻辑。 接下来,我们...

    ajdt_2.2.3

    通过AOP,我们可以编写一次切面代码,然后在整个应用中跨多个类和方法应用这些切面,减少重复代码。 Eclipse AJDT插件提供了以下关键功能: 1. **源代码编辑器**:AJDT为AspectJ语法提供了解析器和高亮显示,使得...

    CAS SSO

    5. **log4j-1.2.15.jar**:Log4j 是一个广泛使用的日志框架,用于记录应用程序中的事件。CAS 使用它来记录诊断信息和错误日志。 6. **quartz-1.5.2.jar**:Quartz 是一个作业调度库,可能在 CAS 中用于定时任务,如...

Global site tag (gtag.js) - Google Analytics