Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring's JavaConfig and CustomScopeConfigurer issue

Tags:

java

spring

I'm seeing some odd behavior, I was hoping someone here can shine some light on the issue.

Let me start by describing my setup. First, a simple data object

public class Apple {
    private String name;
    public Apple withName(String name) {
        this.name = name;
        return this;
    }
    public String getName() {
        return name;
    }
}

And a test class..

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={TestConfig.class})
public class AppleTest {
    @Autowired private Apple apples;

    @Test
    public void simpleTest() {
        System.out.println("OBJ: "+apples);
    }
}

The config is as follows

@Configuration
public interface ConfigInterface {
    public Apple getApple();
}

With an implementing class

@Configuration
@Import(AbstractTestConfig.class)
public class TestConfig implements ConfigInterface {
    public Apple getApple() {
        return new Apple().withName("Granny apples");
    }
}

With the config dependency...

@Configuration
public class AbstractTestConfig {
    @Autowired ConfigInterface conf;

    @Bean Apple myTestApple() {
        return conf.getApple();
    }
}

All of this works great. I run the test, I see the output I expect. But then I throw a spanner into the wheel and modify AbstractTestConfig to look as follows.

@Configuration
public class AbstractTestConfig {
    @Autowired ConfigInterface conf;

    @Bean Apple myTestApple() {
        return conf.getApple();
    }

    // NEW CODE
    @Bean CustomScopeConfigurer scopeConfigurer() {
        return new CustomScopeConfigurer();
    }
}

And all of a sudden the @Autowired object conf is null when it is required to construct the Apple bean.

Even more odd, if I move the CustomScopeConfigurer bean to the TestConfig class, then it works.

Is there something I don't know about scopes or the CustomScopeConfigurer object in particular?

like image 379
jabalsad Avatar asked Feb 18 '13 17:02

jabalsad


1 Answers

Copied from Spring @Bean javadoc:

BeanFactoryPostProcessor-returning @Bean methods

Special consideration must be taken for @Bean methods that return Spring BeanFactoryPostProcessor (BFPP) types. Because BFPP objects must be instantiated very early in the container lifecycle, they can interfere with processing of annotations such as @Autowired, @Value, and @PostConstruct within @Configuration classes. To avoid these lifecycle issues, mark BFPP-returning @Bean methods as static. For example:

@Bean
 public static PropertyPlaceholderConfigurer ppc() {
     // instantiate, configure and return ppc ...
 }

By marking this method as static, it can be invoked without causing instantiation of its declaring @Configuration class, thus avoiding the above-mentioned lifecycle conflicts. Note however that static @Bean methods will not be enhanced for scoping and AOP semantics as mentioned above. This works out in BFPP cases, as they are not typically referenced by other @Bean methods. As a reminder, a WARN-level log message will be issued for any non-static @Bean methods having a return type assignable to BeanFactoryPostProcessor.

like image 191
Luciano Avatar answered Nov 07 '22 18:11

Luciano