¿Cuándo usar múltiples instancias de Spring Container?

Estoy usando ApplicationContext como Spring Container.

Sin embargo, dado que no quiero cambiar mi API, siento la necesidad de usar varias instancias del contenedor de la siguiente manera:

public static void main(String[] args)
 { 
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

    ...
    objA = context.getBean(...);
    objB = context.getBean(...);
 }

// code for Class A

 public void execute() // <-- cannot change this signature 
 {
     ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
     objC = context.getBean(...); // earlier, this was objC = new C();
     objC.method1("...");
 }

Entonces termino usando dos instancias diferentes de ApplicationContext. ¿Cuándo es apropiado y cuándo no es apropiado tener múltiples instancias de ApplicationContext?

preguntado el 12 de junio de 12 a las 17:06

Para la mayoría de las aplicaciones, no debería haber necesidad de múltiples ApplicationContexts. La principal limitación es que no puede compartir instancias de bean entre contenedores. Técnicamente, no hay ninguna razón por la que no pueda dividirlos en dos contenedores, pero tendrá que duplicar las instancias de beans si los necesita en ambos y, por lo tanto, consumirá más memoria. ¿Por qué esta API de la que habla requiere múltiples contenedores? -

¿Puedes poner el contexto de la aplicación en una variable estática en tu principal y luego permitir el acceso desde cualquier otro lugar? -

6 Respuestas

Para la mayoría de las aplicaciones, no debería haber necesidad de múltiples ApplicationContexts. La principal limitación es que no puede compartir instancias de bean entre contenedores. Técnicamente, no hay ninguna razón por la que no pueda dividirlos en dos contenedores, pero estoy seguro de que habrá algunos beans comunes que querrá compartir como fuentes de datos y una capa comercial común, etc.

Mirando su ejemplo, recomendaría permitir que su clase A acepte un contexto SpringApplication como constructor (alternativamente, podría usar un método setter)

public class A {

    private ApplicationContext ctx;

    public A(ApplicationContext applicationContext) {   
        ctx = applicationContext;
    }

    public void execute() {
        // do stuff with beans retrieved from "ctx"
    }
}

Tu main() arrancará; el contexto y pasarlo a una instancia de A

public class MyMain {

    public static void main(String[] args) {

        A a = new A(SpringContextFactory.getInstance());

        a.execute();        
    }
}

Como una pieza extra de buen diseño, encapsule su creación del contexto dentro de una clase Factory

public class SpringContextFactory {

    public static ApplicationContext getInstance() {

        String[] contextXml = new String[]{ "resources/spring-context.xml",
                                            "resources/spring-db.xml" };

        return new ClassPathXmlApplicationContext(contextXml);
    }
}

Descubrí que esta configuración funciona bien con mis pruebas unitarias

Respondido el 12 de junio de 12 a las 17:06

Tu publicación me dio una idea. Creo que crearé ApplicationContext como singleton. - Código Azul

Crear un singleton es una mala idea, ya que si ejecuta varias aplicaciones en el mismo jvm, tendrá problemas. Ya me encontré con este problema y es una mierda depurar. - tom

Si tiene control sobre las clases, intente implementar ApplicationContextAware: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/ApplicationContextAware.html

Esto inyectará applicationContext en la clase, lo que le dará la libertad de obtener cualquier clase que necesite.

mientras la clase A se inicializa en primavera, esto funcionará. Del código dado este es el caso.

Respondido el 12 de junio de 12 a las 19:06

Para mis pruebas, creé una clase de utilidades y simplemente usé una instancia estática y creé un singleton.

Por ejemplo:

 public class Utilities {
private static ApplicationContext _applicationContext = null; 
private static void initApplicationContext() {
        if (_applicationContext == null) {
            _applicationContext = 
new ClassPathXmlApplicationContext("PersistenceHelper-context.xml");
        }
    }
}

Luego, en cualquier momento que lo necesite, simplemente diga:

Utilities.initApplicationContext();

Respondido el 12 de junio de 12 a las 19:06

En su código actual, no está utilizando Spring correctamente. La idea es conectar sus dependencias en Spring y luego usar una ApplicationContext para cargar su bean inicial (probablemente desde su main() método). No es ideal cargar el mismo contexto varias veces en varios lugares solo para obtener beans diferentes.

Por lo que puedo decir, su código para ClassA debería estar tratando de @Autowired una instancia de ClassC (o ObjectC) a su miembro. Quieres hacer esto porque ClassA ya es un bean definido por Spring! Según el alcance proporcionado a Spring para su ClassC bean, debe inyectar el bean directamente (para el singleton alcance):

@Autowired
private ClassC objC;

O debe inyectar una fábrica para crear instancias del bean (para el prototype alcance):

@Autowired
private ClassCFactory objCFactory;

Si realiza este cambio, no tendrá necesidad de cargar el ApplicationContext mas de una vez.

Respondido el 12 de junio de 12 a las 17:06

No es necesario tener un contexto de aplicación múltiple. En muchos casos, necesitamos un contexto de aplicación compartido.

Para evitar la creación de múltiples contextos de aplicación en la aplicación, haga lo siguiente.

Cuando se crea el bean applicationcontextprovider, Spring Framework inyectará ApplicationContext en setApplicationContext.

Ahora tenemos un método de utilidad estático getApplicationContext, que devolverá el contexto de la aplicación cuando sea necesario.

cada vez que necesite el contexto de la aplicación, simplemente diga: ApplicationContextProvider.getApplicationContext(); , que devolverá el contexto de la aplicación compartida.

/* Clase de proveedor de contexto de aplicación */

public class ApplicationContextProvider implements ApplicationContextAware {

    private static Logger logger = Logger.getLogger(ApplicationContextProvider.class);

    private static ApplicationContext ctx;

    @Override
    public void setApplicationContext(ApplicationContext arg0)
            throws BeansException {
        if (arg0 != null) {
            ctx=arg0;
        }
    }

    public synchronized static ApplicationContext getApplicationContext(){
        if (ctx==null) {
            logger.info("Getting the context again as it is null");
            ctx = new ClassPathXmlApplicationContext("Spring-All-Module.xml");
        }
        return ctx;
    }


}

XML de primavera:

<bean id="applicationContextProvider" class="dell.harmony.service.ApplicationContextProvider"></bean> 

Desde su clase de programa principal:

try {
            logger.info("Spring Application Context !!");
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    "/Spring-All-Module.xml");
            logger.info("Spring Application Context - End !!");
        } catch (Exception e) {
                    logger.error("Exception in getting the Spring Application Context !!");
                     /* log the exception */
        }

Siempre que necesite el contexto, simplemente diga: // obtener el contexto de la aplicación

Contexto de ApplicationContext = ApplicationContextProvider.getApplicationContext();
dl = (SingleDataLoader) context.getBean("singledataloaderdao");

Respondido 18 Oct 13, 10:10

Tratar de usar context y solo un puesto application context en SU ​​CONTEXTO DE PROGRAMA en el método principal, en otros métodos solo tiene que obtener, en su caso, use el método estático de alguna clase de Contexto, no es bueno pero no puede cambiar la API

Respondido el 12 de junio de 12 a las 17:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.