我在尝试使用AnnotationConfigApplicationContext
定义上下文层次结构时遇到问题。
问题在于在beanRefContext.xml
中定义模块上下文并使用另一个上下文(基于XML / Annotated)设置'parent'属性。
示例:
模块A中的beanRefContext.xml
<bean id="moduleA_ApplicationContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <property name="configLocations"> <list> <value>classpath:db-context.xml</value> </list> </property> </bean>
DB-context.xml中
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="org.h2.Driver" p:url="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL;TRACE_LEVEL_SYSTEM_OUT=2"/> <!-- Hibernate Session Factory --> <bean name="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="useTransactionAwareDataSource" value="true"/> <property name="packagesToScan"> <list> <value>com.example.model</value> </list> </property> <property name="hibernateProperties"> <!-- hibernate props --> </property> </bean>
模块B中的beanRefContext.xml
<bean id="moduleB_ApplicationContext" class="org.springframework.context.annotation.AnnotationConfigApplicationContext" > <property name="parent" ref="moduleA_ApplicationContext"/> <constructor-arg> <list> <value>com.example.dao</value> </list> </constructor-arg> </bean>
FooHibernateDao
class FooHibernateDao implements FooDao { @Autowired @Qualifier("sessionFactory") private SessionFactory sessionsFactory; // CRUD methods }
模块B应用程序上下文无法在模块A应用程序上下文中找到定义的bean
通过查看AnnotationConfigApplicationContext
的代码,似乎扫描过程不会使用父作为解析bean的参考。
是否存在我做错的事情,或者使用注释配置无法尝试创建层次结构?
答案 0 :(得分:6)
问题源于AnnotationConfigApplicationContext的构造函数执行扫描的事实。因此,父级未设置在此阶段,仅在扫描完成后设置,因为父级由属性设置 - 因此它找不到您的bean的原因。
默认的AnnotationConfigApplicationContext bean没有一个带有父工厂的构造函数 - 不知道为什么。
您可以使用常规的基于xml的应用程序上下文并在其中配置注释扫描,也可以创建一个自定义的fatory bean来创建注释应用程序上下文。这将指定父引用,然后执行扫描。
看一下来源......
工厂看起来像这样:
public class AnnotationContextFactory implements FactoryBean<ApplicationContext> {
private String[] packages;
private ApplicationContext parent;
@Override
public ApplicationContext getObject() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setParent(parent);
context.scan(packages);
context.refresh();
return context;
}
@Override
public Class<ApplicationContext> getObjectType() {
return ApplicationContext.class;
}
@Override
public boolean isSingleton() {
return true;
}
public void setPackages(String... args) {
this.packages = args;
}
public void setParent(ApplicationContext parent) {
this.parent = parent;
}
}
你的bean定义:
<bean id="moduleB_ApplicationContext" class="za.co.test2.AnnotationContextFactory">
<property name="parent" ref="moduleA_ApplicationContext" />
<property name="packages">
<list>
<value>za.co.test2</value>
</list>
</property>
</bean>
答案 1 :(得分:3)
不要将XML用于子上下文。 使用ctx.setParent然后使用ctx.register。像这样:
public class ParentForAnnotationContextExample {
public static void main(String[] args) {
ApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentContext.class);
AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
childContext.setParent(parentContext);
childContext.register(ChildContext.class); //don't add in the constructor, otherwise the @Inject won't work
childContext.refresh();
System.out.println(childContext.getBean(ParentBean.class));
System.out.println(childContext.getBean(ChildBean.class));
childContext.close();
}
@Configuration
public static class ParentContext {
@Bean ParentBean someParentBean() {
return new ParentBean();
}
}
@Configuration
public static class ChildContext {
@Bean ChildBean someChildBean() {
return new ChildBean();
}
}
public static class ParentBean {}
public static class ChildBean {
//this @Inject won't work if you use ChildContext.class in the child AnnotationConfigApplicationContext constructor
@Inject private ParentBean injectedFromParentCtx;
}
}
答案 2 :(得分:1)
我遇到了同样的问题,
另一种可能性是扩展AnnotationConfigApplicationContext并仅添加所需的构造函数或以编程方式构建上下文(如果要从java实例化AnnotationConfigApplicationContext)。
答案 3 :(得分:0)
我做的是以下内容:
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance("classpath:beanRefContext.xml");
BeanFactoryReference parentContextRef = locator.useBeanFactory("ear.context");
ApplicationContext parentContext = (ApplicationContext) parentContextRef.getFactory();
childContext.setParent(parentContext);
猜猜是什么,工作:)
PS:如果有人知道如何用@Configuration类替换classpath:beanRefContext.xml,请大家知道。
答案 4 :(得分:0)
我也遇到了类似的问题,经过一些研究,我发现使用AnnotationConfigApplicationContext中的构造函数可以在上下文之间设置层次结构的以下方法
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parentContext);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(lbf);
context.register(annotatedClass1.class, annotatedClass2.class);
context.refresh();