jon*_*ejj 7 java spring annotations dependency-injection applicationcontext
如果需要,需要哪种配置?这不推荐?
带注释的类:
package com.springbug.beanfactorydependencyissue;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class DependantBean {
@Resource
DependencyBean dependencyBean; // Isn't initialized correctly
public DependencyBean getDependencyBean() {
return dependencyBean;
}
}
Run Code Online (Sandbox Code Playgroud)
失败的依赖bean:
package com.springbug.beanfactorydependencyissue;
import org.springframework.stereotype.Component;
@Component
public class DependencyBean {
}
Run Code Online (Sandbox Code Playgroud)
测试用例:
package com.springbug.beanfactorydependencyissue;
import static org.fest.assertions.Assertions.assertThat;
import javax.annotation.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;
import com.springbug.beanfactorydependencyissue.DependantBean;
@ContextConfiguration(locations = "/applicationContext.xml")
public class AppTest extends AbstractTestNGSpringContextTests {
@Resource
private DependantBean annotatedBean;
@Test
public void testThatDependencyIsInjected() {
// Fails as dependency injection of annotatedBean.dependencyBean does not work
assertThat(annotatedBean.getDependencyBean()).isNotNull();
}
}
Run Code Online (Sandbox Code Playgroud)
具有"错误"依赖关系的自定义BeanFactoryPostProcessor:
package com.springbug.beanfactorydependencyissue;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanFactoryPostProcessorConfiguration {
/**
* The {@link DependantBean} here causes the bug, can
* {@link BeanFactoryPostProcessor} have regular beans as dependencies?
*/
@Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor(
DependantBean dependantBean) {
return new BeanFactoryPostProcessor() {
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory)
throws BeansException {
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
applicationContext.xml中:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.springbug.beanfactorydependencyissue" />
</beans>
Run Code Online (Sandbox Code Playgroud)
为什么不能BeanFactoryPostProcessorConfiguration参考DependantBean?
生成的DependantBean实例AppTest不是null,即它是由spring创建的,但它的dependencies(DependencyBean)为null.Spring没有抱怨的事实让我相信这是春天的一个错误.是否应该支持这种用例?
顺便说一下,我正在使用spring - * - 3.1.1.RELEASE.jar顺便说一下2:重现bug的代码也可以在这里找到.
也许更简单和描述性的答案:
是的,可以使用@Componentbean作为BeanFactoryPostProcessor依赖项.
但是,a的每个依赖关系BeanFactoryPostProcessor都会在任何BeanPostProcessor活动之前被实例化.这些包括:
CommonAnnotationBeanPostProcessor-负责@PostConstruct,@Resource和其他一些注解AutowiredAnnotationBeanPostProcessor- 负责@Autowired和@Value注释所以总结一下:
是的,这是可以使用@Componentbean作为BeanFactoryPostProcessor依赖,但是他们不能使用基于注解注射(@Autowired,@Resource,@WebServiceRef,...),并提供其他功能BeanPostProcessor秒.
您的示例的解决方法可能是ApplicationContext按照您的建议创建层次结构:
其他方法可能是(我更喜欢):
BeanFactoryAware在@Componentbean 上使用接口并自己拉取依赖关系(因为Spring不会注入它).BeanFactoryPostProcessor在上下文配置中定义与s 连接的bean XML或@Configuration(即不要@Component用于这些bean).由于对 spring 进行了一些认真的调试,我们发现参数DependantBeantoBeanFactoryPostProcessorConfiguration导致了其他(完全不相关的)bean 的急切初始化。但随着春天的到来,BeanFactoryPostProcessor他们BeanPostProcessors还没有准备好。
阅读BeanFactoryPostProcessor的 javadoc (感谢 @Pavel 指出了这一点)准确地解释了这个问题:
BeanFactoryPostProcessor 可以与 bean 定义交互并修改 bean 定义,但绝不能与 bean 实例交互。这样做可能会导致 bean 过早实例化,从而破坏容器并导致意外的副作用。如果需要 Bean 实例交互,请考虑实现 {@link BeanPostProcessor}。
解决方案:
稍作修改applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.stackoverflow.springbug.beanfactorydependencyissue.other" />
</beans>
Run Code Online (Sandbox Code Playgroud)
新的bootstrapContext.xml:(请注意,只有软件包不同)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.stackoverflow.springbug.beanfactorydependencyissue.bootstrap" />
</beans>
Run Code Online (Sandbox Code Playgroud)
新的Contexts.java:(请注意,引导程序是常规 applicationContext 的父上下文)
package com.stackoverflow.springbug.beanfactorydependencyissue;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
public final class Contexts
{
private static Supplier<ApplicationContext> bootstrap = Suppliers.memoize(new Supplier<ApplicationContext>(){
public ApplicationContext get()
{
return new ClassPathXmlApplicationContext("/bootstrapContext.xml");
}
});
/**
* Context for beans that are needed before initializing of other beans.
*/
public static ApplicationContext bootstrap()
{
return bootstrap.get();
}
private static Supplier<ApplicationContext> applicationContext = Suppliers.memoize(new Supplier<ApplicationContext>(){
public ApplicationContext get()
{
return new ClassPathXmlApplicationContext(new String[]{"/applicationContext.xml"}, bootstrap());
}
});
public static ApplicationContext applicationContext()
{
return applicationContext.get();
}
}
Run Code Online (Sandbox Code Playgroud)
不BeanFactoryPostProcessorConfiguration带DependantBean参数:
package com.stackoverflow.springbug.beanfactorydependencyissue.other;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.stackoverflow.springbug.beanfactorydependencyissue.Contexts;
import com.stackoverflow.springbug.beanfactorydependencyissue.bootstrap.DependantBean;
@Configuration
public class BeanFactoryPostProcessorConfiguration
{
/**
* The {@link DependantBean} here caused the bug, {@link Contexts#bootstrap()} is used as a
* workaround.
*/
@Bean
public static BeanFactoryPostProcessor beanFactoryPostProcessor()
{
final DependantBean dependantBean = Contexts.bootstrap().getBean(DependantBean.class);
System.out.println(dependantBean.getDependencyBean());
return new BeanFactoryPostProcessor(){
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
让它发挥作用的最后一件事是移动DependantBean并DependencyBean放入bootstrap包中。@Value从数据库读取属性的目标已实现。同时重用 bean 的旧定义并且不重复 bean。
| 归档时间: |
|
| 查看次数: |
10040 次 |
| 最近记录: |