2014-03-30 74 views
2

我试图用Spring创建一个计划任务,但我可能没有正确地在配置中公开@Bean。我的代码如下:春季计划任务

@Configuration 
@PropertySource("classpath:hibernate.properties") 
@EnableJpaRepositories("org.app.repository") 
@ComponentScan("org.app") 
@EnableTransactionManagement 
@EnableScheduling 
public class JpaConfiguration { 

    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver"; 
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password"; 
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url"; 
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username"; 

    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect"; 
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql"; 
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = 
      "entitymanager.packages.to.scan"; 

    @Resource 
    private Environment env; 

    @Bean 
    public DataSource dataSource() { 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 

     dataSource.setDriverClassName(
       env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER)); 
     dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL)); 
     dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME)); 
     dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD)); 

     return dataSource; 
    } 

    @Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 

     // will set the provider to 'org.hibernate.ejb.HibernatePersistence' 
     HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
     // will set hibernate.show_sql to 'true' 
     vendorAdapter.setShowSql(true); 
     // if set to true, will set hibernate.hbm2ddl.auto to 'update' 
     vendorAdapter.setGenerateDdl(true); 

     LocalContainerEntityManagerFactoryBean emfBean = new 
       LocalContainerEntityManagerFactoryBean(); 
     emfBean.setDataSource(dataSource()); 
     emfBean.setJpaVendorAdapter(vendorAdapter); 
     emfBean.setPersistenceProviderClass(
       org.hibernate.jpa.HibernatePersistenceProvider.class); 

     emfBean.setPackagesToScan(
       env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN)); 

     emfBean.setJpaProperties(hibProperties()); 

     return emfBean; 
    } 

    private Properties hibProperties() { 
     Properties properties = new Properties(); 
     properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, 
       env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT)); 
     properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, 
       env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL)); 
     return properties; 
    } 

    @Bean 
    public JpaTransactionManager transactionManager() { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(entityManagerFactory().getObject()); 
     return transactionManager; 
    } 

    @Bean 
    public ThreadPoolTaskScheduler taskScheduler() { 
     ThreadPoolTaskScheduler ts = new ThreadPoolTaskScheduler(); 
     ts.initialize(); 
     ts.setPoolSize(8); 
     ts.setWaitForTasksToCompleteOnShutdown(true); 
     return ts; 
    } 
} 

@Component 
public class MainBean { 

    @Autowired 
    private MyRunnable myRunnable; 

    @Autowired 
    private CategoryRepo categoryRepo; 

    @Autowired 
    private ThreadPoolTaskScheduler taskScheduler; 

    public void start() { 

      //This works 
     categoryRepo.findAll().forEach(System.out::println); 


     //this throws an exception 
     taskScheduler.execute(myRunnable); 

     //if i use an infinite loop here in order to prevent 
     //the method from exiting everything works normal 
     // while(true) { 
     // Thread.sleep(10000000); 
     // } 
     System.out.println("Application Started. . ."); 
    } 
} 

类别回购

public interface CategoryRepo extends JpaRepository<Category, String> { 

} 

Runnable接口

@Component 
public class MyRunnable implements Runnable { 



    @Autowired 
    private CategoryRepo categoryRepo; 

    @Override 
    public void run() { 


     try { 
      List<Category> list = categoryRepo.findAll(); 
      list.forEach(System.out::println); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

另外,如果我不使用调度,我只是做

myRunnable.run(); 

它正常执行。

任何人都有一个想法,我做错了什么,或者可能是一个替代方法?

编辑:我的pom.xml依赖如下(春天是4.0.2,你可以在属性标签看):

<properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <spring.version>4.0.2.RELEASE</spring.version> 
    </properties> 

    <dependencies> 

     <!--Hibernate Dependencies--> 
     <dependency> 
      <groupId>org.hibernate.javax.persistence</groupId> 
      <artifactId>hibernate-jpa-2.1-api</artifactId> 
      <version>1.0.0.Final</version> 
     </dependency> 

     <dependency> 
      <groupId>org.hibernate</groupId> 
      <artifactId>hibernate-core</artifactId> 
      <version>4.3.4.Final</version> 
     </dependency> 

     <dependency> 
      <groupId>org.hibernate</groupId> 
      <artifactId>hibernate-c3p0</artifactId> 
      <version>4.3.4.Final</version> 
     </dependency> 

     <dependency> 
      <groupId>org.hibernate</groupId> 
      <artifactId>hibernate-entitymanager</artifactId> 
      <version>4.3.4.Final</version> 
     </dependency> 

     <dependency> 
      <groupId>org.hibernate</groupId> 
      <artifactId>hibernate-validator</artifactId> 
      <version>5.0.3.Final</version> 
     </dependency> 


     <!-- Spring Dependencies --> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context-support</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-jdbc</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-orm</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-tx</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework.data</groupId> 
      <artifactId>spring-data-jpa</artifactId> 
      <version>1.5.1.RELEASE</version> 
     </dependency> 


     <!--CGLIB is required to process @Configuration classes--> 
     <dependency> 
     <groupId>cglib</groupId> 
     <artifactId>cglib</artifactId> 
     <version>3.1</version> 
     </dependency> 

     <!--Other Dependencies--> 
     <dependency> 
      <groupId>org.jsoup</groupId> 
      <artifactId>jsoup</artifactId> 
      <version>1.7.2</version> 
     </dependency> 

     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>slf4j-api</artifactId> 
      <version>1.7.6</version> 
     </dependency> 

     <dependency> 
      <groupId>log4j</groupId> 
      <artifactId>log4j</artifactId> 
      <version>1.2.17</version> 
     </dependency> 

     <dependency> 
      <groupId>mysql</groupId> 
      <artifactId>mysql-connector-java</artifactId> 
      <version>5.1.28</version> 
     </dependency> 


    </dependencies> 

而Java是1.8 - 也试图与1.7和有相同的结果

编辑:

显然,我认为这个问题是程序在退出,离开Spring上下文。因此,当runnable执行时,线程无法找到entitymanager。

如果我使用一个无限而MainBean前右环退出然后一切正常执行

+0

请发布您正在使用的库版本。 –

回答

2

不幸的是,我还没有找到任何令人满意的答案。我发现唯一非正统的解决方案(在我看来)是做一个无限循环,不允许程序退出如下:

public void start() { 

    System.out.println("Application Started. . ."); 

    taskScheduler.scheduleAtFixedRate(myRunnable, Date.from(Instant.now()), 
      TimeUnit.DAYS.toMillis(1)); 

    while (true) { 
     try { 
      Thread.sleep(Long.MAX_VALUE); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

我有同样的问题,并注意到,如果我用一个使用@PersistenceContext注释的DAO替换回购它工作正常。不知道为什么它不会执行回购方法。 –

1

好像在春季启动或Spring 4 https://github.com/spring-projects/spring-boot/issues/253

一个已知的错误,因为它似乎,调度口罩真正的问题在甩掉这个奇怪的错误。

在你的情况,因为它正好与调度情况,我会尝试做一个异常断点找出哪些类型的异常是在这种情况下被隐藏的被抛出。

2

的根本原因是

Caused by: java.lang.NoSuchMethodError: org.app.config.JpaConfiguration.setBeanFactory(Lorg/springframework/beans/factory/BeanFactory;)V 

一个NoSuchMethodError几乎总是表明,有一个版本的问题与您的构建。应用程序试图执行在编译时可用的方法,但不是在运行时。换句话说,编译时的类路径与运行时的类路径不同。

spring-data-jpa版本1.5.1.RELEASE使用Spring 3.2.8进行编译,但是您提供了4.0.2.RELEASE的Spring库。但是,它的构建方式是将它委托给项目的实际依赖项(如果存在的话)。在当前的设置,它会使用以下

<artifactId>spring-context-support</artifactId> 
<artifactId>spring-context</artifactId> 
<artifactId>spring-jdbc</artifactId> 
<artifactId>spring-orm</artifactId> 
<artifactId>spring-tx</artifactId> 

4.0.2.RELEASE版本,但它将使用版本3.2.8.RELEASE

<artifactId>spring-core</artifactId> 
<artifactId>spring-beans</artifactId> 

这些都是典型的依赖spring-context具有相同的版本,但这里似乎他们被spring-data-jpa覆盖。

最简单的,但也许不完全(根据您的配置的其余部分),是明确声明和两个依赖

<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-core</artifactId> 
    <version>${spring.version}</version> 
</dependency> 
<dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-beans</artifactId> 
    <version>${spring.version}</version> 
</dependency> 

所以spring-data-jpa现在委托给这些。或者,除非您使用Spring的某些功能4.0.2.RELEASE,否则您可以摆脱所有其他Spring依赖关系,只保留spring-data-jpa。它将负责拉动另一个Spring库。

+0

我尝试了两种解决方案。它仍然通过包含两个缺失的依赖关系来提供相同的错误。我不能真正使用其他解决方案,因为3.2.8不支持我想使用的Java 1.8。 – ChrisGeo

+0

@ChrisGeo你确定它是一样的错误吗?我试着用你已经显示的代码进行尝试,它对我有用。也许你还有别的干扰? –

+0

显然,这个错误与JPA有关,如果我运行一个像System.out.println(“Something”)这样的简单runnable,那没关系。我会更新一些JPA代码,以防万一您能发现某些东西 – ChrisGeo