Spring4升级Spring5:移除SpringBeanAutowiringInterceptor是否可行?
一、两种注入方式的核心差异
1. 适用场景与实例归属
- 原方式(
@Interceptors(SpringBeanAutowiringInterceptor.class)+@Autowired):
这种方式是给非Spring容器管理的类(比如JAX-RS资源类、EJB、第三方框架创建的实例)注入Spring Bean。因为这些类不是Spring创建的,Spring本身无法自动完成装配,所以通过拦截器在实例创建后,主动触发Spring的自动装配逻辑,给@Autowired字段赋值。类的生命周期由创建它的容器(而非Spring)控制。 - 新方式(
@Inject):
既然测试正常,说明你的foo类现在已经是Spring容器管理的Bean(比如加了@Component/@Service等注解),此时Spring在创建Bean实例时直接完成@Inject的注入;或者依托了支持JSR-330规范的容器(如CDI)。@Inject是JSR-330标准注解,不绑定Spring,通用性更强。
2. 注入触发逻辑
- 原方式:注入动作由拦截器触发,时机在实例被创建后、方法执行前(拦截器的拦截逻辑),属于"事后补注入"。
- 新方式:如果是Spring管理Bean,注入动作在Bean实例化、初始化阶段由Spring容器完成,属于"原生注入",时机更早,是Spring Bean生命周期的一部分。
3. 注解规则细节
@Autowired是Spring专属注解,支持required属性(默认true,注入失败会抛异常),配合@Qualifier指定Bean名称;@Inject是JSR-330标准注解,无required属性,要实现可选注入需搭配@Nullable(Spring扩展)或@Optional(JSR-330规范),配合@Named指定Bean名称。
二、变更后的潜在影响
1. 实例归属变化带来的风险
如果后续foo类的创建方式发生改变(比如改回由非Spring容器创建),@Inject将无法自动注入,而原拦截器方式只要拦截器生效就能完成注入。需确保后续类的创建逻辑始终由Spring容器管控。
2. 生命周期行为变化
原方式中,foo类的生命周期由非Spring容器管理,Spring不会处理它的@PostConstruct、@PreDestroy等生命周期注解;若现在foo是Spring管理Bean,Spring会自动执行这些方法。需检查类中是否有这类方法,确认其执行不会引发业务逻辑异常。
3. 多实现Bean的注入风险
如果SomeBean存在多个实现类,原方式中@Autowired配合@Qualifier指定Bean,新方式中@Inject需要配合@Named指定。若之前依赖@Qualifier的逻辑未同步调整,后续新增SomeBean实现时可能出现NoUniqueBeanDefinitionException。
4. 兼容性适配
@Inject依赖JSR-330规范,Spring5使用javax.inject包,若未来升级到Spring6,需替换为jakarta.inject包(Java EE转Jakarta EE的规范变更),提前做好依赖包的版本规划。
5. 拦截器隐含逻辑丢失
SpringBeanAutowiringInterceptor除了注入Bean,还会确保实例能感知Spring上下文(比如实现ApplicationContextAware)。如果原foo类依赖了上下文感知的能力,现在改为@Inject后,若未通过其他方式(比如实现ApplicationContextAware或注入ApplicationContext)补充,可能导致相关逻辑失效。
内容的提问来源于stack exchange,提问作者Nikhil

