nsdiv
nsdiv

Reputation: 983

Spring: Reference bean in @import file during annotation based Configuration

I have two spring Configuration classes A and B. Beans in B are imported in A using the @import annotation, like this

@Configuration
@Import({B.class})
public class A {
    private BBean bbean;

    @Bean
    public ABean aBean() {
        // need to reference B's bean over here
        return aBean()// after referencing B's bean
    }
}

@Configuration
public class B {
    @Bean
    public BBean bBean(){
       return new BBean();        
    }
}

How would I reference the bean bBean while creating bean aBean? One would think that @Required or @Autowired would work here, but it does not :(

UPDATE - What I'm trying to do here is run unit tests using TestNG and maven. When I try to reference the 'Autowired' bean, maven hangs, possibly in an infinite loop or waiting for the bean to be loaded.

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running TestSuite
13:15:42,427  INFO eans.factory.xml.XmlBeanDefinitionReader: 315 - Loading XML bean definitions from class path resource [META-INF/spring/app-context.xml]
13:15:42,589  INFO nnotation.ClassPathBeanDefinitionScanner: 210 - JSR-330 'javax.inject.Named' annotation found and supported for component scanning
13:15:42,671  INFO ontext.support.GenericApplicationContext: 495 - Refreshing org.springframework.context.support.GenericApplicationContext@45d6a56e: startup date [Fri Feb 15 13:15:42 PST 2013]; root of context hierarchy
13:15:42,769  INFO ctory.support.DefaultListableBeanFactory: 623 - Overriding bean definition for bean 'dataSource': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=repositoryConfig; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/abc/pagg/ddee/repository/config/RepositoryConfig.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=serviceConfig; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/abc/pagg/ddee/service/config/ServiceConfig.class]]
13:15:42,983  INFO ion.AutowiredAnnotationBeanPostProcessor: 139 - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
13:15:43,027  INFO ctory.support.DefaultListableBeanFactory: 557 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@66b51404: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,serviceConfig,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,transactionManager,sqlSessionFactory,org.mybatis.spring.mapper.MapperScannerConfigurer#0,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,commonConfig,propertiesConfig,repositoryConfig,iusRestManager,localCacheClientAdapter,memcachedClientAdapter,s3Adapter,dataSource,userMapper]; root of factory hierarchy  <<--- hangs right here

UPDATE - Real code here

@Configuration
@Import({CommonConfig.class})
public class ServiceConfig {
private final Logger log = LoggerFactory.getLogger(ServiceConfig.class);
private org.apache.commons.configuration.Configuration propertiesConfig;

@Autowired
public void setPropertiesConfig(org.apache.commons.configuration.Configuration propertiesConfig){
    this.propertiesConfig = propertiesConfig;
}

public ServiceConfig() {
}

@Bean
public DataSource dataSource() {
    final BasicDataSource dataSource = new BasicDataSource();
 --->   dataSource.setDriverClassName(propertiesConfig.getString("jdbc.driver")); <----
    //dataSource.setUrl(propertiesConfig.getString("jdbc.url"));
    //dataSource.setUsername(propertiesConfig.getString("jdbc.username"));
    //dataSource.setPassword(propertiesConfig.getString("jdbc.password"));

    return dataSource;
}

The bean propertiesConfig is defined in CommonConfig. I get an invocationTargetException on the highlighted line because propertiesConfig is null. The dataSource bean keeps on getting instantiated in a loop.

Upvotes: 2

Views: 8037

Answers (2)

Ryan Stewart
Ryan Stewart

Reputation: 128919

It's not the @Autowired causing your problem. From where you experience the hang, I expect you have a bean that does something on startup that's not finishing in a timely manner. Since the bean's initialization never finishes, Spring can't continue starting up. Some kind of network communication is most likely, as those have a bad habit of hanging indefinitely with no output unless specifically configured otherwise. Pull a stack dump when the JVM is hung, and see what your threads are doing. Otherwise, attach a debugger, and manually pause the JVM for the same effect.

Upvotes: 0

matt b
matt b

Reputation: 140061

The documentation for @Import mentions that you should use @Autowired in cases like the one you describe:

@Bean definitions declared in imported @Configuration classes should be accessed by using @Autowired injection. Either the bean itself can be autowired, or the configuration class instance declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly navigation between @Configuration class methods.

Upvotes: 2

Related Questions