Java过滤器-拦截器-AOP-Controller

1 对比

组件 核心用途 主要应用场景
‌**过滤器 (Filter)**‌ 在请求到达Servlet之前或响应返回客户端之前,对原始的ServletRequestServletResponse进行预处理或后处理。 字符编码设置、敏感词过滤、URL级别的权限认证、请求日志记录。‌12
‌**拦截器 (Interceptor)**‌ 在请求进入Controller方法前后,以及视图渲染前后,对请求进行拦截和处理。它基于Spring的反射机制。 权限认证、审计日志、请求参数预处理、响应数据包装。‌12
‌**切面 (AOP)**‌ 通过"切面"技术,在不修改目标方法代码的情况下,横向切入业务逻辑,实现功能的扩展和解耦。它基于动态代理(如JDK Proxy或CGLIB)。 方法级别的权限控制、日志记录、事务管理、缓存操作、方法执行时间监控。‌13
ControllerAdvice 全局异常处理和数据绑定/预处理,专门用于增强Controller层。(也是基于AOP) 统一的全局异常处理、统一的数据格式化、统一的请求参数预处理。‌13

使用过程中需要注意执行顺序和和优先级。

2 Servlet

在Java Web应用程序中,Servlet是处理HTTP请求和响应的核心组件,Servlet的生命周期:

1 加载和实例化

当服务器启动时,会加载web.xml中配置的Servlet或者在注解为@WebServlet的类。

服务器将为每个Servlet创建一个实例。

  1. 初始化

在Servlet实例创建后,会调用init(ServletConfig config)方法进行初始化。

这个方法通常用于执行仅需执行一次的初始化操作,比如加载资源文件、打开数据库连接等。

  1. 请求处理

当客户端发送请求到服务器时,服务器会调用Servlet的service(ServletRequest req, ServletResponse res)方法。

在Servlet 3.0及更高版本中,推荐使用doGet(HttpServletRequest request, HttpServletResponse response)

和doPost(HttpServletRequest request, HttpServletResponse response)等方法来分别处理GET和POST请求。

  1. 服务

在每次接收到新的请求时,service方法或相应的doXxx方法会被调用,用于处理请求并生成响应。

  1. 销毁

当Web应用被卸载或服务器关闭时,会调用Servlet的destroy()方法。这个方法用于释放资源,比如关闭数据库连接、停止线程等。

注意事项:

‌单例性‌:默认情况下,Servlet是单例的,即整个Web应用生命周期内只会有一个Servlet实例。这意味着所有的客户端请求将共享同一个Servlet实例。如果Servlet需要处理大量并发请求,应确保其线程安全。

‌多线程‌:由于Servlet是单例的,多个请求可能会并发地执行service方法或其子方法(如doGet, doPost)。因此,编写Servlet时需要考虑线程安全。可以使用同步块或并发工具类来管理共享资源的访问。

‌生命周期管理‌:可以通过覆盖init和destroy方法来管理资源的初始化和清理工作。对于非单例的Servlet,可以使用@WebServlet(value="/path", loadOnStartup=1)注解来控制加载顺序和时机

3 动态代理

维度 Java动态代理‌(基于JDK) CGLIB代理‌(基于ASM)
实现原理 通过反射机制生成实现目标接口的代理类 通过ASM字节码操作生成目标类的子类
适用场景 目标类必须实现接口 目标类无需实现接口,支持类级别的代理
性能 通常稍逊于CGLIB,但差异可忽略 性能更优,尤其在无接口场景下
限制 无法代理final类或方法 无法代理final类
实现方式 java.lang.reflect.Proxy + InvocationHandler net.sf.cglib.proxy.Enhancer
使用场景 接口多、结构清晰的项目 无接口类、老项目或性能敏感场景

JDK Proxy

反射和接口

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义目标接口
interface TargetInterface {
    void doSomething();
}

// 实现目标接口
class TargetImpl implements TargetInterface {
    @Override
    public void doSomething() {
        System.out.println("TargetImpl method");
    }
}

// 代理处理器
class TargetProxy implements InvocationHandler {
    private TargetInterface targetInterface;

    public TargetProxy(TargetInterface targetInterface) {
        this.targetInterface = targetInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + "前置处理");
        Object result = method.invoke(targetInterface, args);
        System.out.println(method.getName() + "后置处理");
        return result;
    }

    public TargetInterface getProxyInstance() {
        return (TargetInterface) Proxy.newProxyInstance(
            TargetProxy.class.getClassLoader(),
            targetInterface.getClass().getInterfaces(),
            this
        );
    }
}

// 测试类
public class JDKDynamicProxyExample {
    public static void main(String[] args) {
        TargetInterface target = new TargetImpl();
        TargetProxy proxyHandler = new TargetProxy(target);
        TargetInterface proxy = proxyHandler.getProxyInstance();
        proxy.doSomething();
    }
}

CGLIb

SM字节码操作生成目标类的子类

java 复制代码
public class TargetClass {
    public void doSomething() {
        System.out.println("TargetClass.doSomething()执行");
    }
    
    public String getValue(String input) {
        return "处理结果: " + input;
    }
}

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("前置增强: " + method.getName());
        Object result = proxy.invokeSuper(obj, args); // 调用父类方法
        System.out.println("后置增强: " + method.getName());
        return result;
    }
}

import net.sf.cglib.proxy.Enhancer;

public class CglibProxyDemo {
    public static void main(String[] args) {
        // 创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(TargetClass.class);
        // 设置回调
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        TargetClass proxy = (TargetClass) enhancer.create();
        
        // 调用方法
        proxy.doSomething();
        String result = proxy.getValue("CGLIB测试");
        System.out.println(result);
    }
}
相关推荐
你怎么知道我是队长4 小时前
C语言---枚举变量
c语言·开发语言
李慕婉学姐4 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
吃茄子的猫4 小时前
quecpython中&的具体含义和使用场景
开发语言·python
云栖梦泽4 小时前
易语言中小微企业Windows桌面端IoT监控与控制
开发语言
数据大魔方4 小时前
【期货量化实战】日内动量策略:顺势而为的短线交易法(Python源码)
开发语言·数据库·python·mysql·算法·github·程序员创富
奋进的芋圆5 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin6 小时前
设计模式之桥接模式
java·设计模式·桥接模式
Edward.W6 小时前
Python uv:新一代Python包管理工具,彻底改变开发体验
开发语言·python·uv
小熊officer6 小时前
Python字符串
开发语言·数据库·python
model20056 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端