1️⃣ 核心概念

Spring MVC 的拦截器(HandlerInterceptor)可以用两种方式注册:

  1. 由 Spring 管理的 Bean 注入

    • 通过 @Component@Bean 注入

    • 拦截器内部可以使用 @Autowired 注入其他 Bean

  2. 直接 new 一个对象

    • 拦截器内部不依赖 Spring Bean,完全自给自足

    • 不会触发 Spring 的依赖注入和生命周期管理

  3. 什么时候用哪个?

         3.1.拦截器需要依赖注入的情况

                如果拦截器中需要通过 @Autowired 注入属性,例如:

@Component
public class TokenIntercept implements HandlerInterceptor {
    @Autowired
    private RedisTemplate redisTemplate;
}
  • 则拦截器类必须加上 @Component,由 Spring 容器管理。

  • WebMvcConfigurer 中必须通过 @Autowired 注入该拦截器:

@Autowired
private TokenIntercept tokenIntercept;
  • 如果使用 new TokenIntercept() 直接创建实例,拦截器内部的 redisTemplate 将会是 null,依赖注入无法生效。

         3.2.拦截器不依赖注入的情况

                如果拦截器内部不需要通过 @Autowired 注入属性,则类上加不加 @Component 都可以。

  • WebMvcConfigurer 中可以通过 @Autowired 注入,也可以直接 new 实例:

registry.addInterceptor(new LoginInterceptor());
  • 因为拦截器内部没有依赖注入的属性,所以无论 Spring 管理与否,都不会影响拦截器的功能。


2️⃣ 为什么要注意这个区别?

情况 方法 原因
拦截器内部需要注入其他 Bean(Redis、JWT、Service 等) 通过 Spring 注入 (@Component + @Autowired) 直接 new 拦截器不会触发依赖注入,内部对象为 null
拦截器内部不需要依赖 Bean 可以直接 new 简单轻量,不依赖 Spring 管理

💡 关键点:是否依赖 Spring 注入决定能否直接 new。


3️⃣ 例子对比

3.1 通过 Spring 注入

@Component
public class TokenIntercept implements HandlerInterceptor {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("拦截器拦截请求");
        String token = request.getHeader("token");
        if (token == null) return false;
        String userId = jwtUtil.parseJWT(token);
        String redisToken = (String) redisUtil.get("token:userId:" + userId);
        return token.equals(redisToken);
    }
}

@Configuration
public class TokenInterceptConfig implements WebMvcConfigurer {
    @Autowired
    private TokenIntercept tokenIntercept; // 注入 Spring 管理的 Bean

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenIntercept)
                .excludePathPatterns("/login/**","/register/**")
                .addPathPatterns("/**");
    }
}

✅ 特点:

  • TokenIntercept 内部依赖 RedisUtilJwtUtil

  • 必须通过 @Autowired 注入,不能 new


3.2 直接 new 对象

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("登录拦截器拦截请求");
        return true;
    }
}

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) // 直接 new
                .excludePathPatterns("/login/**", "/register/**");
    }
}

✅ 特点:

  • 拦截器内部没有依赖 Spring Bean

  • 直接 new 就可以使用

  • 生命周期由程序管理,Spring 不会干预


4️⃣ 总结

  1. 是否依赖注入 决定拦截器是否可以直接 new:

    • 依赖注入 → 必须通过 Spring 容器管理

    • 不依赖 → 可直接 new

  2. 注意事项

    • 如果直接 new,会导致拦截器内部的 @Autowired 失效

    • Spring 管理的 Bean 可以享受 AOP、事务、依赖注入等功能

  3. 最佳实践

    • 推荐:所有需要依赖注入的拦截器都使用 Spring 容器管理

    • 简单拦截器(如日志、统计、权限判断)可以直接 new

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐