Wie funktioniert ApplicationContextAware im Frühjahr?

82

Wenn im Frühjahr eine Bohne implementiert wird ApplicationContextAware, kann sie auf die zugreifen applicationContext. Daher ist es in der Lage, andere Bohnen zu bekommen. z.B

public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;     

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

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

Dann SpringContextUtil.getApplicationContext.getBean("name")kann die Bohne "Name" bekommen.

Um dies zu tun, sollten wir dies SpringContextUtilin die applications.xmlz

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

Hier enthält die Bohne SpringContextUtilnicht die Eigenschaft applicationContext. Ich denke, wenn Spring Bean initialisiert wird, wird diese Eigenschaft festgelegt. Aber wie geht das? Wie wird die Methode setApplicationContextaufgerufen?

Jimmy
quelle
13
Frühling ist Magie.
Umfassen Sie

Antworten:

98

Wenn der Frühling Bohnen instanziiert, sucht er nach ein paar Schnittstellen wie ApplicationContextAware und InitializingBean. Wenn sie gefunden werden, werden die Methoden aufgerufen. ZB (sehr vereinfacht)

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

Beachten Sie, dass es in neueren Versionen möglicherweise besser ist, Anmerkungen zu verwenden, als federbezogene Schnittstellen zu implementieren. Jetzt können Sie einfach verwenden:

@Inject // or @Autowired
private ApplicationContext ctx;
Bozho
quelle
4
Vielen Dank, das ist was ich will! Vielleicht muss ich einen Federcode lesen, um zu verstehen, wie der Frühling funktioniert.
Jimmy
2
In den meisten Fällen ist es besser, @Autowired zu verwenden, aber es gibt andere, bei denen dies möglicherweise nicht funktioniert, z. B. wenn Sie eine "@Component" haben, die ein Singleton ist, aber eine Bean mit einem Sitzungsbereich injizieren müssen. Da die Abhängigkeiten bei der Erstellung des Anwendungskontexts automatisch verdrahtet werden, wird Ihnen keine Session-Bean injiziert. Wenn Sie einen Verweis auf den Anwendungskontext haben, können Sie die Session-Bean programmgesteuert abrufen, wodurch die Session-Bean-Instanz korrekt zurückgegeben wird.
Raspacorp
Ich würde erwarten, dass Spring stattdessen eine dynamisch generierte Proxy-Klasse einfügt - eine solche Klasse hat einen Anwendungsbereich, aber beim Zugriff wird sie an eine Instanz des Sitzungsbereichs delegiert oder eine Ausnahme
ausgelöst
@raspacorp Wenn eine Sesson Scope Bean nicht von injiziert werden kann ApplicationContext, kann sie auch nicht von injiziert werden ApplicationContextAware instance. Weil ApplicationContextAware instancebekommt eine Bohne von dem gleichen applicationContextObjekt wie das injizierte.
Tiina
10

Spring-Quellcode, um zu erklären, wie ApplicationContextAware
bei Verwendung von ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
In AbstractApplicationContextclass funktioniert. Die refresh()Methode verfügt über den folgenden Code:

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

Wenn Sie diese Methode eingeben, beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));wird ApplicationContextAwareProcessor zu AbstractrBeanFactory hinzugefügt.

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));
...........

Wenn spring Bean in initialisiert , rufen Sie AbstractAutowireCapableBeanFactoryin method auf initializeBean, applyBeanPostProcessorsBeforeInitializationum den Bean-Post-Prozess zu implementieren. Der Prozess beinhaltet das Einfügen des 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;
    }

Wenn BeanPostProcessor Object implementiert, um die postProcessBeforeInitialization-Methode auszuführen, z. B. ApplicationContextAwareProcessordie zuvor hinzugefügte.

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
quelle
0

Schnittstelle, die von jedem Objekt implementiert werden soll, das über den ApplicationContext benachrichtigt werden möchte, in dem es ausgeführt wird.

Das obige ist ein Auszug aus der Spring Doc-Website https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContextAware.html .

Es schien also aufgerufen zu werden, wenn der Spring-Container gestartet wurde, wenn Sie zu diesem Zeitpunkt etwas tun möchten.

Es gibt nur eine Methode, um den Kontext festzulegen. Sie erhalten also den Kontext und tun etwas, um etw bereits im Kontext zu tun, denke ich.

Yu Chai
quelle
-1

ApplicationContextAware Interface, der aktuelle Anwendungskontext, über den Sie die Spring Container Services aufrufen können. Wir können die aktuelle applicationContext-Instanz mit der folgenden Methode in die Klasse einfügen

public void setApplicationContext(ApplicationContext context) throws BeansException.
Techiesantosh
quelle