• Spring AOP 自定义注解实现统一日志管理


    一、AOP的基本概念:

    AOP,面向切面编程,常用于日志,事务,权限等业务处理。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容(Spring核心之一),是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    二、AOP的几个特征:

    (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

    (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

    (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

    (4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

    (5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

    三、具体功能实例:

    (1)首先引入spring AOP所需的jar包依赖:

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.3</version>
    </dependency>
            
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.3</version>
    </dependency>

     (2)自定义注解类:

    /**
     * 自动日志监听注解类
     * @author AoXiang
     *
     */
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SysAutoLog {
    
        String module() default "";
        String methods() default "";
        String description() default "";
        
    }

     (3)新建切面类:

    /**
     * 日志切面类
     * @author AoXiang
     *
     */
    @Aspect
    @Component
    public class SysLogAopControl{
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        private LocalVariableTableParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        
        @Autowired
        private SysHandLogStub SysHandLogStub;
        
    
        @Pointcut("@annotation(cn.tisson.tc.annotation.SysAutoLog)")
        public void LogAspect() {}
    
        @AfterThrowing(pointcut = "LogAspect()", throwing = "e")
        public void doAfterThrowing(JoinPoint point, Throwable e) throws Exception {
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes)ra;
            HttpServletRequest request = sra.getRequest();
            SysHandLogEntity sysLog = new SysHandLogEntity();
            Map<String, Object> map = this.getMethodDescription(point);
            sysLog.setModel(map.get("module").toString());
            sysLog.setMethod("执行方法异常:-->" + map.get("methods").toString());
            sysLog.setStatusDesc("执行方法异常:-->" + e);
            sysLog.setArgs(map.get("args").toString());
            sysLog.setIp(GetRemoteIpUtil.getRemoteIp(request));
            sysLog.setCreateDate(new Date());
            SysHandLogStub.update(sysLog);
        }
    
        @Around("LogAspect()")
        public Object doAround(ProceedingJoinPoint point) {
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes)ra;
            HttpServletRequest request = sra.getRequest();
            Object result = null;
            try {
                result = point.proceed();
                SysHandLogEntity sysLog = new SysHandLogEntity();
                Map<String, Object> map = this.getMethodDescription(point);
                sysLog.setModel(map.get("module").toString());
                sysLog.setMethod(map.get("methods").toString());
                sysLog.setStatusDesc(map.get("description").toString());
                sysLog.setArgs(map.get("args").toString());
                sysLog.setIp(GetRemoteIpUtil.getRemoteIp(request));
                sysLog.setCreateDate(new Date());
                //用户信息
                Subject subject = SecurityUtils.getSubject();
                UserVo userVo = (UserVo)subject.getPrincipal();
                if (userVo == null) {
                    userVo = (UserVo)ShiroSubject.getSessionVo();
                }
                if(userVo != null) {
                    sysLog.setUserRealName(userVo.getRealName());
                }
                SysHandLogStub.update(sysLog);
            } catch (Throwable e) {
                logger.error("异常信息:{}", e.getMessage());
                throw new RuntimeException(e);
            }
            return result;
        }
    
        @SuppressWarnings("rawtypes")
        public Map<String, Object> getMethodDescription(JoinPoint joinPoint) throws Exception {
            Map<String, Object> map = new HashMap<String, Object>();
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] arguments = joinPoint.getArgs();
            Class<?> targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        map.put("module", targetName.substring(targetName.lastIndexOf(".")+1,targetName.length()));
                        String methodStr = method.toString().substring(0,method.toString().lastIndexOf("(") );
                        methodStr = methodStr.substring(methodStr.lastIndexOf(".")+1,methodStr.length() );
                        map.put("methods", methodStr);
                        map.put("args", this.getArgs(method, arguments));
                        String desc = method.getAnnotation(SysAutoLog.class).description();
                        if (StringUtils.isEmpty(desc))
                            desc = "执行成功!";
                        map.put("description", desc);
                        break;
                    }
                }
            }
            return map;
        }
        
        private String getArgs(Method method, Object[] arguments) {
            StringBuilder builder = new StringBuilder("{");
            String params[] = parameterNameDiscoverer.getParameterNames(method);
            if(params.length==0) {
                return "无参数";
            }
            for (int i = 0; i < params.length; i++) {
                if(!"password".equals(params[i])) {
                    builder.append(params[i]).append(" : ").append(arguments[i]).append(";");
                }
            }
            return builder.append("}").toString(); 
        }
    }

     (4)配置springMVC.xml文件,启动AOP支持

    <!-- 该文件只注入Controller 类 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!-- 设置使用注解的类所在的jar包 -->
    <context:component-scan base-package="cn.test" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

     注意,关于springMVC.xml配置文件的写法,有几点需要注意:

    引用crawl+的博客http://www.cnblogs.com/crawl/p/7940755.html中的描述如下:

    use-default-filters 属性的默认值为 true,即使用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描,因为前面说过,我们希望 SpringMVC 只来控制网站的跳转逻辑,所以我们只希望 SpringMVC 的配置扫描 @Controllerce 注解标注的类,不希望它扫描其余注解标注的类,所以设置了 use-default-filters 为 false,并使用 context:include-filter 子标签设置其只扫描带有 @Controller 注解标注的类。

    在使用 use-default-filters 属性时要分清楚需要扫描哪些包,是不是需要使用默认的 Filter 进行扫描。楼主稍微总结一下,即 use-default-filters="false" 需要和 context:include-filter 一起使用,而不能和 context:exclude-filter 属性一起使用。

    (5)使用方式

    @ResponseBody
    @SysAutoLog(description="测试方法")
    @RequestMapping("testr")
    public String test(HttpServletRequest request) throws Exception {}

    只需要在方法上添加@SysAutoLog(description="")即我们自定义的注解即可,description是方法描述,这样在记录日志的时候可以一并记录下日志描述。

    四、总结:

    关于Spring AOP处理日志的实现比较简单,当然对于日志的统一处理也不止于这一种方式,还可以使用拦截器的方式,可以根据项目具体的应用环境选择合适的方式,有什么不当之处欢迎大家批评指正。

  • 相关阅读:
    ios testing
    Visual Studio文件自动定位功能
    如何:为 SharePoint 2013 中的 PerformancePoint Services
    sharepoint application page
    power rename batch files
    sharepoint app development configuration
    Installing and Configuring Workflow Manager 1.0
    安装用于 SharePoint 2013 的 Reporting Services SharePoint 模式
    ios dev tech
    Applications command line
  • 原文地址:https://www.cnblogs.com/ao-xiang/p/10997769.html
Copyright © 2020-2023  润新知