Spring:无法从父上下文

时间:2016-08-24 11:12:48

标签: spring spring-boot autowired applicationcontext

我有一个Spring Boot(1.4.0)应用程序,它在初始化期间启动第二个上下文(我需要这个,因为我必须使用特定类型的授权发布Web服务,而父上下文发布不同的服务)。

我创建了一个像这样的子上下文:

@Configuration
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@ConditionalOnWebApplication
public class ChildContextConfiguration implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

    private final Logger logger = LoggerFactory.getLogger(ChildContextConfiguration.class);
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private void createChildContext() {
        final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext(ChildConfiguration.class);
        childContext.setParent(this.applicationContext);
        childContext.setId(this.applicationContext.getId() + ":child");
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        logger.info("creating child context");
        createChildContext();
    }
}

子上下文的配置类如下所示:

@Configuration
@ComponentScan(basePackages = {"com.example.child"})
@PropertySource("file:some-config.properties")
@ConfigurationProperties(prefix = "child")
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class ChildConfiguration {

    private Integer port;
    private String keyStore;
    private String keyStorePass;
    private String keyPass;
    private String trustStore;
    private String trustStorePass;
    private String packageBase;

    public void setPort(Integer port) {
        this.port = port;
    }

    public void setKeyStore(String keyStore) {
        this.keyStore = keyStore;
    }

    public void setKeyStorePass(String keyStorePass) {
        this.keyStorePass = keyStorePass;
    }

    public void setKeyPass(String keyPass) {
        this.keyPass = keyPass;
    }

    public void setTrustStore(String trustStore) {
        this.trustStore = trustStore;
    }

    public void setTrustStorePass(String trustStorePass) {
        this.trustStorePass = trustStorePass;
    }

    public void setPackageBase(String packageBase) {
        this.packageBase = packageBase;
    }

    @Bean
    public Jaxb2Marshaller swpMarshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setPackagesToScan(packageBase);
        return marshaller;
    }

    @Bean
    public Unmarshaller swpUnmarshaller() throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(packageBase);
        return jaxbContext.createUnmarshaller();
    }

    @Bean
    public Filter encodingFilter() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        return encodingFilter;
    }

    @Bean
    public ServerProperties serverProperties() {
        ServerProperties props = new ServerProperties();
        props.setPort(port);
        props.setSsl(ssl());

        return props;
    }

    private Ssl ssl() {
        Ssl ssl = new Ssl();
        ssl.setEnabled(true);
        ssl.setKeyStore(keyStore);
        ssl.setKeyStorePassword(keyStorePass);
        ssl.setKeyStoreType("JKS");
        ssl.setKeyPassword(keyPass);
        ssl.setTrustStore(trustStore);
        ssl.setTrustStorePassword(trustStorePass);
        ssl.setClientAuth(Ssl.ClientAuth.NEED);


        return ssl;
    }
}

到目前为止,这是有效的。但是当我尝试从父上下文自动装配bean时,我收到一条错误,指出没有候选者。

另一件有趣的事情是,当我使用ApplicationContextAware接口将(子)上下文注入我的子上下文的bean之一时,该上下文的getParent()属性在那时为空。

我现在所做的是实现这样的getter函数:

private SomeBean getSomeBean() {
    if (this.someBean == null) {
        this.someBean = applicationContext.getParent().getBean(SomeBean.class);
    }
    return this.someBean;
}

总结一下:在构造子上下文的bean期间,没有设置父上下文,所以我不能使用autowire。

有没有办法让autowire与我的设置一起工作?

1 个答案:

答案 0 :(得分:1)

构造函数在内部注册刷新上下文 - 尝试设置类并在设置父上下文后手动刷新。

private void createChildContext() {
    final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext();
    childContext.setParent(this.applicationContext);
    childContext.setId(this.applicationContext.getId() + ":child");
    childContext.register(ChildConfiguration.class);
    childContext.refresh();
}