Spring Boot使用Spring Profile忽略Java配置类中的bean

10

当我在Eclipse上使用经典上下文加载运行我的应用程序时,没有任何问题,与所选择的Spring配置文件相对应的配置类中定义的Bean正确地被实例化。

public class BasketHandlerLoader {

    public static void main(String[] args) throws Exception {
        @SuppressWarnings("resource")
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:config/spring/spring-archibald-basket-handler-context.xml");
        context.registerShutdownHook();
    }
}

但是,当我使用Spring Boot运行应用程序时,这些bean没有被实例化。

@Configuration
@ImportResource("classpath:config/spring/spring-archibald-basket-handler-context.xml")
public class BasketHandlerLoader {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(BasketHandlerLoader.class, args);
    }
}

这是用于"dev" Spring配置文件的Java配置类:

@Configuration
@Profile("dev")
@EnableTransactionManagement
@PropertySources(value = { @PropertySource("classpath:filters/dev.properties") })
public class DevPersistenceConfig extends AbstractPersistenceConfig {

    @Inject
    private Environment env;

    @Override
    @Bean
    public DataSource dataSource() {
        return super.createDataSource(env);
    }

    @Override
    public Properties hibernateProperties() {
        return super.createHibernateProperties(env);
    }
}

这里是包含其他未实例化bean的AbstractPersistenceConfig类:

public abstract class AbstractPersistenceConfig {

    // Constants...

    // ************************** ABSTRACT METHODS **************************

    /**
    * Returns a property list containing the Hibernate properties.
    * 
    * @return the Hibernate properties.
    */
    public abstract Properties hibernateProperties();

    /**
    * Defines the application datasource bean corresponding with the current Spring Profile.
    * 
    * @return the application datasource bean corresponding with the current Spring Profile.
    */
    @Bean
    public abstract DataSource dataSource();

    /**
    * Defines the Hibernate session factory bean.
    * 
    * @return the {@code LocalSessionFactoryBean}.
    */
    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { HIBERNATE_PACKAGE_TO_SCAN });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    /**
    * Defines the bean allowing to Hibernate to support the transaction handling mechanism.
    * 
    * @return the {@code HibernateTransactionManager}.
    */
    @Bean
    public HibernateTransactionManager transactionManager() {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory().getObject());
        return txManager;
    }

    // ************************** PROTECTED METHODS **************************

    // ...

    // ************************** PRIVATE METHODS **************************

    // ...
}

我尝试使用相同的命令运行应用程序,但结果相同:

java -jar archibald-basket-handler-1.0-SNAPSHOT.jar --spring.profiles.active=dev

java -jar -Dspring.profiles.active=dev archibald-basket-handler-1.0-SNAPSHOT.jar

具体来说,bean“sessionFactory”未实例化,无法注入到我的GenericDaoImpl类中...

堆栈跟踪:

java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
        at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'basketDaoImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.hibernate.SessionFactory fr.ina.archibald.dao.impl.GenericDaoImpl.sessionFactory; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.inject.Inject()}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
        at fr.ina.archibald.basket.loader.BasketHandlerLoader.main(BasketHandlerLoader.java:30)
        ... 6 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.hibernate.SessionFactory fr.ina.archibald.dao.impl.GenericDaoImpl.sessionFactory; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.inject.Inject()}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
        ... 21 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.     Dependency annotations: {@javax.inject.Inject()}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
        ... 23 more

我使用的是Spring Boot 1.0.2.RELEASE,但没有使用Spring Boot的父POM。我只是在POM文件中定义了以下内容:

<dependencyManagement>
    <dependency>
        <!-- Import dependency management from Spring Boot -->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${org.springframework.boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencyManagement>

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <mainClass>${start-class}</mainClass>
    </configuration>
</plugin>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-integration</artifactId>
    <version>${org.springframework.boot.version}</version>
</dependency>

你有一些想法吗?

非常感谢!!


如果您在Eclipse中使用dev配置文件,将BasketHandlerLoader作为main运行,是否会得到相同的结果? - Artem Bilan
谢谢你的帮助。是的,在Eclipse上结果一样... - Didasko
“DevPersistenceConfig”是否被主方法加载并不明显,它们之间有什么联系? - Dave Syer
我不确定是否理解您的问题。但是,DevPersistenceConfig是由在XML文件上定义的组件扫描加载的。当我在Eclipse上运行此应用程序时,它可以正常工作,而且当我通过Tomcat在我的Web应用程序中加载相同的Spring上下文(相同的XML文件)时也可以正常工作。 - Didasko
正如我在下面的答案中所说,DevPersistenceConfig是由Spring实例化的,但不包括@Bean方法。因此,“dataSource()”、“sessionFactory()”和其他bean方法都没有被实例化... - Didasko
2个回答

8
我认为您需要直接导入您的@Configuration类或使用@ComponentScan注解。您最初使用ClassPathXmlApplicationContext的示例将起作用,因为XML处理发生在早期,而将在处理之前找到您的@Configuration类。 在第二个示例中,SpringApplication已经开始处理您的@Configuration类,并且通过@ImportResource加载XML。此时,XML 无法添加更多@Configuration。 简短回答:尝试在BasketHandlerLoader类上使用@ComponentScan。

0

太好了!它起作用了! 非常感谢Phil(解决方案和解释!):-)

@Configuration
@ImportResource("classpath:config/spring/spring-archibald-basket-handler-context.xml")
@ComponentScan(basePackages = { "fr.ina.archibald.dao.config.persistence" }, includeFilters = @ComponentScan.Filter(value = Component.class, type = FilterType.ANNOTATION))
public class BasketHandlerLoader {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(BasketHandlerLoader.class, args);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接