Spring MVC旧项目的日志埋点

一、HTTP接口切面

  1. web容器和应用容器
    IoC是Spring框架中的核心概念之一,如果要在Spring MVC中使用Spring的这一特性,也需要构建类似的容器。在Spring MVC中,主要通过web.xml进行Web相关的配置,例如配置DispatchServlet,以便应对url请求到具体的controller方法的映射。当DispatcherServlet启动的时候,它会创建一个对应的web应用上下文,负责加载web相关的组件,例如控制器、视图解析器以及处理器映射。在web.xml中,还有个常用配置:ContextLoaderListener,会创建一个Spring应用上下文,用于加载应用中的其他bean,例如各种Service、各种数据库访问层。借用官方文档-mvc servlet的一张图,可以看出,由ContextLoaderListener启动的容器为Root容器(父容器)、由DispatcherServlert启动的容器为Web容器(子容器),并且,子容器可以看到父容器中的bean,反之则不可。正是因为这个原因,在Controller层应用AOP技术的时候,要注意两点:(1)xxx-servlet.xml中的component-scan配置,要确定只扫描web组件、yyyyApplicationContext.xml中的component-scan配置,要排除掉web组件;(2)在xxx-servlet.xml中配置AOP,启动自动代理的配置为:,使用基于类的代理机制——CGLIB。

    Spring MVC旧项目的日志埋点_第1张图片
    mvc-context-hierarchy

  2. 基于注解的AOP应用
    我这里所谓基于注解的AOP技术,是指利用自定义注解标注要织入的切点,这种方式比较灵活,可以对指定接口中的某几个方法进行切面。例如,在这次处理日志埋点的需求中,我只给公开的接口加了注解:

import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BizLogAnnotation {
    String description() default "";
}

然后在xxxAspect中给出如下切点定义即可:

@Aspect
@Component
public class DubboLogAspect {
    @Pointcut(value = "@annotation(com.xxxx.dubbo.log.BizLogAnnotation)")
    public void hsfMethod() { }
    ……
}
  1. 从切点JoinPoint获取注解中的描述信息,该方法参考自一文,代码如下:
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;  
    }  

二、RPC服务接口切面

  1. 普通Service的AOP

三、Log4j日志配置

  1. 配置依赖,log4j + slf4j依赖
  2. 配置log4j.properties
  3. 修改代码中的Logger

四、补充资料

  1. 在阅读官方文档的时候,发现官方文档中也有对Controller AOP的阐述。

In some cases a controller may need to be decorated with an AOP proxy at runtime. One example is if you choose to have @Transactional annotations directly on the controller. When this is the case, for controllers specifically, we recommend using class-based proxying. This is typically the default choice with controllers. However if a controller must implement an interface that is not a Spring Context callback (e.g. InitializingBean, *Aware, etc), you may need to explicitly configure class-based proxying. For example with , change to .

  1. 当AOP遇到双上下文
  2. 为什么对Controller应用AOP的时候必须使用class-based的代理机制呢?这又涉及Spring中的两种代理机制:Java Proxy和CGLIB,Java Proxy要求被代理的类必须实现某个接口;CGLIB则属于基于子类的代理机制。参考What is the difference between JDK dynamic proxy and CGLib?

本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。


Spring MVC旧项目的日志埋点_第2张图片
javaadu

你可能感兴趣的:(Spring MVC旧项目的日志埋点)