我看到了一些奇怪的行为,我希望这里的人能对这个问题有所了解。
让我先描述一下我的设置。首先,一个简单的数据对象
public class Apple {
private String name;
public Apple withName(String name) {
this.name = name;
return this;
}
public String getName() {
return name;
}
}
和一个测试类..
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={TestConfig.class})
public class AppleTest {
@Autowired private Apple apples;
@Test
public void simpleTest() {
System.out.println("OBJ: "+apples);
}
}
配置如下
@Configuration
public interface ConfigInterface {
public Apple getApple();
}
使用实现类
@Configuration
@Import(AbstractTestConfig.class)
public class TestConfig implements ConfigInterface {
public Apple getApple() {
return new Apple().withName("Granny apples");
}
}
具有配置依赖项。。。
@Configuration
public class AbstractTestConfig {
@Autowired ConfigInterface conf;
@Bean Apple myTestApple() {
return conf.getApple();
}
}
所有这些都很好用。我运行测试,看到我期望的输出。但是后来我把一个扳手扔进轮子里,修改AbstractTestConfig,如下所示。
@Configuration
public class AbstractTestConfig {
@Autowired ConfigInterface conf;
@Bean Apple myTestApple() {
return conf.getApple();
}
// NEW CODE
@Bean CustomScopeConfigurer scopeConfigurer() {
return new CustomScopeConfigurer();
}
}
当需要构建Apple
bean时,@Autowired
对象conf
突然变为空。
更奇怪的是,如果我将 CustomScopeConfigurer
bean 移动到 TestConfig
类,那么它就可以工作了。
关于作用域或是CustomScopeConfigurer
对象,有什么我不知道的吗?
从Spring@Bean javadoc复制:
BeanFactoryPostProcessor-return @Bean 方法
必须特别考虑返回SpringBeanFactoryPostProcessor(BFPP)类型的@Bean方法。由于BFPP对象必须在容器生命周期的早期实例化,因此它们可能会干扰@Configuration类中的@Autowired、@Value和@PostConstruct等注释的处理。为了避免这些生命周期问题,将BFPP返回@Bean方法标记为静态。例如:
@Bean
public static PropertyPlaceholderConfigurer ppc() {
// instantiate, configure and return ppc ...
}
通过将此方法标记为静态,可以在不导致实例化其声明的@Configuration类的情况下调用它,从而避免上述生命周期冲突。然而,请注意,静态@Bean方法不会像上面提到的那样针对作用域和AOP语义进行增强。这在BFPP情况下是可行的,因为它们通常不会被其他@Bean方法引用。作为提醒,将为任何具有可分配给BeanFactoryPostProcessor的返回类型的非静态@Bean方法发出WARN级日志消息。