简体   繁体   English

一段时间后,生产春季启动应用程序将引发NoSuchBeanDefinitionException

[英]After a while, production spring boot app throws NoSuchBeanDefinitionException

We had a medium complicated spring boot 1.5.14 app with rest api + mybatis for backend, angular 4 with material/prime-ng for frontend. 我们有一个中等复杂的Spring Boot 1.5.14应用程序,后端使用api + mybatis,前端为4角,材质/ prime-ng。 It works fine from developers' box up to UAT environments, but in production, it works fine for the first couple of days, then throws NoSuchBeanDefinition. 从开发人员的盒子到UAT环境,它都可以正常工作,但是在生产中,它在头几天工作良好,然后抛出NoSuchBeanDefinition。 The production environment is openshift + openjdk version "1.8.0_171". 生产环境为openshift + openjdk版本“ 1.8.0_171”。

To trim down the app and leave related info, here are code snippets: 要精简应用程序并保留相关信息,请参见以下代码段:

public interface ITaxCalculator {
    BigDecimal calc(BigDecimal amount);
}

public class FedProvTaxCalculator implements ITaxCalculator {
    ... ...
}

@Configuration
public class TaxCalculatorConfiguration {
    ...
    @Bean("onTaxCalculator")
    public ITaxCalculator ontairioTaxCalculator() {
        FedProvTaxCalculator ret = ..
        ...
        return ret;
    }

    @Bean("bcTaxCalculator")
    public ITaxCalculator britishColumbiaTaxCalculator() {
        FedProvTaxCalculator ret = ..
        ...
        return ret;
    }

}

public class CAOrderProcessor implements IOrderProcessor {
    @Autowire @Qualifier("onTaxCalculator")
    private FedProvTaxCalculator onTaxCalculator;

    @Autowire @Qualifier("bcTaxCalculator")
    private FedProvTaxCalculator bcTaxCalculator;

    ....
}

// --------------- below code are at framework level -----

public interface IOrderProcessor {
    void process(Order order);
}

public interface IOrderProcessorFactory {
    IOrderProcessor createOrderProcessor(String countryCode, MembershipType membership);
}

@Service
public class OrderProcessorFactoryPropImpl implements IOrderProcessorFactory {
    @Autowired
    private AutowireCapableBeanFactory beanFactory;

    @Override
    @Cacheable("orderProcessor")
    public IOrderProcessor createOrderProcessor(String countryCode, MembershipType membership) {
        String clzName = resolveOrderProcessClzName(countryCode, membership);       // resolve to CAOrderProcess clz-name
        try {
            Object ret = Class.forName(clzName).newInstance();
            beanFactory.autowireBean(ret);          
            // the above line throws error after a while 
            return (IOrderProcessor)ret;
        } catch (Exception ex) {
          ...
          throw new RuntimeException(...);
        }
    }

    private String resolveOrderProcessClzName(String countryCode, MembershipType membership) {
        String clzName = lookupFromPropFile(countryCode + "." + membership.name());
        if (StringUtils.isBlank( clzName )) {
            clzName = lookupFromPropFile(countryCode);
        }
        return clzName;
    }
}

After restarting spring boot app, it works fine for the first couple of days, even with CA=CAOrderProcessor. 重新启动Spring Boot应用程序后,即使使用CA = CAOrderProcessor,它也可以在前几天正常工作。 But then one day, with countryCode=CA, it throws NoSuchBeanDefinitionException: No qualifying bean of type 'FedProvTaxCalculator' available: expected at least 1 bean which qualifies as autowire candidate. 但是有一天,使用countryCode = CA时,它抛出NoSuchBeanDefinitionException:没有可用的'FedProvTaxCalculator'类型的合格Bean:期望至少有1个有资格作为自动装配候选者的bean。 After restarting Java app, it works again for CA=CAOrderProcessor. 重新启动Java应用程序后,它可以再次用于CA = CAOrderProcessor。

Why does spring framework behave this way? Spring框架为什么会这样? Thanks in advance! 提前致谢!

The issue can be solved by 这个问题可以通过解决

@Configuration public class TaxCalculatorConfiguration {
    @Bean("onTaxCalculator")
    public ITaxCalculator ontairioTaxCalculator() { ... }
}
public class CAOrderProcessor implements IOrderProcessor {
    @Autowire @Qualifier("onTaxCalculator")
    private ITaxCalculator onTaxCalculator;
}

Using AutowireCapableBeanFactory is fine. 使用AutowireCapableBeanFactory很好。 Why does it work initially, and then fails, and only fails on one ENV - openshift with min 2 pods? 为什么它先开始工作,然后失败,然后仅在一个ENV上失败-带有最少2个吊舱的openshift? the other ENVs work fine always. 其他ENV总是可以正常工作。 Looks like spring relaxes autowire bean-type check initially, and later on under certain conditions, it checks the bean-type. 看起来像Spring最初放松了autowire bean类型的检查,然后在某些条件下,它检查了bean类型。 Logical guess is that bean-definition returns interface type, which may be proxied, bean-wiring refers a concrete type, the proxied interface doesn't equal concrete type, raising this error. 逻辑猜测是bean定义返回接口类型,该接口类型可能是代理类型,bean接线是具体类型,代理接口不等于具体类型,从而引发此错误。 But in that case, it should always give error. 但是在那种情况下,它应该总是出错。 If not, if I don't use the cache, or evict cache, I should be able to easily re-produce it in any ENVs, but it works fine on my local macos + oracle jdk 1.8. 如果没有,如果我不使用高速缓存或逐出高速缓存,我应该能够轻松地在任何ENV中重现它,但是它在我的本地macos + oracle jdk 1.8上可以正常工作。 I even create a docker container based on production openshift docker image to run the app without cache, evict cache, force YGC and FGC, it works fine too. 我什至基于生产openshift docker镜像创建了一个docker容器来运行应用程序而无需缓存,逐出缓存,强制YGC和FGC,它也可以正常工作。

I don't why behaves like that, probably because you use AutowireCapableBeanFactory directly and even worse then that in combination with @Cacheable . 我不为什么会这样,可能是因为您直接使用AutowireCapableBeanFactory ,甚至更糟地是与@Cacheable结合使用。

You should reconsider your framework level code . 您应该重新考虑 框架级别的代码 I believe that you should never use AutowireCapableBeanFactory directly and especially in your case. 我认为您绝对不应直接使用AutowireCapableBeanFactory ,尤其是在您的情况下。 It's simple and you can achieve the same result with less effort and using simple Map of country_code + membershi_type -> processor , for example: 这很简单,您可以通过使用country_code + membershi_type -> processor简单Map来轻松实现相同的结果,例如:

@Configuration
public class ProcessorConfiguration {
    . . .
    @Bean("cAOrderProcessor ")
    public IOrderProcessor cAOrderProcessor() [
       return new CAOrderProcessor();
    }
    . . .
    @Bean
    public IOrderProcessorFactory processorFactory() {
       // create country_code + membershi_type -> processor map

       Map<ProcessorKey, IOrderProcessor> processorMap = new HashMap<>();
       // not sure about values in MembershipType, so I put SOME just for example
       // this map also can be a bean if you're gonna need that in other parts of app
       processorMap.put(new ProcessorKey("CA", MembershipType.SOME), cAOrderProcessor());

       // set it to factory
       return new OrderProcessorFactoryPropImpl(processorMap );
    }
    . . .
}

public class OrderProcessorFactoryPropImpl implements IOrderProcessorFactory {
    private final Map<ProcessorKey, IOrderProcessor> processorMap;

    public OrderProcessorFactoryPropImpl(Map<ProcessorKey, IOrderProcessor> processorMap) {
        this.processorMap = processorMap;
    }

    @Override
    // @Cacheable("orderProcessor") you dont need that because get it from map costs nothing
    // changed the name to "get" instead of "create"
    public IOrderProcessor getOrderProcessor(String countryCode, MembershipType membership) {
        // just get processor by key
        return processorMap.get(constructKey(countryCode, membership));
    }

    private ProcessorKey constructKey(String countryCode, MembershipType membership) {
        return new ProcessorKey(countryCode, membership);
    }
}

Also I noticed that you mix java and annotation-based bean config which is considered as a bad practice. 我还注意到,您将Java和基于注释的bean配置混合使用,这被认为是不好的做法。 Hope this's going to help. 希望这会有所帮助。


Update 1 - Answering comment 更新1-回答评论

Well, to figure out what's wrong person's gonna need to full copy of your app to debug/logs and reproduce it's usual use cases. 好吧,要弄清楚出什么问题了,人们将需要完整复制您的应用程序以进行调试/记录并重现其通常的用例。 It's probably not possible to say what's wrong just looking at examples you've provided (at least for me). 仅查看您提供的示例(至少对我而言),就不可能说出问题所在。

And I just pointed out that the way you are using AutowireCapableBeanFactory is not up to best practices and that's why you have problems in your runtime. 我只是指出您使用AutowireCapableBeanFactory方式并不符合最佳实践,这就是为什么您的运行时遇到问题的原因。

So you probably have 2 solutions: 因此,您可能有两种解决方案:

  1. Get rid of it, and use somewhat different approach (maybe similar to the one I've suggested previously). 摆脱它,并使用一些不同的方法(可能与我之前建议的方法类似)。 I believe that's only one good option. 我相信那只是一个不错的选择。 But this is up to you to decide. 但这由您决定。

  2. Enable spring logs and hope that you will catch problem there. 启用spring日志,并希望在那里能够解决问题。 Probably need to enable debug logs like that in your log4j.xml (I suppose it's log4j but might be something else): 可能需要在log4j.xml启用类似的调试日志(我想它是log4j,但可能是其他东西):

<category name="org.springframework.beans"> <priority value="debug" /> </category>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Boot:NoSuchBeanDefinitionException - Spring Boot: NoSuchBeanDefinitionException Spring引导和JavaMailSender NoSuchBeanDefinitionException - Spring boot and JavaMailSender NoSuchBeanDefinitionException Vaadin Spring 引导 - 尝试导航到“”时出现异常 - NoSuchBeanDefinitionException - Vaadin Spring Boot - There was an exception while trying to navigate to '' - NoSuchBeanDefinitionException 使用 Java 模块测试 Spring 启动应用程序时出现 NoSuchBeanDefinitionException / UnsatisfiedDependencyException - NoSuchBeanDefinitionException / UnsatisfiedDependencyException when testing Spring Boot app with Java modules 带有多个JdbcTemplate和Spring Boot的NoSuchBeanDefinitionException - NoSuchBeanDefinitionException with Multiple JdbcTemplate and Spring Boot 在以下Spring代码中启动Google App Server时出现BeanCreationException NoSuchBeanDefinitionException - BeanCreationException NoSuchBeanDefinitionException while starting Google App Server for below Spring code Spring找不到bean并抛出NoSuchBeanDefinitionException - Spring can't find bean and throws NoSuchBeanDefinitionException 我在使用 JpaRepository 创建一个简单的 Spring Boot 项目时得到 NoSuchBeanDefinitionexception - I am getting NoSuchBeanDefinitionexception while creating a simple Spring Boot project with JpaRepository Spring-Boot可执行文件容器NoSuchBeanDefinitionException - Spring-Boot Executable-Jar NoSuchBeanDefinitionException Spring Boot DBUnit测试获取NoSuchBeanDefinitionException - Spring Boot DBUnit test getting NoSuchBeanDefinitionException
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM