《Spring实战》学习:jdbcTemplate bean创建偶现找不到dataSource错误
问题根源
设置激活Profile的时序错误是导致偶现启动失败的核心原因:
你重写onStartup方法时先执行了super.onStartup(servletContext),该方法会直接触发Spring上下文的完整初始化流程,包括Bean定义的解析、Profile匹配、Bean实例化。而你是在super.onStartup执行完成后才向ServletContext设置spring.profiles.active参数,此时Spring已经完成了Profile匹配逻辑,两个标注了@Profile的dataSource Bean都没有被注册到容器中,因此后续创建jdbcTemplate时会抛出找不到dataSource的异常。
问题偶现是因为Servlet容器的参数读取逻辑存在时序波动,极少数情况下Spring上下文初始化时能读取到提前写入的参数,但该逻辑并不稳定。
额外说明:你添加的@DependsOn注解没有实际作用,Spring会自动根据方法参数的依赖关系控制Bean创建顺序,jdbcTemplate的入参要求注入DataSource,本来就会等待DataSource创建完成后再实例化。
解决方案
方案1:调整onStartup执行顺序
将参数设置逻辑放到super.onStartup之前,保证Spring初始化前能读取到激活的Profile:
@Override public void onStartup(ServletContext servletContext) throws ServletException { // 先设置Profile参数 servletContext.setInitParameter("spring.profiles.active", "prod"); // 再执行上下文初始化 super.onStartup(servletContext); }
方案2:重写Initializer的Profile指定方法(更稳妥)
直接重写AbstractAnnotationConfigDispatcherServletInitializer提供的Profile配置方法,优先级高于Servlet上下文参数,不会出现时序问题:
// 指定DispatcherServlet对应Web上下文的激活Profile @Override protected String[] getServletProfiles() { return new String[]{"prod"}; } // 如果你的dataSource配置在根上下文,还可以重写根上下文的Profile配置 @Override protected String[] getRootProfiles() { return new String[]{"prod"}; }
内容的提问来源于stack exchange,提问作者LIL PIGGY
相关产品推荐
相关产品推荐

