Quarkus中如何在Servlet线程内注入Agroal数据源?注入为空求助
问题分析与解决方案
你的核心问题是手动创建的LoopThread不属于Quarkus CDI容器管理的Bean,因此@Inject注解不会被容器处理,导致datasource始终为null。Quarkus的依赖注入仅对容器实例化的对象生效,手动new出来的对象无法触发注入逻辑。此外,静态工具类持有数据源的方式也不符合Quarkus的设计规范,容易引发原生编译或上下文传播问题。
推荐解决方案:使用CDI管理的任务 + Quarkus线程池
以下是符合Quarkus最佳实践的实现方式:
1. 将循环任务改为CDI管理的Runnable Bean
避免手动继承Thread,改用Runnable并交由CDI容器管理,确保依赖能被正确注入:
@ApplicationScoped public class LoopTask implements Runnable { @Inject @Named("db") AgroalDataSource datasource; @Inject DbUtil dbUtil; @Override public void run() { try { dbUtil.setUserErrorLogged(false); // 直接使用注入的数据源执行事务 try (Connection conn = datasource.getConnection()) { // 执行数据库操作逻辑 LogUtil.debug("任务启动,数据库连接已获取"); } } catch (Exception ex) { LogUtil.error(ex); } } }
2. 将静态工具类DbUtil改为CDI Bean
移除静态状态,改用依赖注入管理数据源和状态:
@ApplicationScoped public class DbUtil { private boolean userErrorLogged; // 若需要直接操作数据库,可在此注入数据源 @Inject @Named("db") AgroalDataSource datasource; public boolean isUserErrorLogged() { return userErrorLogged; } public void setUserErrorLogged(boolean userErrorLogged) { this.userErrorLogged = userErrorLogged; } // 新增数据库操作方法,直接使用注入的数据源 public void executeSomeTransaction() throws SQLException { try (Connection conn = datasource.getConnection()) { // 事务逻辑 } } }
3. 在Servlet中使用Quarkus管理的线程池启动任务
使用ManagedExecutorService提交任务,这是Quarkus推荐的异步任务执行方式,支持上下文传播,适配原生编译模式:
@WebServlet(urlPatterns = "/your-servlet-path", loadOnStartup = 1) public class YourServlet extends HttpServlet { @Inject ManagedExecutorService executor; @Inject LoopTask loopTask; @Override public void init() throws ServletException { super.init(); // 提交任务到Quarkus线程池 executor.submit(loopTask); } }
备选方案:手动传递依赖(不推荐)
如果坚持使用手动创建的Thread,可以在Servlet中先注入数据源,再通过构造函数传递给线程:
@WebServlet(urlPatterns = "/your-servlet-path", loadOnStartup = 1) public class YourServlet extends HttpServlet { @Inject @Named("db") AgroalDataSource datasource; @Override public void init() throws ServletException { super.init(); LoopThread thread = new LoopThread(datasource); thread.start(); } } // 修改LoopThread构造函数接收数据源 class LoopThread extends Thread { private final AgroalDataSource datasource; public LoopThread(AgroalDataSource datasource) { this.datasource = datasource; } @Override public void run() { try { DbUtil.userErrorLogged = false; DbUtil.initDataSource(datasource); LogUtil.debug("线程启动"); // 执行数据库操作 } catch (Exception ex) { LogUtil.error(ex); } } }
注意:此方式不推荐,手动创建的线程不受Quarkus生命周期管理,原生编译模式下可能出现上下文丢失或资源泄漏问题。
内容的提问来源于stack exchange,提问作者Vidath Adheesha
相关产品推荐
相关产品推荐

