您的位置:首页 > 编程语言

面向切面编程(AOP)应用,日志切面,基于注解

2016-04-19 18:08 393 查看
名词解释:

切面(Aspect) :一个关注点的模块化,这个关注点可能会横切多个对象,在本例中,“切面”就是类SystemLogAspect所的具体行为,例如,“切面”可以在ApplicationContext中<aop:aspect>来配置,或者使用注解@Aspect。
Aspect    //定义一个切面
Component
@Order(1)
public class SystemLogAspect {}



或者配置文件:
aop:config>
<!-- 定义切面 -->
<aop:aspect id="security" ref="securityHandler1">
<!-- 定义pointcut,并写表达式 -->
<aop:pointcut id="allMethod" expression="execution(* managerImpl.UserManagerImpl.add*(..))|| execution(* man											agerImpl.UserManagerImpl.del*(..))"/>
<!-- 定义advice,织入pointcut -->
<aop:before method="checkSecurity" pointcut-ref="allMethod"/>
</aop:aspect>
</aop:config>


连接点(Joinpoint) :在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候,joinPoint对象进程作为参数使用,从而获取这个连接点的相关信息,例如:可以为通知(Advice)的主体部分获得连接点信息

通知(Advice) :在切面的某个特定的连接点(Joinpoint)上执行的动作,例如前置通知,后置通知,异常通知等等。

       通知:即为在向连接点切入时所执行的动作

/**
* 前置通知 用于拦截Controller层记录用户的操作
* joinPoint 切点为参数,可以使通知获取连接点的信息
*/
@Before("controllerAspect()")
public  void doBefore(JoinPoint joinPoint) { //doSomeThing }


切入点(Pointcut) :匹配连接点的断言,是一个表达式,通知和一个切入点表达式相关联。并在满足这个切入点的连接点上运行,

//Controller层切入点,    
@Pointcut("@annotation(com.poobo.comm.web.aop.SystemCtrLo4jAop)")


public void controllerAspect() { }
自定义一个注解  表达式:"@annotation(com.poobo.comm.web.aop.SystemCtrLo4jAop)"是一个自定义的注解,切入点的表达式使用这个注解后,只要在一段代码前使用了这个注解,那么该代码就是一个切入点。这样就不仅同一了名称,


而且避免了使用切入点表达式execution(* com.spring.service.*.*(..))的局限性。


@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemCtrLo4jAop {
String description()  default "";
}


目标对象(Target Object) :一个或者多个切面(aspect)所通知(advise)的对象。Spring
AOP采用代理实现,实际AOP操作的是TargetObject的代理对象。

AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理,。强制使用CGLIB代理需要将 
<aop:config>
 的 
proxy-target-class
 属性设为true
//定义一个切面

@Aspect
@Component
@Order(1)
public class SystemLogAspect {

//系统日志
@Autowired
private ISysLogService iSysLogService;

@Autowired
//系统用户
private IPrivateAccountService accountService;

//本地异常日志记录对象
private Logger log = Logger.getLogger(SystemLogAspect.class);

//Service层切点
@Pointcut("@annotation(com.poobo.comm.web.aop.SystemServiceLo4jAop)")
public  void serviceAspect() {
}

//Controller层切点
@Pointcut("@annotation(com.poobo.comm.web.aop.SystemCtrLo4jAop)")
public  void controllerAspect() {
}

/**
* 前置通知 用于拦截Controller层记录用户的操作
*
* @param joinPoint 切点
*/
@Before("controllerAspect()")
public  void doBefore(JoinPoint joinPoint) {
//读取session中的用户
SysAccount user =  AppContextUtil.getLoginInfo();
//请求的IP
String ip = AppContextUtil.getRequest().getRemoteAddr();
try {
/* //*========控制台输出=========
System.out.println("=====前置通知开始=====");
System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));
System.out.println("请求人账号:" + user.getLoginName());
System.out.println("请求人昵称:" + user.getNickName());
System.out.println("请求人角色:" + user.getRole().getName());
System.out.println("请求IP:" + ip);
System.out.println("请求时间:"+DateUtil.getNowTime());
//*========数据库日志=========*/
SysLog tbSysLog=new  SysLog();
tbSysLog.setMethods(getControllerMethodDescription(joinPoint));
tbSysLog.setLogDesc((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
tbSysLog.setLoginIp(ip);
tbSysLog.setRoleName(user.getRole().getName());
tbSysLog.setAccountName(user.getNickName());
tbSysLog.setLoginName(user.getLoginName());
tbSysLog.setCreateDate(DateUtil.getNowTime());
tbSysLog.setType(WebConstants.SYS_LOG_RECORD);
//保存数据库
iSysLogService.saveSysLog(tbSysLog);
//System.out.println("=====前置通知结束=====");
}  catch (Exception e) {
//记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}",e);
}
}

/**
* 异常通知 用于拦截service层记录异常日志
*
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {

//读取session中的用户
SysAccount user = AppContextUtil.getLoginInfo();
//获取请求ip
String ip = AppContextUtil.getRequest().getRemoteAddr();
//获取用户请求方法的参数并序列化为JSON格式字符串
String params = "";
if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {
for ( int i = 0; i < joinPoint.getArgs().length; i++) {
params += JSON.toJSONString(joinPoint.getArgs()[i]) + ";";
}
}
try {
/*========控制台输出=========*/
/*  System.out.println("=====异常通知开始=====");
System.out.println("异常代码:" + e.getClass().getName());
System.out.println("异常信息:" + e.getMessage());
System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));
System.out.println("请求人:" + user.getLoginName());
System.out.println("请求IP:" + ip);
System.out.println("请求参数:" + params);    */
/*    ==========数据库日志=========   */
SysLog sysLog=new SysLog();
sysLog.setMethods(getServiceMthodDescription(joinPoint));
sysLog.setExceptionCode(e.getClass().getName());
sysLog.setType(WebConstants.SYS_LOG_EXCEPTION);
sysLog.setLogDesc((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
sysLog.setExceptionDetail(e.getMessage());
sysLog.setParams(params);
sysLog.setCreateBy(user.getLoginName());
sysLog.setCreateDate(DateUtil.getNowTime());
sysLog.setLoginIp(ip);
//保存数据库
iSysLogService.saveSysLog(sysLog);
// System.out.println("=====异常通知结束=====");
}  catch (Exception ex) {
//记录本地异常日志
log.error("==异常通知异常==");
log.error("异常信息:{}", ex);
}
/*==========记录本地异常日志==========*/
// log.error(null,joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage());

}

/**
* 获取注解中对方法的描述信息 用于service层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public  static String getServiceMthodDescription(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) {
description = method.getAnnotation(SystemServiceLo4jAop.class).description();
break;
}
}
}
return description;
}

/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public  static String getControllerMethodDescription(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) {
description = method.getAnnotation(SystemCtrLo4jAop. class).description();
break;
}
}
}
return description;
}
}


//自定义注解
/**
* 自定义aop拦截日志
* @author xyy
*
*/
@Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SystemCtrLo4jAop { String description() default ""; }


//应用于一个切入点
@RequestMapping(value="admin/goods/ajaxDoDeleteSysGoods",produces="text/html;charset=UTF-8")
@ResponseBody
@SystemCtrLo4jAop(description="删除商品")
public String ajaxDoDeleteSysGoods(SysGoods goods,HttpServletRequest request){

//删除商品
json = goodsService.deleteGoods(goods);

return json.toJSONString();
}


当运行切入点时即可在数据库保存一条日志记录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  AOP