SpringMVC's AOP interception controller

use

Generally implement log management (the way of custom annotation).

First of all, why do we need to do log management? We often encounter system exceptions or problems in the actual online. At this time, immediately open the CRT or SSH to connect to the server for analysis. Subject to various limitations of the network. So we wondered why we can't view the error message directly in the management background. So log management appeared.

Secondly, I personally think that Aop is the best for log management, and some people also like to use interceptors. Either way, here I will focus on my implementation.

Some people in Aop say that the Controller cannot be intercepted. Some people say that if you want to block AnnotationMethodHandlerAdapter to intercept Controller, you must intercept org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.

First of all, Aop can intercept the Controller, which is unquestionable. Secondly, it is not necessary to intercept the AnnotationMethodHandlerAdapter. At least I haven't verified this successfully. My spring version is 4.0.3.

The reason why some people in Aop say that the Controller cannot be intercepted is because the Controller is represented by the jdk. We just hand it over to the cglib proxy.

The first step is to define two annotations:

package com.yj.aop;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**  
 *自定义注解 拦截Controller  
 */ 
@Target({ElementType.PARAMETER, ElementType.METHOD})//只能方法使用
@Retention(RetentionPolicy.RUNTIME)//表明注解可以变jvm编译
@Documented
public @interface SystemControllerLog {

    String description() default "";

}



package com.yj.aop;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**  
 *自定义注解 拦截service  
 */   
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemServiceLog {

    String description() default "";
}

The second step is to create a pointcut class

package com.yj.aop;

import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 切点类
 * @author jing
 *
 */
@Aspect
@Component
public class SystemLogAspect {

    //controller层切点
    @Pointcut("@annotation(com.yj.aop.SystemControllerLog)")
    public void controllerAspect(){};
    //service层切点
    @Pointcut("@annotation(com.yj.aop.SystemServiceLog)")
    public void serviceAspect(){};

    @Before("controllerAspect()")
    public void deBefore(JoinPoint joinPoint){

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
 //       HttpSession session = request.getSession();        
        //请求的IP    
        String ip = request.getRemoteAddr();    
         try {    
            //*========控制台输出=========*//    
            System.out.println("=====前置通知开始=====");    
            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
            System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));    
            System.out.println("请求人:" + "1111");    
            System.out.println("请求IP:" + ip);       
            System.out.println("=====前置通知结束=====");    
        }  catch (Exception e) {    
            e.printStackTrace();    
        }    
    }

    /**  
     * 异常通知 用于拦截service层记录异常日志  
     *  
     * @param joinPoint  
     * @param e  
     */    
    @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")    
     public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {    
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
        //获取请求ip    
        String ip = request.getRemoteAddr();    
         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("请求人:" + "请求人");    
            System.out.println("请求IP:" + ip);    
            System.out.println("请求参数:" + "请求参数");    
            System.out.println("=====异常通知结束=====");    
        }  catch (Exception ex) {    
             e.printStackTrace();
        }    

    }    

    /**  
     * 获取注解中对方法的描述信息 用于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(SystemControllerLog. class).description();    
                     break;    
                }    
            }    
        }    
         return description;    
    }    

     /**  
      * 获取注解中对方法的描述信息 用于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(SystemServiceLog. class).description();    
                      break;    
                 }    
             }    
         }    
          return description;    
     }    
}    

The third step is to write the configuration file and hand over the proxy rights of the Controller to cglib

1. To be clear, we are monitoring aop on SpringMVC, then all report scanning and injection are done in the configuration file of SpringMVC, do not complete it in the configuration file of spring, otherwise, after the proxy is turned on, it is found that it still does not play any role. .

2. Scan the controller

<!-- 扫描controller(controller层注入) -->
    <context:component-scan base-package="com.yj.controller"/>

3. Of course, if you use the service layer for this AOP pointcut, you need to add

<!-- 扫描service(service层注入) -->
    <context:component-scan base-package="com.yj.service"/>

4. Point-cut scanning. (This scan can be achieved with or without addition, you can Baidu for the specific difference)

<!--切点类路径-->
<context:component-scan base-package="com.ht.annotation" annotation-config="true"/>

5. Turn on his proxy mode in the SpringMVC configuration file

<!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller-->
    <aop:aspectj-autoproxy proxy-target-class="true" />

The fourth step is to use

use of controller

package com.yj.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.yj.aop.SystemControllerLog;

@Controller()
public class TextController {

    @RequestMapping("text")
    @SystemControllerLog(description="aop测试")
    public void text(){
        System.out.println("text    运行");
    }
}

use of service

    //此处为AOP拦截Service记录异常信息。方法不需要加try-catch 
    @SystemServiceLog(description="aop测试")
    public void text(){
        System.out.println("text    运行");
    }

The fifth step is to use the jar (here I will write maven)

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.0</version>
            </dependency>

Reference: http://blog.csdn.net/czmchen/article/details/42392985
Reference: http://blog.csdn.net/tianjun2012/article/details/47809739

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325835810&siteId=291194637