Interface ApplicationContextAware :
public interface ApplicationContextAware extends Aware { void setApplicationContext(ApplicationContext applicationContext) throws BeansException; }
Tout d'abord, l'interface Aware sait qu'il s'agit d'une extension Springboot que les utilisateurs peuvent utiliser. La méthode setApplicationContext est fournie ici. Le paramètre doit être transmis dans l'objet de contexte du conteneur Spring. object.Nous voulons savoir comment obtenir le conteneur spring.Quel est le rôle spécifique du contexteApplicationContextC'est le but de l'interface étendue d'obtenir le contexte et de faire quelque chose en fonction des caractéristiques du contexte.
Jetons un coup d'œil aux méthodes de l'objet ApplicationContext :
Jetons un coup d'œil aux méthodes de la classe d'implémentation AbstractApplicationContext :
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);}
Ici, nous pouvons constater que la méthode getBean() semble familière, car nous Nous n'avons pas utilisé Spring lorsque nous avons appris Spring pour la première fois. Lors de la création d'un projet d'échafaudage, la façon dont nous obtenons le bean consiste généralement à analyser le fichier XML du bean avec classPathContextLoader et à l'analyser pour former un objet ApplicationCOntext, puis à appeler sa méthode getBean pour l'obtenir. le bean instance.
À partir de cela, nous pouvons constater que notre principale méthode d'application consiste à utiliser cette méthode getBean. Ensuite, nous pouvons injecter dynamiquement des beans via de nombreuses méthodes, il n'est donc pas difficile de penser au problème selon lequel les beans injectés ne peuvent pas être utilisés dans des méthodes statiques.
Ensuite, reproduisons ce problème. Jetons un œil au code suivant :
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); }
Nous avons constaté que l'appel du bean injecté dans la méthode statique Test signale directement une erreur : Grâce au mécanisme de chargement et de chargement. Dans l'ordre de la classe, les attributs statiques et les blocs de code statiques sont chargés en premier (le statique est prioritaire). Il n'y a pas d'instance de bean pour que vous puissiez charger des méthodes statiques ici, donc une erreur sera naturellement signalée.
Comment le résoudre ? Nous pouvons adopter l'idée d'appeler la méthode getBean lorsque Spring obtient l'objet bean, et stocker statiquement le contexte du conteneur Spring lorsque le conteneur est chargé :
@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); } }
Ce à quoi nous devons seulement faire attention ici est la définition, affectation et vérification de la variable membre statique ApplicationContext :
/** * 将上下文静态设置,在初始化组件时就进行静态上下文的覆盖(这个覆盖是将远spring容器的上下文对象引用加到我们预定设置) */ private static ApplicationContext applicationContext = null;
Réécrire la méthode de l'interface étendue pour obtenir une couverture de contexte statique :
@Override public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException { SpringContextHolder.applicationContext = applicationContext; }
Rendre publique la méthode d'obtention et faciliter son partage :
public static ApplicationContext getApplicationContext() { assertContextInjected(); return applicationContext; }
Je ne le fais toujours pas Je ne comprends pas après avoir écrit ceci, quel est l'intérêt de définir un composant de cette manière pour remplacer statiquement l'objet de contexte Spring. Que fait-il ?
Pas de panique, jetons un œil à cette méthode de cette classe :
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清理,防止内存泄露。 } }
Nous avons constaté que l'opération de vérification de la bibliothèque a été effectuée dans l'exemple de code ci-dessus :
DingAppInfo appInfo = SpringContextHolder.getBean(DingAppInfoService.class).findAppInfo(APP_CODE);
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!