¿Cómo funciona ApplicationContextAware en Spring?

82

En primavera, si un frijol se implementa ApplicationContextAware, entonces puede acceder al archivo applicationContext. Por lo tanto, puede obtener otros granos. p.ej

public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;     

    public void setApplicationContext(ApplicationContext context) throws BeansException {
      applicationContext = context;
    }

    public static ApplicationContext getApplicationContext() {
      return applicationContext;
    }
}

Entonces SpringContextUtil.getApplicationContext.getBean("name")puede obtener el "nombre" del bean.

Para hacer esto, debemos poner esto SpringContextUtildentro de applications.xml, por ejemplo

<bean class="com.util.SpringContextUtil" />

Aquí el frijol SpringContextUtilno incluye la propiedad applicationContext. Supongo que cuando se inicializa el frijol de primavera, se establece esta propiedad. Pero, ¿cómo se hace esto? ¿Cómo setApplicationContextse llama al método ?

Palanqueta
fuente
12
La primavera es mágica. Abraza la magia
rosenthal

Respuestas:

98

Cuando spring instancia beans, busca un par de interfaces como ApplicationContextAwarey InitializingBean. Si se encuentran, se invocan los métodos. Ej. (Muy simplificado)

Class<?> beanClass = beanDefinition.getClass();
Object bean = beanClass.newInstance();
if (bean instanceof ApplicationContextAware) {
    ((ApplicationContextAware) bean).setApplicationContext(ctx);
}

Tenga en cuenta que en la versión más reciente puede ser mejor usar anotaciones, en lugar de implementar interfaces específicas de Spring. Ahora puedes simplemente usar:

@Inject // or @Autowired
private ApplicationContext ctx;
Bozho
fuente
4
Muchas gracias, esto es lo que quiero! Quizás necesito leer un código de primavera para entender cómo funciona la primavera.
Jimmy
2
Es mejor usar @Autowired para la mayoría de los casos, pero hay otros en los que puede que no funcione, por ejemplo, cuando tienes un "@Component" que es un singleton pero necesitas inyectar un bean que tiene un alcance de sesión. Como las dependencias están conectadas automáticamente en la creación del contexto de la aplicación, realmente no se inyectará un bean de sesión, al tener una referencia al contexto de la aplicación, puede recuperar el bean de sesión mediante programación, lo que devolverá la instancia del bean de sesión correctamente.
raspacorp
En su lugar, esperaría que Spring inyecte una clase de proxy generada dinámicamente: dicha clase tiene un alcance de aplicación, pero cuando se accede, delega a una instancia de alcance de sesión o lanza una excepción si no hay una solicitud vinculada al hilo que se está ejecutando actualmente
xorcus
@raspacorp si un bean de alcance sesson no se puede obtener de inyectado ApplicationContext, tampoco se puede obtener de ApplicationContextAware instanceninguno. Porque ApplicationContextAware instanceobtiene un frijol del mismo applicationContextobjeto que el inyectado.
Tiina
10

Spring código fuente para explicar cómo funciona ApplicationContextAware
cuando usa ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
En AbstractApplicationContextclase, el refresh()método tiene el siguiente código:

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

ingrese este método, beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));agregará ApplicationContextAwareProcessor a AbstractrBeanFactory.

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
...........

Cuando spring initialize bean in AbstractAutowireCapableBeanFactory, en el método initializeBean, llame applyBeanPostProcessorsBeforeInitializationpara implementar el proceso de post de bean. el proceso incluye inyectar el applicationContext.

@Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

cuando BeanPostProcessor implemente Object para ejecutar el método postProcessBeforeInitialization, por ejemplo, ApplicationContextAwareProcessorel agregado antes.

private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
                        new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }
Eduardo
fuente
0

Interfaz para ser implementada por cualquier objeto que desee ser notificado del ApplicationContext en el que se ejecuta.

arriba está extraído del sitio web de Spring doc https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContextAware.html .

Por lo tanto, parece que se invoca cuando se inicia el contenedor Spring, si desea hacer algo en ese momento.

Solo tiene un método para establecer el contexto, por lo que obtendrá el contexto y hará algo para algo ahora ya en el contexto, creo.

Yu Chai
fuente
-1

ApplicationContextAware Interface, el contexto actual de la aplicación, a través del cual puede invocar los servicios de contenedor de primavera. Podemos obtener la instancia de applicationContext actual inyectada por el método siguiente en la clase

public void setApplicationContext(ApplicationContext context) throws BeansException.
techiesantosh
fuente