Jak ApplicationContextAware działa na wiosnę?

82

Wiosną, jeśli fasola się zaimplementuje ApplicationContextAware, może uzyskać dostęp do applicationContext. Dlatego jest w stanie uzyskać inne ziarna. na przykład

public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;     

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

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

Następnie SpringContextUtil.getApplicationContext.getBean("name")można uzyskać „nazwę” fasoli.

Aby to zrobić, należy umieścić to SpringContextUtilwewnątrz applications.xmlnp

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

Tutaj fasola SpringContextUtilnie obejmuje właściwości applicationContext. Wydaje mi się, że podczas inicjalizacji fasoli wiosennej ta właściwość jest ustawiona. Ale jak to się robi? Jak setApplicationContextwywoływana jest metoda ?

Jimmy
źródło
13
Wiosna to magia. Embrace the magic
rosenthal

Odpowiedzi:

99

Gdy wiosna tworzy instancję, szuka kilku interfejsów, takich jak ApplicationContextAwarei InitializingBean. Jeśli zostaną znalezione, wywoływane są metody. Np. (Bardzo uproszczone)

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

Zwróć uwagę, że w nowszej wersji może być lepiej użyć adnotacji, niż implementować interfejsy specyficzne dla sprężyny. Teraz możesz po prostu użyć:

@Inject // or @Autowired
private ApplicationContext ctx;
Bozho
źródło
4
Dziękuję bardzo, tego chcę! Może muszę przeczytać kod sprężyny, aby zrozumieć, jak działa wiosna.
Jimmy
2
W większości przypadków lepiej jest używać @Autowired, ale są też inne, w których może to nie działać, na przykład gdy masz „@Component”, który jest singletonem, ale musisz wstrzyknąć komponent bean o zasięgu sesji. Ponieważ zależności są automatycznie przypisywane podczas tworzenia kontekstu aplikacji, tak naprawdę nie zostanie wstrzyknięty komponent bean sesji, mając odniesienie do kontekstu aplikacji, możesz pobrać komponent bean sesji programowo, co zwróci poprawnie instancję komponentu bean sesji.
raspacorp,
Spodziewałbym się, że zamiast tego Spring wstrzykuje dynamicznie generowaną klasę proxy - taka klasa ma zakres aplikacji, ale po uzyskaniu do niej dostępu deleguje do instancji zakresu sesji lub zgłasza wyjątek, jeśli nie ma żądania związanego z aktualnie uruchomionym wątkiem
xorcus
@raspacorp, jeśli nie można uzyskać fasoli zakresu sesson z wstrzyknięcia ApplicationContext, to nie można jej również pobrać ApplicationContextAware instance. Ponieważ ApplicationContextAware instancedostaje ziarno z tego samego applicationContextprzedmiotu, co wstrzyknięty.
Tiina
10

Kod źródłowy Spring wyjaśniający, jak ApplicationContextAware działa,
gdy używasz ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
In AbstractApplicationContextclass, refresh()metoda ma następujący kod:

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

wprowadź tę metodę, beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));doda ApplicationContextAwareProcessor do 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));
...........

Gdy wiosna zainicjuje bean AbstractAutowireCapableBeanFactoryw metodzie initializeBean, wywołajapplyBeanPostProcessorsBeforeInitialization aby zaimplementować proces post bean. proces obejmuje wstrzyknięcie 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;
    }

gdy BeanPostProcessor implementuje Object, aby wykonać metodę postProcessBeforeInitialization, na przykład ApplicationContextAwareProcessordodaną wcześniej.

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);
            }
        }
    }
Edward
źródło
0

Interfejs do zaimplementowania przez dowolny obiekt, który chce otrzymywać powiadomienia o ApplicationContext, w którym działa.

powyżej pochodzi z witryny Spring doc https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContextAware.html .

Wydawało się więc, że został wywołany, gdy kontener Spring został uruchomiony, jeśli chcesz coś zrobić w tym czasie.

Ma tylko jedną metodę ustawiania kontekstu, więc myślę, że dostaniesz kontekst i zrobisz coś, co jest już w kontekście.

Yu Chai
źródło
-1

ApplicationContextAware Interface, bieżący kontekst aplikacji, za pomocą którego można wywoływać usługi kontenera sprężynowego. Możemy pobrać bieżącą instancję applicationContext wstrzykniętą poniższą metodą w klasie

public void setApplicationContext(ApplicationContext context) throws BeansException.
techiesantosh
źródło