Levancho
Levancho

Reputation: 149

Spring Java based config "chicken and Egg situation"

Just recently started looking into Spring and specifically its latest features, like Java config etc. I have this somewhat strange issue:

Java config Snippet:

@Configuration
@ImportResource({"classpath*:application-context.xml","classpath:ApplicationContext_Output.xml"})
@Import(SpringJavaConfig.class)
@ComponentScan(excludeFilters={@ComponentScan.Filter(org.springframework.stereotype.Controller.class)},basePackages = " com.xx.xx.x2.beans")
public  class ApplicationContextConfig extends WebMvcConfigurationSupport {
    private static final Log log = LogFactory.getLog(ApplicationContextConfig.class);

    @Autowired
    private Environment env;

    @Autowired
    private IExtendedDataSourceConfig dsconfig;    

    @PostConstruct
    public void initApp() {
     ...

    }   

    @Bean(name="transactionManagerOracle")
    @Lazy
    public DataSourceTransactionManager transactionManagerOracle() {
        return new DataSourceTransactionManager(dsconfig.oracleDataSource());
    }

IExtendedDataSourceConfig has two implementations which are based on spring active profile one or the other in instantiated. For this example let say this is the implementation :

@Configuration
@PropertySources(value = {
        @PropertySource("classpath:MYUI.properties")})
@Profile("dev")
public class MYDataSourceConfig implements IExtendedDataSourceConfig {
    private static final Log log = LogFactory.getLog(MYDataSourceConfig.class);

    @Resource
    @Autowired
    private Environment env;

    public MYDataSourceConfig() {
        log.info("creating dev datasource");
    }

    @Bean
    public DataSource oracleDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        dataSource.setUrl(env.getProperty("oracle.url"));
        dataSource.setUsername(env.getProperty("oracle.user"));
        dataSource.setPassword(env.getProperty("oracle.pass"));
        return dataSource;
    }

The problem is that when transactionManagerOracle bean is called, (even if I try to mark it as lazy) dsconfig variable value appears to be null.

I guess @beans are processed first and then all Autowires, is there a fix for this? How do I either tell spring to inject dsconfig variable before creating beans, or somehow create @beans after dsconfig is injected?

Upvotes: 1

Views: 360

Answers (1)

dunni
dunni

Reputation: 44535

You can just specify DataSource as method parameter for the transaction manager bean. Spring will then automatically inject the datasource, which is configured in the active profile:

@Bean(name="transactionManagerOracle")
@Lazy
public DataSourceTransactionManager transactionManagerOracle(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

If you still want to do this through the configuration class, specify that as parameter:

public DataSourceTransactionManager transactionManagerOracle(IExtendedDataSourceConfig dsconfig) {}

In both ways you declare a direct dependency to another bean, and Spring will make sure, that the dependent bean exists and will be injected.

Upvotes: 1

Related Questions