Heim  >  Artikel  >  Java  >  So verwenden Sie die erweiterte SpringBoot ApplicationContextAware-Schnittstelle

So verwenden Sie die erweiterte SpringBoot ApplicationContextAware-Schnittstelle

王林
王林nach vorne
2023-05-15 17:04:06958Durchsuche

ApplicationContextAware-Schnittstelle:

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

Zunächst weiß die Aware-Schnittstelle, dass es sich um eine Springboot-Erweiterung handelt, die von Benutzern verwendet werden kann. Die Methode setApplicationContext dient dazu, das Kontextobjekt des Spring-Containers zu übergeben Wir möchten wissen, wie man den Spring-Container erhält. Dies ist der Zweck der erweiterten Schnittstelle.

Werfen wir einen Blick auf die Methoden des ApplicationContext-Objekts:

So verwenden Sie die erweiterte SpringBoot ApplicationContextAware-Schnittstelle

Werfen wir einen Blick auf die Methoden der AbstractApplicationContext-Implementierungsklasse:

    public Object getBean(String name) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(name);}
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(name, requiredType);}
    public Object getBean(String name, Object... args) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(name, args);}
    public <T> T getBean(Class<T> requiredType) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(requiredType);}
    public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {this.assertBeanFactoryActive();return this.getBeanFactory().getBean(requiredType, args);}
    public <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType) {this.assertBeanFactoryActive();return this.getBeanFactory().getBeanProvider(requiredType);}
    public <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {this.assertBeanFactoryActive();return this.getBeanFactory().getBeanProvider(requiredType);}
    public boolean containsBean(String name) {return this.getBeanFactory().containsBean(name);}
    public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {this.assertBeanFactoryActive();return this.getBeanFactory().isSingleton(name);}
    public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {this.assertBeanFactoryActive();return this.getBeanFactory().isPrototype(name);}

Hier können wir feststellen, dass die getBean()-Methode bekannt vorkommt, weil wir Als wir Spring zum ersten Mal lernten, verwendeten wir Spring nicht. Beim Erstellen eines Gerüstprojekts erhalten wir die Bean normalerweise, indem wir die XML-Datei der Bean mit classPathContextLoader scannen, sie analysieren, um ein ApplicationCOntext-Objekt zu bilden, und dann die getBean-Methode aufrufen, um sie abzurufen die Instanz-Bean.

Daraus können wir erkennen, dass unsere Hauptanwendungsmethode die Verwendung dieser getBean-Methode ist. Dann können wir Bohnen über viele Methoden dynamisch injizieren, sodass es nicht schwer ist, sich das Problem vorzustellen, dass injizierte Bohnen nicht in statischen Methoden verwendet werden können.

Als nächstes reproduzieren wir dieses Problem:

public class JsonGetter {
@Resource
private UuidGetter uuidGetter;
public static string Test(){
       return uuidGetter.getUuid();
}
public static JsONobject set0bjectToJsonObject(object data){
       return JsoNobject.parseObject(String.valueof(JsONObject.toJSON(data)));
}
public static JsONObject setStringTO3son0bject(String data) { return JsONObject.parseObject(data);
}

Wir haben festgestellt, dass der Aufruf der injizierten Bean in der statischen Testmethode direkt einen Fehler meldet: Dank des Lademechanismus und des Ladens In der Reihenfolge der Klasse werden statische Attribute und statische Codeblöcke zuerst geladen (statisch hat hier Priorität, sodass Sie hier keine statischen Methoden laden können, daher wird natürlich ein Fehler gemeldet).

Wie kann man es lösen? Wir können die Idee übernehmen, die getBean-Methode aufzurufen, wenn Spring das Bean-Objekt erhält, und den Kontext des Spring-Containers statisch zu speichern, wenn der Container geladen wird:

@Component
@Lazy(value = false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
    /**
     * 将上下文静态设置,在初始化组件时就进行静态上下文的覆盖(这个覆盖是将远spring容器的上下文对象引用加到我们预定设置)
     */
    private static ApplicationContext applicationContext = null;
    public static ApplicationContext getApplicationContext() {
        assertContextInjected();
        return applicationContext;
    }
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        assertContextInjected();
        return (T) applicationContext.getBean(name);
    }
    public static  <T> T getBean(Class<T> beanType) {
        assertContextInjected();
        return applicationContext.getBean(beanType);
    }
    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
    }
    @Override
    public void destroy() {
        applicationContext = null;
    }
    private static void assertContextInjected() {
        Assert.notNull(applicationContext,
                "applicationContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
    }
    public static void pushEvent(ApplicationEvent event){
        assertContextInjected();
        applicationContext.publishEvent(event);
    }
}

Worauf wir hier nur achten müssen, ist die Definition. Zuweisung und Überprüfung der statischen Mitgliedsvariablen ApplicationContext:

    /**
     * 将上下文静态设置,在初始化组件时就进行静态上下文的覆盖(这个覆盖是将远spring容器的上下文对象引用加到我们预定设置)
     */
    private static ApplicationContext applicationContext = null;

Schreiben Sie die Methode der erweiterten Schnittstelle neu, um eine statische Kontextabdeckung zu erreichen:

    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
    }

Ändern Sie die Methode, um sie zur einfachen Freigabe öffentlich abzurufen:

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

Ich verstehe es danach immer noch nicht Welchen Sinn hat es, eine Komponente auf diese Weise zu definieren, um das Spring-Kontextobjekt statisch zu überschreiben?

Keine Panik, schauen wir uns diese Methode dieser Klasse an:

public class AppContext {
    static transient ThreadLocal<Map<String, String>> contextMap = new ThreadLocal<>();
    ......省略n行业务代码
    public static void fillLoginContext() {
        DingAppInfo appInfo = SpringContextHolder.getBean(DingAppInfoService.class).findAppInfo(APP_CODE);
        setDingVerifyInfo(appInfo);
        CloudChatAppInfo cloudChatAppInfo = SpringContextHolder.getBean(CloudChatAppInfoService.class).findAppInfo(APP_CODE);
        setCloudChatInfo(cloudChatAppInfo);
    }
    public static void clear() {
        contextMap.remove(); //本地线程的remove方法极其重要,注意每次给它使用之后一定要调用remove清理,防止内存泄露。
    }
}

Wir haben festgestellt, dass der Bibliotheksüberprüfungsvorgang im obigen Beispielcode ausgeführt wurde:

DingAppInfo appInfo = SpringContextHolder.getBean(DingAppInfoService.class).findAppInfo(APP_CODE);

Das obige ist der detaillierte Inhalt vonSo verwenden Sie die erweiterte SpringBoot ApplicationContextAware-Schnittstelle. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen