All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.context.support.BeanFactoryProvider Maven / Gradle / Ivy

/*
 * Copyright 2016-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.support;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Provider;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.OrderComparator;

import com.google.inject.spi.ProvisionListener;

/**
 * 

* A {@link Provider} for a {@link BeanFactory} from an * {@link ApplicationContext} that will not be refreshed until the Guice * injector wants to resolve dependencies. Delaying the refresh means that the * bean factory can resolve dependencies from Guice modules (and vice versa). *

*

* Also implements {@link Closeable} so if you want to clean up resources used * in the application context then you can keep a reference to the provider and * call {@link #close()} on it when the application is shut down. Alternatively, * you could register an {@link ApplicationContextInitializer} that sets a * shutdown hook, so that the context is closed automatically when the JVM ends. *

* * @author Dave Syer * */ public class BeanFactoryProvider implements Provider, Closeable { private Class[] config; private String[] basePackages; private List> initializers = new ArrayList>(); private PartiallyRefreshableApplicationContext context; public ApplicationContext getApplicationContext(){ return this.context; } /** * Create an application context by scanning these base packages. * * @param basePackages base packages to scan * @return a provider */ public static BeanFactoryProvider from(String... basePackages) { return new BeanFactoryProvider(null, basePackages); } /** * Create an application context using these configuration classes. * * @param config classes to build an application * @return a provider */ public static BeanFactoryProvider from(Class... config) { return new BeanFactoryProvider(config, null); } public BeanFactoryProvider initializer( ApplicationContextInitializer... initializers) { this.initializers.addAll(Arrays.asList(initializers)); return this; } private BeanFactoryProvider(Class[] config, String[] basePackages) { this.config = config; this.basePackages = basePackages; } @Override public void close() throws IOException { if (this.context != null) { synchronized (this) { if (this.context != null) { this.context.close(); this.context = null; } } } } @Override public ConfigurableListableBeanFactory get() { if (this.context == null) { synchronized (this) { if (this.context == null) { PartiallyRefreshableApplicationContext context = new PartiallyRefreshableApplicationContext(); if (config != null && config.length > 0) { context.register(config); } if (basePackages != null && basePackages.length > 0) { context.scan(basePackages); } context.partialRefresh(); if (initializers != null && !initializers.isEmpty()) { OrderComparator.sort(initializers); for (ApplicationContextInitializer initializer : initializers) { initializer.initialize(context); } } this.context = context; } } } return context.getBeanFactory(); } private static final class PartiallyRefreshableApplicationContext extends AnnotationConfigApplicationContext { private final AtomicBoolean partiallyRefreshed = new AtomicBoolean(false); /* * Initializes beanFactoryPostProcessors only to ensure that all * BeanDefinition's are available */ private void partialRefresh() { getBeanFactory().registerSingleton("refreshListener", new ContextRefreshingProvisionListener(this)); getBeanFactory().addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); invokeBeanFactoryPostProcessors(getBeanFactory()); } private void delayedRefresh() throws BeansException, IllegalStateException { super.refresh(); } @Override public void refresh() { } @Override protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { if (partiallyRefreshed.compareAndSet(false, true)) { super.invokeBeanFactoryPostProcessors(beanFactory); } } } private static final class ContextRefreshingProvisionListener implements ProvisionListener { private final PartiallyRefreshableApplicationContext context; private final AtomicBoolean initialized = new AtomicBoolean(false); private ContextRefreshingProvisionListener(PartiallyRefreshableApplicationContext context) { this.context = context; } @Override public void onProvision(ProvisionInvocation provision) { if (!initialized.getAndSet(true) && !context.isActive()) { context.delayedRefresh(); } provision.provision(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy