我试图用Spring创建一个Scheduled任务,但是我可能没有做正确的事情来暴露@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> {

}


可运行

@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依赖项如下(Spring是4.0.2,如您在properties标记中看到的):

    <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 Context。因此,当执行runnable时,线程找不到实体管理器。

如果我在MainBean退出之前使用无限while循环,那么一切都会正常执行

最佳答案

根本原因是

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 3.2.8.RELEASE库。

09-25 22:54
查看更多