Java Spring引导REST服务器在Ubuntu服务器14.04上不工作
我已经用SpringBoot1.3.1编写了一个REST服务器,它在Windows7和Ubuntu服务器15.04上按预期运行。但是它在Ubuntu服务器14.04上没有,甚至所有的单元测试都失败了 问题的再现 因为我不确定是否忘记了US14.04上的设置,所以我安装了两个虚拟机。一个是Ubuntu服务器14.04,另一个是Ubuntu服务器15.10。 此外,我从相同的版本安装了Java8,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项目。然后我
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);
}
}