Spring 多线程bean的问题(Spring+Javaweb中任务调度)

本文探讨了在Spring框架中实现定时任务时@Autowired注入失败的问题及其原因。介绍了如何通过正确配置Spring容器避免注入失败,以及使用工具类获取Bean的方法。

在写一个文件暂存系统的时候,有这样的一个需求:一个定时任务,每隔t分钟,做一些扫描操作。

实现思路是继承ContextLoaderListener,实现自己的Listener,在这个Listener中,开启定时任务。

一开始直接使用@Componet注解+@Autowired注解,结果导致注入失败。

由于一开始没意识到是线程的原因,所以在上网搜的原因及解决方案都是无效的,但也有一些有用的知识:

1.一般@Autowired注入失败有以下一个原因:

1.包没扫描到。

2.controller层的@controller或者service层的@Service注解没写

3.如果使用@Resource 注入service需要注意对象名字。

2.默认情况下,<context:component-scan>查找使用构造型(stereotype)注解所标注的类,如@Component(组件)@Service(服务),@Controller(控制器),@Repository(数据仓库)。

3.SpringSpringMVC整合的问题,二者在整合的时候,会产生两个容器,一个Spring容器,一个SpringMVC容器。Spring容器是父容器,SpringMVC容器是Spring容器的子容器。Spring容器初始化后,SpringMVC再进行初始化,并将Spring容器作为它的父容器。

子容器能够访问父容器的bean,而反之不行。

当父容器的初始化路径(base-package)等于或者包括了子容器的路径,那么可能出现,当SpringMVC子容器初始化时,如果发现有相同的类,会将新初始化的实例覆盖Spring容器中已经存在的实例,这可能导致注入失败,空指针的问题。

所以要做到2个容器要扫描的包必须相互区分,互不干扰。Spring容器扫描非Controller的实例,而SpringMVC容器扫描Controller的实例就行。

 

 

然后在一个论坛中得知了是线程的原因:

“因为主线程中可以直接使用@Autowired注解进行注入,但是在新开的线程中就不可以进行注入,每次启动服务器就会报空指针异常,新开启的线程直接就挂掉了,网上也搜了好多,原来是spring不会去管理这个新的线程,所以也就注入不进去任何bean。注解得方式最终都不能注入。

有以下几种方式来获取,我使用的是:通过工具类获取。Spring工具类获取bean

这种方法必须要把该工具类在SpringApplicationContext中注册bean,这样Spring才能通过工具类的set方法给其注入context。这样也带出了这种方法的弊端:工具类必须在Spring容器初始化完之后才能工作。

在现有的实现思路的基础上,这个弊端立刻就显现出来了,在自己重写的WebContextListener运行的时候,Spring容器是没有初始化的!所以会报空指针异常。

解决思路:工具类必须在Spring容器初始化完后才可以正常工作,那么可以找一个合适的位置开启(仅开启一次)任务调度器。

 

### Bean 注入问题 - **问题描述**:可能出现 Bean 注入失败,如某个 Bean 的属性未注入,采用延迟加载形式注入 Bean 时,只有在使用到该 Bean 调用 `getBean()` 方法才会抛出异常 [^1]。 - **解决办法**:检查配置文件确保组件扫描和自动装配设置正确,使用正确注解定义和注入 Bean,保证依赖版本兼容以及 Bean 类在正确类路径下,避免循环依赖。例如,在 `applicationContext.xml` 中配置组件扫描: ```xml <context:component-scan base-package="com.example.demo" /> ``` 使用注解注入: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class ExampleService { // 业务逻辑 } @Service public class AnotherService { @Autowired private ExampleService exampleService; // 其他逻辑 } ``` ### Bean 初始化问题 - **问题描述**:在 Spring Bean 初始化阶段可能出现问题,初始化方法执行顺序混乱或未执行 [^2]。 - **解决办法**:了解初始化方法执行顺序,确保 `@PostConstruct` 标注方法、实现 `InitializingBean` 接口的 `afterPropertiesSet()` 方法、自定义初始化方法按顺序正确执行。例如: ```java import javax.annotation.PostConstruct; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Service; @Service public class InitExampleService implements InitializingBean { @PostConstruct public void postConstructMethod() { // 初始化逻辑 } @Override public void afterPropertiesSet() throws Exception { // 初始化逻辑 } public void customInitMethod() { // 自定义初始化逻辑 } } ``` ### Bean 销毁问题 - **问题描述**:当 Spring 容器关闭时,Bean 的资源未正确释放 [^3]。 - **解决办法**:可以让 Bean 实现 `DisposableBean` 接口,在 `destroy` 方法中编写资源释放逻辑;或者在 XML 配置中为 `<bean>` 标签指定 `destroy - method` 属性,在注解配置中通过 `@Bean` 注解的 `destroyMethod` 属性指定销毁方法。例如: ```java import org.springframework.beans.factory.DisposableBean; import org.springframework.stereotype.Service; @Service public class DestroyExampleService implements DisposableBean { @Override public void destroy() throws Exception { // 资源释放逻辑,如关闭数据库连接 } } ``` ### 获取 Bean 问题 - **问题描述**:在 Java Web 中可能无法正确获取 Spring 容器中的 Bean [^4]。 - **解决办法**:可以使用 `ClassPathXmlApplicationContext` 来获取 Bean,示例如下: ```java import org.springframework.context.support.ClassPathXmlApplicationContext; public class GetBeanExample { public static void main(String[] args) { ClassPathXmlApplicationContext beanFac = new ClassPathXmlApplicationContext("classpath:serviceImpl.xml"); Object bean = beanFac.getBean("exampleBean"); // 使用 Bean } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值