Java Spring引导REST服务器在Ubuntu服务器14.04上不工作

Java Spring引导REST服务器在Ubuntu服务器14.04上不工作,java,spring,ubuntu,spring-boot,Java,Spring,Ubuntu,Spring Boot,我已经用SpringBoot1.3.1编写了一个REST服务器,它在Windows7和Ubuntu服务器15.04上按预期运行。但是它在Ubuntu服务器14.04上没有,甚至所有的单元测试都失败了 问题的再现 因为我不确定是否忘记了US14.04上的设置,所以我安装了两个虚拟机。一个是Ubuntu服务器14.04,另一个是Ubuntu服务器15.10。 此外,我从相同的版本安装了Java8,Java-version显示了相同的版本。之后,我从存储库安装了Maven并克隆了我的git项目。然后我

我已经用SpringBoot1.3.1编写了一个REST服务器,它在Windows7和Ubuntu服务器15.04上按预期运行。但是它在Ubuntu服务器14.04上没有,甚至所有的单元测试都失败了

问题的再现 因为我不确定是否忘记了US14.04上的设置,所以我安装了两个虚拟机。一个是Ubuntu服务器14.04,另一个是Ubuntu服务器15.10。 此外,我从相同的版本安装了Java8,
Java-version
显示了相同的版本。之后,我从存储库安装了Maven并克隆了我的git项目。然后我运行了
mvn clean install

这将执行单元测试,单元测试在VM US 14.04上失败,并显示与US 14.04相同的错误消息。在VM US 15.10上,单元测试可以正常运行

错误 在我的REST服务器中,我从一个数据库加载元数据(用户、权限、数据库连接),然后加载实际数据。 为了在代码中区分这一点,我有两个类用
@Configuration
注释:
MetadataConf
RealDataConf

MetadataConf
的设置方式是创建
UserRepository
。这是通过
@EnableJpaRepositories(entityManagerFactoryRef=“metaDataEntityManagerFactory”,basePackages=“com.somename.data.metadata.repository”)完成的,
transactionManagerRef=“metaDataTransactionManager”)

RealDataConf
中,
UserRepository
是自动连接的

@Configuration
@EnableJpaRepositories(repositoryFactoryBeanClass = ExtendedRepositoryFactoryBean.class,
                       entityManagerFactoryRef = "realDataEntityManagerFactory",
                       basePackages = "com.somename.data.realdata.repository",
                       transactionManagerRef = "realDataTransactionManager")
@EnableTransactionManagement
public class RealDataConf
{
  @Autowired
  UserRepository userRepository;

  // FooBar is a POJO and as not annotations
  @Bean
  FooBar foobar()
  {
    // ...
    if(userRepository == null)
    {
      throw new Exception("UserRepository must not be null.");
    }
    return new FooBar(userRepository);
  }

  // ...

}
我添加了null检查以使堆栈跟踪更清晰,因为否则稍后会抛出NPE并创建非常长的堆栈跟踪。 无论如何,在US 14.04机器上,始终会引发此异常,而在其他操作系统上,则不会引发此异常。因此,由于某些原因,存储库不是自动连接的,也不是作为
null
注入的

最简单的解决方案可能是升级Ubuntu。或者切换到更新的内核? 但另一方面,我担心我犯了一个错误,这也可能发生在其他操作系统上

(我发布了尽可能少的代码和解释,以避免问题变得臃肿,如果需要更多代码,我当然会提供)

编辑 我尝试将存储库添加为方法参数。然后,在运行单元测试时,我在US 14.04上遇到以下错误(在Win7上进行修改后,没有问题):

短版 经过进一步的研究,我和我的同事发现在有故障的系统上,Bean的创建顺序是错误的

为了确保顺序正确,我们在应用程序中添加了
@ComponentScan({“com.somename.first”、“com.somename.second”、“com.somename.third”、“com.somename.forth”})
。 由于某种原因,
@DependsOn
对故障系统没有影响

长版本 通过向
@Configuration
类的
@PostConstruct
@Bean
方法添加日志输出,我们检测到错误的顺序。工作系统上的日志条目顺序与预期一致,但故障系统上的日志条目顺序不一致。因此,
UserRepository
还无法构建,因此
null
。此外,日志中根本没有出现一个
@Configuration

在第一次尝试中,我们尝试使用
@DependsOn
。为了确保正确使用它,我们通过反转
@Configuration
类的依赖关系来中断工作系统上的应用程序。之后,我们按照预期的顺序更改注释,以便它在工作系统上再次工作。但在有缺陷的系统上没有成功

在一次绝望的尝试中,我的同事向我们的主类添加了
@ComponentScan
,将包的顺序作为参数。包
com.somename.first
包含必须首先构建的
@Configuration
类,依此类推。这最终说服了故障系统以所需的顺序创建
Bean
s,REST服务器按预期运行

毕竟,我们不知道为什么这种行为发生在一个系统上而不是另一个系统上

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
    JpaRepositoriesAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
@ComponentScan({"com.somename.first", "com.somename.second", "com.somename.third", "com.somename.forth"})
public class Application
{
  static ConfigurableApplicationContext c;

  public static void main(String[] args)
  {
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    c = SpringApplication.run(Application.class, args);
  }
}

不要将
userRepository
自动连接为属性,只需将其添加为
@Bean
方法的方法参数即可<代码>foobar(UserRepository UserRepository)。然后看看它是否仍然发生。@M.Deinum请查看我的编辑是您的
FooBar
,是否以
@Service
或类似方式注释?虽然不确定为什么会发生这种情况,但似乎没有按正确的顺序调用正确的方法。它是在正确设置
FactoryBean
之前进行初始化。这是奇怪的,因为它在其他系统上工作…有趣的问题:)。在我看来,
userRepository
和`metadataUserRepository`作为名称,您在这里输入的代码是否正确。您能否提供一个复制此问题的最小项目?我怀疑这是因为您自己有
@EnableJpaRepositories
(您可能正在使用多个实体管理器?)。也许ubuntu/windows中的加载顺序改变了。是的,我想我会升级/重新安装ubuntu,希望它能像预期的那样工作。重现这个问题将成为我周末的新项目
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
    JpaRepositoriesAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
@ComponentScan({"com.somename.first", "com.somename.second", "com.somename.third", "com.somename.forth"})
public class Application
{
  static ConfigurableApplicationContext c;

  public static void main(String[] args)
  {
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    c = SpringApplication.run(Application.class, args);
  }
}