我们说我创建了一个名为@EnableFeauture
的注释,它导入了一个bean配置类EnableFeatureConfiguration
。此注释通常位于调度程序配置之上。像视图解析器等必须的bean属于该调度程序配置,但是一些bean实际上属于根上下文。
如何在不需要其他注释的情况下定义这些bean?我的第一个想法是自动装配WebApplicationContext
并致电context.getParentBeanFactory()
来注册豆类,但我不确定这是否是实现目标的最佳方式。这通常是怎么做的?
稍微澄清一下这个问题。我正在开发一个项目,将模板引擎与Spring MVC集成在一起。该项目包括以下类别/部分:
EnableFeature
(导入配置)逻辑上,所有类类别都可以存在于Web应用程序上下文中。但是,模板工厂也可以被其他服务使用(电子邮件等)。主要存在于根上下文中的服务。所以我基本上要问的是,如何以干净的方式使工厂可用于根上下文。我希望配置尽可能低。截至目前,设置只需要在调度程序配置类的顶部放置一个注释。
答案 0 :(得分:3)
我花了一些时间来清楚地了解你想做什么以及超越的含义。从servlet中查找根应用程序上下文可以是一个简单的部分,context.getParentBeanFactory()
,或直接context.getParent()
在任何ApplicationContextAware
类中立即提供它,或者直接注入ApplicationContext
}。
困难的部分是,在初始化servlet应用程序上下文时,根应用程序上下文已经刷新。如果我看看Tomcat会发生什么:
DispatcherServlet
初始化子上下文作为父上下文。这意味着当初始化servlet上下文时,在根上下文中注入bean是为时已晚:所有单例bean都已创建。
可能有解决方法,都有自己的缺陷:
我的结论是,针对2个不同的应用程序上下文进行单一配置有点违反Spring哲学,我建议您保留2个单独的配置类,一个用于根上下文,另一个用于servlet上下文。但是如果你愿意,我可以详细说明从servlet上下文刷新根上下文(第一个解决方案)。
如果要将bean从 feature 注入根上下文中,而 feature 将在servlet上下文中声明为具有单个配置点,则可以使用以下内容:
@Configuration
public class FeatureConfig implements ApplicationContextAware {
static boolean needInit = true;
@Override
// Register the configuration class into parent context and refreshes all
public void setApplicationContext(ApplicationContext ac) throws BeansException {
AnnotationConfigWebApplicationContext parent =
(AnnotationConfigWebApplicationContext) ((AnnotationConfigWebApplicationContext) ac).getParent();
if (needInit) { // ensure only one refresh
needInit = false;
parent.register(RootConfig.class);
parent.refresh();
((AnnotationConfigWebApplicationContext) ac).refresh();
}
}
@Configuration
@Conditional(NoParentContext.class)
// Can only be registered in root context
public static class RootConfig {
// configuration to be injected in root context ...
}
// special condition that the context is root
public static class NoParentContext implements Condition {
@Override
public boolean matches(ConditionContext cc, AnnotatedTypeMetadata atm) {
logger.debug(" {} parent {}", cc.getBeanFactory(), cc.getBeanFactory().getParentBeanFactory());
return (cc.getBeanFactory().getParentBeanFactory() == null);
}
}
// other beans or configuration that normally goes in servlet context
}
使用这样的@Configuration
类,就可以在@import(FeatureConfig.class)
的应用程序上下文的配置类中使用DispatcherServlet
注释。
但我找不到任何方法允许配置在正常的servlet应用程序上下文初始化之前发生。结果是来自特殊配置的任何bean只能在根上下文中注入@Autowired(required=false)
,因为根上下文将刷新两次,第一次没有特殊配置类,第二次使用它。
答案 1 :(得分:0)
据我所知,您所要做的就是提供自定义配置,该配置将通过@Configuration
注释@EnableFeature
类来导入。然后,您只需在EnableFeatureConfiguration
类中包含自定义bean。
@Configuration
public class EnableFeatureConfiguration {
@Bean
public MyBean myBean() {
return MyBean();
}
}
然后你的EnableFeature
看起来像:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(EnableFeatureConfiguration.class)
public @interface EnableFeature {
}
就是这样。在项目中你必须使用:
@Configuration
@EnableFeature
public class MySpringConfig {
}