日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

Spring 有一個(gè)特點(diǎn),就是創(chuàng)建出來的 Bean 對(duì)容器是無感的,一個(gè) Bean 是怎么樣被容器從一個(gè) Class 整成一個(gè) Bean 的,對(duì)于 Bean 本身來說是不知道的,當(dāng)然也不需要知道,也就是 Bean 對(duì)容器的存在是無感的。

但是有時(shí)候我們可能會(huì)遇到一些場景,這些場景讓我們?nèi)ジ兄萜鞯拇嬖冢筛缗e幾個(gè)例子:

  1. Spring 容器提供的功能不止 IoC、AOP 這些,常見的 I18N 也是 Spring 的能力之一,如果我們想要在自己的 Bean 中去使用 I18N,那就得去找 Spring,這樣就感知到了 Spring 容器的存在了。
  2. Spring 提供了資源加載器,如果我們想要使用這個(gè)資源加載器去加載配置,那就得去找 Spring 要,這樣就感知到了 Spring 容器的存在了。
  3. 想根據(jù) beanName 去 Spring 容器中查找 Bean,那不用多說,肯定得知道 Spring 容器的存在。
  4. ...

也就是說,雖然 Spring 中的 Bean 可以不用去感知 Spring 容器的存在,但是在實(shí)際開發(fā)中,我們往往還是需要 Spring 容器提供的各種能力,這樣就迫使我們的 Bean 不得不去感知到 Spring 容器的存在。

那么 Spring 中的 Bean 如何感知到 Spring 容器的存在呢?

1. Aware

Aware 本身就有感知的意思。

Spring Aware 是 Spring 框架中的一個(gè)特性,它允許我們的應(yīng)用程序或組件與 Spring 容器進(jìn)行交互。當(dāng)一個(gè)類實(shí)現(xiàn)了 Spring Aware 接口并注冊(cè)到 Spring 容器中時(shí),該類就能夠感知到 Spring 容器的存在,并且可以獲取容器的一些資源或進(jìn)行一些特定的操作。

Spring Aware 接口包括了多個(gè)子接口,每個(gè)子接口對(duì)應(yīng)于不同的 Spring 容器資源或功能。

Aware 的實(shí)現(xiàn)有很多,大的方向來說主要有如下一些:

如何讓 Bean 深度感知 Spring 容器圖片

每一個(gè) Aware 的作用如下:

  • ApplicationEventPublisherAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取事件發(fā)布的能力。
  • ServletContextAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到 ServletContext 對(duì)象。
  • MessageSourceAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到 MessageSource 對(duì)象,MessageSource 支持多消息源,主要用于主要用于國際化。
  • ResourceLoaderAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ResourceLoader,Spring ResourceLoader 則為我們提供了一個(gè)統(tǒng)一的 getResource() 方法來通過資源路徑檢索外部資源,例如文本文件、XML 文件、屬性文件或圖像文件等。
  • ApplicationStartupAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ApplicationStartup 對(duì)象,這個(gè)比較新,是 Spring 5.3 中新推出的,通過 ApplicationStartup 可以標(biāo)記應(yīng)用程序啟動(dòng)期間的步驟,并收集有關(guān)執(zhí)行上下文或其處理時(shí)間的數(shù)據(jù)。
  • NotificationPublisherAware:實(shí)現(xiàn)該接的對(duì)象可以獲取到一個(gè) NotificationPublisher 對(duì)象,通過該對(duì)象可以實(shí)現(xiàn)通知的發(fā)送。
  • EnvironmentAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) Environment 對(duì)象,通過 Environment 可以獲取到容器的環(huán)境信息。
  • BeanFactoryAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) BeanFactory 對(duì)象,通過 BeanFactory 可以完成 Bean 的查詢等操作。
  • ImportAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) AnnotationMetadata 對(duì)象,ImportAware 接口是需要和 @Import 注解一起使用的。在 @Import 作為元注解使用時(shí),通過 @Import 導(dǎo)入的配置類如果實(shí)現(xiàn)了 ImportAware 接口就可以獲取到導(dǎo)入該配置類接口的數(shù)據(jù)配置。
  • EmbeddedValueResolverAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) StringValueResolver 對(duì)象,通過 StringValueResolver 對(duì)象,可以讀取到 Spring 容器中的 properties 配置的值(YAML 配置也可以)。
  • ServletConfigAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ServletConfig 對(duì)象,不過這個(gè)似乎沒什么用,我們很少自己去配置 ServletConfig。
  • LoadTimeWeaverAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) LoadTimeWeaver 對(duì)象,通過該對(duì)象可以獲取加載 Spring Bean 時(shí)織入的第三方模塊,如 AspectJ 等。
  • BeanClassLoaderAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ClassLoader 對(duì)象,ClassLoader 能干嘛不需要我多說了吧。
  • BeanNameAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè)當(dāng)前 Bean 的名稱。
  • ApplicationContextAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ApplicationContext 對(duì)象,通過 ApplicationContext 可以獲取容器中的 Bean、環(huán)境等信息。

通過實(shí)現(xiàn)這些接口,我們可以在應(yīng)用程序中獲取 Spring 容器提供的各種資源,并與容器進(jìn)行交互,以實(shí)現(xiàn)更靈活和可擴(kuò)展的功能。

2. 實(shí)踐

舉兩個(gè)例子小伙伴們來感受下 Aware 的具體用法。

2.1 案例

例如我想在 Bean 中感知到當(dāng)前 Bean 的名字,那么我們可以按照如下方式來使用:

@Service
public class UserService implements BeanNameAware {
    private String beanName;
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public String toString() {
        return "UserService{" +
                "beanName='" + beanName + ''' +
                '}';
    }
}

讓當(dāng)前 bean 實(shí)現(xiàn) BeanNameAware 接口,并重寫 setBeanName 方法,這個(gè)方法會(huì)在 Spring 容器初始化 Bean 的時(shí)候自動(dòng)被調(diào)用,我們就可以據(jù)此獲取到 bean 的名稱了。

再比如我想做一個(gè)工具 Bean,用來查找其他 Bean,那么我可以使用如下方式:

@Component
public class BeanUtils implements BeanFactoryAware {
    private static BeanFactory beanFactory;
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public static  <T> T getBean(Class<T> clazz) {
        return (T) beanFactory.getBean(clazz);
    }
}

讓當(dāng)前 Bean 實(shí)現(xiàn) BeanFactoryAware 接口并重寫 setBeanFactory 方法,在系統(tǒng)初始化當(dāng)前 Bean 的時(shí)候,會(huì)自動(dòng)調(diào)用 setBeanFactory 方法,進(jìn)而將 beanFactory 變量傳進(jìn)來。

2.2 原理

當(dāng) Spring 容器創(chuàng)建一個(gè) Bean 的時(shí)候,大致的流程是創(chuàng)建實(shí)例對(duì)象 -> 屬性填充 -> Bean 初始化

最后這個(gè) Bean 的初始化,就是調(diào)用 init 方法、afterPropertiesSet 方法以及 BeanPostProcessor 中的方法的,如下:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 invokeAwareMethods(beanName, bean);
 Object wrappedBean = bean;
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 }
 try {
  invokeInitMethods(beanName, wrappedBean, mbd);
 }
 catch (Throwable ex) {
  throw new BeanCreationException(
    (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
 }
 if (mbd == null || !mbd.isSynthetic()) {
  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 }
 return wrappedBean;
}

在這個(gè)方法一進(jìn)來,首先有一個(gè) invokeAwareMethods,這個(gè)就是用來觸發(fā) Aware 的,來看下:

private void invokeAwareMethods(String beanName, Object bean) {
 if (bean instanceof Aware) {
  if (bean instanceof BeanNameAware beanNameAware) {
   beanNameAware.setBeanName(beanName);
  }
  if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
   ClassLoader bcl = getBeanClassLoader();
   if (bcl != null) {
    beanClassLoaderAware.setBeanClassLoader(bcl);
   }
  }
  if (bean instanceof BeanFactoryAware beanFactoryAware) {
   beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
  }
 }
}

小伙伴們可以看到,BeanNameAware、BeanClassLoaderAware 以及 BeanFactoryAware 這三種類型的 Aware 是在這里觸發(fā)的。

每種 Aware 因?yàn)楣δ懿煌虼俗饔玫臅r(shí)機(jī)也不同。

invokeAwareMethods 方法執(zhí)行完畢之后,接下來是執(zhí)行 applyBeanPostProcessorsBeforeInitialization 方法,這個(gè)我們之前分析過,這個(gè)方法最終會(huì)觸發(fā) BeanPostProcessor#postProcessBeforeInitialization 方法的執(zhí)行,而 BeanPostProcessor 有一個(gè)子類專門處理 Aware 的,就是 ApplicationContextAwareProcessor:

@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
   bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
   bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
   bean instanceof ApplicationStartupAware)) {
  return bean;
 }
 invokeAwareInterfaces(bean);
 return bean;
}
private void invokeAwareInterfaces(Object bean) {
 if (bean instanceof Aware) {
  if (bean instanceof EnvironmentAware environmentAware) {
   environmentAware.setEnvironment(this.applicationContext.getEnvironment());
  }
  if (bean instanceof EmbeddedValueResolverAware embeddedValueResolverAware) {
   embeddedValueResolverAware.setEmbeddedValueResolver(this.embeddedValueResolver);
  }
  if (bean instanceof ResourceLoaderAware resourceLoaderAware) {
   resourceLoaderAware.setResourceLoader(this.applicationContext);
  }
  if (bean instanceof ApplicationEventPublisherAware applicationEventPublisherAware) {
   applicationEventPublisherAware.setApplicationEventPublisher(this.applicationContext);
  }
  if (bean instanceof MessageSourceAware messageSourceAware) {
   messageSourceAware.setMessageSource(this.applicationContext);
  }
  if (bean instanceof ApplicationStartupAware applicationStartupAware) {
   applicationStartupAware.setApplicationStartup(this.applicationContext.getApplicationStartup());
  }
  if (bean instanceof ApplicationContextAware applicationContextAware) {
   applicationContextAware.setApplicationContext(this.applicationContext);
  }
 }
}

大家看下,這七種類型的 Aware 是在這里被觸發(fā)的。

另外像 ImportAware 是在 ImportAwareBeanPostProcessor#postProcessBeforeInitialization 方法中處理的;LoadTimeWeaverAware 是在 、LoadTimeWeaverAwareProcessor#postProcessBeforeInitialization 方法中處理的。

基本上,大部分的 Aware 接口都是在 BeanPostProcessor 中處理的。

分享到:
標(biāo)簽:Spring
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定