欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解析Java的Spring框架的基本結(jié)構(gòu)

 更新時(shí)間:2016年03月21日 08:48:23   作者:liweisnake  
這篇文章主要介紹了Java的Spring框架的基本結(jié)構(gòu),作者從Spring的設(shè)計(jì)角度觸發(fā)解析其基礎(chǔ)的架構(gòu)內(nèi)容,需要的朋友可以參考下

   在java屆,有位名叫Rod Johnson的牛人,發(fā)現(xiàn)最初的java企業(yè)級(jí)開(kāi)發(fā)處于混沌狀態(tài)。

   于是,它決心編寫(xiě)一個(gè)能夠解決問(wèn)題的通用的基礎(chǔ)架構(gòu)。

   因?yàn)樗钚琶嫦蚪涌诰幊棠軌驅(qū)⒆兓刂频阶钚?,同時(shí)也利于擴(kuò)展和變化。于是,它編寫(xiě)了如下的接口。 

201632184450914.png (1045×387)

   在混沌狀態(tài)最先要?jiǎng)?chuàng)造的是一切對(duì)象的母親BeanFactory,有了它,就能夠得到一切它孕育的對(duì)象和屬性,也就是說(shuō)首先要造蓋亞--大地之母。

   有了最初的母親BeanFactory,johnson想,如果我要得到一組Bean對(duì)象而不單單是某個(gè)或某幾個(gè)呢?另外,如果母親的孩子也要孕育對(duì)象呢?于是,johnson創(chuàng)造了ListableBeanFactory以操作一組bean對(duì)象,比如getBeansOfType就能夠根據(jù)得到同類(lèi)型的一組Bean;創(chuàng)造了HierarchicalBeanFactory來(lái)解決多個(gè)BeanFactory的層次問(wèn)題,比如getParentBeanFactory就能夠得到BeanFactory的父Factory。

   這個(gè)BeanFactory最終是要在某個(gè)應(yīng)用上使用的,那么,需要給予BeanFactory在一個(gè)應(yīng)用中活動(dòng)的能力。在BeanFactory中,只需要考慮跟bean相關(guān)的行為,比如怎么得到bean,bean的類(lèi)型等;而如果要賦予其在應(yīng)用中的能力,則就需要考慮更多,比如應(yīng)用的名字,啟動(dòng)時(shí)間,id等等跟應(yīng)用本身相關(guān)的行為和屬性,于是johnson想到了創(chuàng)造ApplicationContext。johnson想,這個(gè)ApplicationContext一定要能做許多事,要能夠處理參數(shù)化和國(guó)際化的文本信息,于是增加了MessageSource接口;要能發(fā)布事件以便解耦組件,于是有了ApplicationEventPublisher接口;要能得到資源文件,于是有了ResourcePatternResolver接口;要能有在不同環(huán)境有不同處理對(duì)象的能力,于是有了EnvironmentCapable接口。

   ApplicationContext繼承了所有這些接口。

   但是最重要的是,無(wú)論是BeanFactory還是ApplicationContext,它們都需要有可配置的能力,于是有了子接口ConfigurableBeanFactory和ConfigurableApplicationContext;另外,web在當(dāng)時(shí)是非常重要的趨勢(shì),而且相比其他應(yīng)用有些獨(dú)特,需要得到ServletContext,于是有了WebApplicationContext。

   到目前為止,johnson都是面向接口進(jìn)行行為的抽象思考,并未具體實(shí)現(xiàn)他們。

   看著創(chuàng)造出來(lái)的BeanFactory和ApplicationContext,johnson意識(shí)到這一天的工作遠(yuǎn)遠(yuǎn)沒(méi)有結(jié)束,因?yàn)椴](méi)有真正解決怎么能夠讓整套體系運(yùn)轉(zhuǎn)起來(lái),于是,johnson開(kāi)始思索如何實(shí)現(xiàn)他們。

   johoson首先想到的還是這個(gè)實(shí)現(xiàn)應(yīng)該具備什么能力?當(dāng)然要把之前提到的AutowireCapableBeanFactory,ListableBeanFactory和ConfigurableBeanFactory都包括進(jìn)去。因此創(chuàng)造了ConfigurableListableBeanFactory。其次,需要考慮對(duì)于bean對(duì)象的幾種能力,一是起別名的能力;二是保存單例對(duì)象的能力;三是緩存的能力;他們分別在SimpleAliasRegistry類(lèi),DefaultSingletonBeanRegistry類(lèi)和FactoryBeanRegistrySupport類(lèi)中實(shí)現(xiàn)。

201632184523588.png (673×591)

   最終,創(chuàng)造出了DefaultListableBeanFactory,它是spring中一切ioc工廠(chǎng)的原型,是BeanFactory第一個(gè)真正的孩子,這個(gè)孩子非常重要,已經(jīng)成為獨(dú)立的創(chuàng)建ioc容器的基礎(chǔ),如果有擴(kuò)展和使用,大多是繼承它或者組合使用它。

  如果要初始化一個(gè)DefaultListableBeanFactory,可以用如下代碼

ClassPathResource res = new ClassPathResource("applicationContext.xml"); 
    DefaultListableBeanFactory f = new DefaultListableBeanFactory(); 
    XmlBeanDefinitionReader r = new XmlBeanDefinitionReader(f); 
    r.loadBeanDefinitions(res); 

  接下來(lái)johnson想,BeanFactory有了一個(gè)功能比較全面的默認(rèn)實(shí)現(xiàn),那么ApplicationContext呢?于是johnson孜孜不倦的創(chuàng)造了3個(gè)重要的ApplicationContext實(shí)現(xiàn):FileSystemXmlApplicationContext, ClassPathXmlApplicationContext, AnnotationConfigWebApplicationContext(其實(shí)還有很多,比如處理portlet的, 處理web的)
201632184550126.png (791×504)

    johnson最先考慮的是如何去做spring的啟動(dòng)流程,它應(yīng)該放到一個(gè)比較抽象的層次以便下層的所有類(lèi)能夠復(fù)用。于是他用一個(gè)AbstractApplicationContext實(shí)現(xiàn)了ConfigurableApplicationContext。還有一個(gè)很重要的功能,即將一個(gè)文件以資源的形式加載進(jìn)來(lái),這需要將資源抽象為Resource類(lèi),將定位資源的具體實(shí)現(xiàn)抽象到ResourceLoader,AbstractApplicationContext同樣需要繼承DefaultResourceLoader以提供這個(gè)功能。AbstractApplicationContext完成了整個(gè)啟動(dòng)流程(上帝將它安排在第二天完成),唯獨(dú)沒(méi)有做對(duì)BeanFactory的管理。于是,它的子類(lèi)AbstractRefreshableApplicationContext專(zhuān)門(mén)做了這件事,實(shí)現(xiàn)了refreshBeanFactory, closeBeanFactory, getBeanFactory專(zhuān)門(mén)對(duì)BeanFactory的生命周期做了一些管理,但是AbstractRefreshableApplicationContext仍然沒(méi)有加載所有配置好的Bean。到哪里加載配置好的資源,實(shí)際上到了下層的子類(lèi)去做,比如FileSystemXmlApplicationContext,就是到文件系統(tǒng)去讀一個(gè)xml形式的applicationContext;ClassPathXmlApplicationContext則是到類(lèi)加載路徑下去讀這個(gè)applicationContext。而AnnotationConfigWebApplicationContext則從類(lèi)文件的annotation中加載bean,spring的掃描也從此開(kāi)始。

  看著主要的框架已經(jīng)建立起來(lái),johnson滿(mǎn)意的笑著睡著了。
 
   頭一日,johnson完成了一個(gè)spring的整體框架。

  第二日,johnson準(zhǔn)備實(shí)際去處理前面遺留的問(wèn)題。比如spring的容器初始化過(guò)程。如圖,johnson將這個(gè)過(guò)程分為很多子過(guò)程,這些子過(guò)程都在圍繞著如何將bean載入這一宏偉的目標(biāo)而努力。

201632184620113.png (148×651)

    這個(gè)過(guò)程放在A(yíng)bstractApplicationContext中的refresh方法中。代碼如下,johnson將refresh的過(guò)程分為很多子過(guò)程,并且這些子過(guò)程在同一個(gè)抽象層級(jí)上,這種寫(xiě)法是為了給后人一個(gè)榜樣。

public void refresh() throws BeansException, IllegalStateException { 
  synchronized (this.startupShutdownMonitor) { 
    // Prepare this context for refreshing. 
    prepareRefresh(); 
 
    // Tell the subclass to refresh the internal bean factory. 
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 
 
    // Prepare the bean factory for use in this context. 
    prepareBeanFactory(beanFactory); 
 
    try { 
      // Allows post-processing of the bean factory in context subclasses. 
      postProcessBeanFactory(beanFactory); 
 
      // Invoke factory processors registered as beans in the context. 
      invokeBeanFactoryPostProcessors(beanFactory); 
 
      // Register bean processors that intercept bean creation. 
      registerBeanPostProcessors(beanFactory); 
 
      // Initialize message source for this context. 
      initMessageSource(); 
 
      // Initialize event multicaster for this context. 
      initApplicationEventMulticaster(); 
 
      // Initialize other special beans in specific context subclasses. 
      onRefresh(); 
 
      // Check for listener beans and register them. 
      registerListeners(); 
 
      // Instantiate all remaining (non-lazy-init) singletons. 
      finishBeanFactoryInitialization(beanFactory); 
 
      // Last step: publish corresponding event. 
      finishRefresh(); 
    } 
 
    catch (BeansException ex) { 
      // Destroy already created singletons to avoid dangling resources. 
      destroyBeans(); 
 
      // Reset 'active' flag. 
      cancelRefresh(ex); 
 
      // Propagate exception to caller. 
      throw ex; 
    } 
  } 
} 

  如果更高層次一些看,實(shí)際上這些過(guò)程圍繞著幾個(gè)方面來(lái)做:1. 刷新的生命周期;2. 對(duì)beanFactory的初始化及準(zhǔn)備;3. 生成并注冊(cè)beanDefinition;4. beanFactory后處理器;5.設(shè)置消息,事件及監(jiān)聽(tīng)器。
  1. 刷新的生命周期

201632184644326.png (473×197)

    prepareRefresh,這個(gè)過(guò)程主要記錄日志表示spring啟動(dòng)了,初始化property資源(比如serlvet中一些資源初始化),以及property資源的驗(yàn)證(比如只寫(xiě)了key沒(méi)有value)。

  onRefresh,目的是提供給一些特殊的ApplicationContext,使他們有能夠在刷新過(guò)程中能夠擴(kuò)展的能力。目前使用到的大多是為servlet application context設(shè)置theme

  finishRefresh,做一些收尾的工作,如初始化LifecycleProcessor,發(fā)布refresh結(jié)束的事件等。

  cancelRefresh,主要是在異常產(chǎn)生時(shí)將當(dāng)前的狀態(tài)改變?yōu)榉莂ctive。

  2. 對(duì)beanFactory的初始化及準(zhǔn)備

  johnson想,我們應(yīng)該讓beanFactory在初始化時(shí)就把bean透明的加載并注冊(cè)好,這樣對(duì)外界而言,我的封裝就非常成功,因此這步實(shí)際上做了很多事。下圖省略了許多步驟,只列出關(guān)鍵點(diǎn)。

  AbstractApplicationContext會(huì)調(diào)用refreshBeanFactory,它首先會(huì)檢查并關(guān)閉已有的beanFactory,其次新建一個(gè)beanFactory,然后利用該factory裝載所有BeanDefinition

  其中,loadBeanDefinitions會(huì)交給子類(lèi)做不同的實(shí)現(xiàn),比如AbstractXmlApplicationContext主要是通過(guò)xml讀取;AnnotationConfigWebApplicationContext的實(shí)現(xiàn)則會(huì)調(diào)用掃描器掃描類(lèi)中的bean

201632184713998.png (992×248)

   3. 生成并注冊(cè)beanDefinition
  當(dāng)解析完xml配置以后,DefaultBeanDefinitionDocumentReader的parseDefaultElement方法會(huì)根據(jù)xml中的元素做對(duì)應(yīng)的處理。其中,遇到bean元素時(shí)會(huì)最終調(diào)用BeanDefinitionReaderUtils中的registerBeanDefinition方法,該方法傳入的參數(shù)為BeanDefinitionRegistry,實(shí)際上是回調(diào)了DefaultListableBeanFactory的registerBeanDefinition方法來(lái)注冊(cè)beanDefinition(DefaultListableBeanFactory實(shí)現(xiàn)了BeanDefinitionRegistry)。

   4. beanFactory后處理器

   beanFactory后處理器是spring提供出來(lái)的讓其子類(lèi)靈活擴(kuò)展的方式。spring中分為2個(gè)步驟:postProcessBeanFactory,invokeBeanFactoryPostProcessors。registerBeanPostProcessors則是實(shí)例化并調(diào)用所有的BeanPostProcessor,用來(lái)在bean初始化前和初始化后對(duì)bean做擴(kuò)展。

   5. 設(shè)置消息,事件及監(jiān)聽(tīng)器

  設(shè)置默認(rèn)消息源為DelegatingMessageSource,如工廠(chǎng)里已經(jīng)有messageSource則使用該messageSource,事件多播器為SimpleApplicationEventMulticaster,如工廠(chǎng)里已經(jīng)有applicationEventMulticaster,則使用該applicationEventMulticaster,并注冊(cè)所有的應(yīng)用程序Listener以便能夠接收事件

  消息源:MessageSource是國(guó)際化資源文件的重要方法,spring在applicationContext就支持消息源。

  spring中提供了MessageSource的默認(rèn)實(shí)現(xiàn),使用java.util.ResourceBundle來(lái)提取消息。spring通過(guò)配置一個(gè)特殊id為messageSource的bean并制定i18n的文件名,就能夠從ApplicationContext.getMessage()直接訪(fǎng)問(wèn)message。如果在jsp中,還能通過(guò)spring:message這個(gè)tag訪(fǎng)問(wèn)到message。

  事件:事件是比較重要的解耦機(jī)制,spring在核心ApplicationContext就引入了它,其原理比較簡(jiǎn)單,一方面是事件產(chǎn)生方,能夠發(fā)送事件;一方面似乎事件監(jiān)聽(tīng)方,能夠響應(yīng)事件。而具體實(shí)現(xiàn)基本上都是在產(chǎn)生方hold住一個(gè)事件監(jiān)聽(tīng)者集合,并將所有監(jiān)聽(tīng)方“注冊(cè)”(即加入)到這個(gè)事件監(jiān)聽(tīng)者集合。

  spring中將ApplicationContext當(dāng)做事件產(chǎn)生方,使用applicationListeners作為監(jiān)聽(tīng)者集合,applicationEventMulticaster用來(lái)做事件發(fā)布。

  事件發(fā)布的幾個(gè)步驟:

  訂閱:最初addApplicationListener將applicationListener加入監(jiān)聽(tīng)者集合。

  發(fā)布:ApplicationContext繼承了ApplicationEventPublisher,因而實(shí)現(xiàn)了publishEvent,該方法首先會(huì)遍歷本applicationContext的applicationListeners集合,對(duì)每個(gè)listener調(diào)用onApplicationEvent,因此每個(gè)listener都會(huì)被通知到;這步完成后會(huì)對(duì)applicationContext的parent的所有applicationListeners做同樣的事件發(fā)布。

  事件發(fā)布非常常用,不僅我們自己的應(yīng)用可以使用這個(gè)事件發(fā)布,spring框架自身也在使用事件發(fā)布。下面是一些spring中事件的應(yīng)用:

  在finishRefresh中會(huì)發(fā)布ContextRefreshedEvent表明refresh結(jié)束借此通知listener。在A(yíng)pplicationContext中start和stop方法會(huì)發(fā)布事件表示context開(kāi)始或結(jié)束。
  johnson將spring的主框架與運(yùn)行流程創(chuàng)造完畢之后,發(fā)覺(jué)spring中提供了許多靈活擴(kuò)展的地方。于是johnson準(zhǔn)備在第三日將這些靈活擴(kuò)展的用法公布出來(lái)。

  1. BeanPostProcessor。BeanPostProcessor提供了bean創(chuàng)建完成后的擴(kuò)展接口,當(dāng)你需要在bean創(chuàng)建完后對(duì)其做一定處理,則BeanPostProcessor是首選的方式。

  2. Aware。注入的bean需要了解其容器的某些部分,spring通過(guò)Aware完成回調(diào),如BeanNameAware,可以讓bean得知自己的名字, BeanFactoryAware可以讓bean了解到BeanFactory, ApplicationContextAware,可以讓bean操作ApplicationContext。通過(guò)這種方式,注入spring的bean能夠做更加廣泛的事情。

  對(duì)于BeanPostProcessor的擴(kuò)展,spring自身有一個(gè)例子,即如何識(shí)別Aware bean的例子。Aware bean是比較特殊的bean,需要spring對(duì)其額外注入一些屬性,那么注入的過(guò)程spring會(huì)怎么做呢?實(shí)際上spring并沒(méi)有將他寫(xiě)在核心的處理過(guò)程里面,而是放到了ApplicationContextAwareProcessor這個(gè)BeanPostProcessor,通過(guò)BeanPostProcessor的postProcessBeforeInitialization最終invokeAwareInterfaces以判斷該bean的類(lèi)型并注入相應(yīng)的屬性。這種做法利用了BeanPostProcessor完成了另一個(gè)擴(kuò)展用法,實(shí)在是高超。

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

  關(guān)于A(yíng)ware的用法則更多了,比如如下代碼能夠感知ApplicationContext,spring在創(chuàng)建完這個(gè)bean之后便會(huì)注入ApplicationContext,于是我們就可以使用該context完成事件發(fā)布。

public class HelloBean implements ApplicationContextAware {  
  
  private ApplicationContext applicationContext;  
  private String helloWord = "Hello!World!";  
  
  public void setApplicationContext(ApplicationContext context) {  
    this.applicationContext = context;  
  }  
  
  public void setHelloWord(String helloWord) {  
    this.helloWord = helloWord;  
  }  
  
  public String getHelloWord() {  
    applicationContext.publishEvent(  
        new PropertyGettedEvent("[" + helloWord + "] is getted"));  
    return helloWord;  
  }  
}  

  3. BeanFactoryPostProcessor,這個(gè)PostProcessor通常是用來(lái)處理在BeanFactory創(chuàng)建后的擴(kuò)展接口。一個(gè)例子如下,當(dāng)注入這個(gè)bean以后,它便會(huì)在BeanFactory創(chuàng)建完畢自動(dòng)打印注入的bean數(shù)量:

public class BeanCounter implements BeanFactoryPostProcessor{ 
 
  @Override 
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
      throws BeansException { 
    System.out.println(beanFactory.getBeanDefinitionCount()); 
  } 
   
} 

   4. FactoryBean。FactoryBean是一種特殊的bean,這種bean允許注入到spring容器并用其生成真正的bean,所以可以這樣定義,F(xiàn)actoryBean本身是一種bean,這種bean又有能夠提供bean的能力。下面從FactoryBean的調(diào)用開(kāi)始,講到spring是如何使用這個(gè)bean的。
   要想?yún)^(qū)分普通bean和FactoryBean,spring也必須有判斷他們并特殊處理的過(guò)程,這個(gè)過(guò)程就在A(yíng)bstractBeanFactory的getObjectForBeanInstance中

protected Object getObjectForBeanInstance( 
      Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { 
 
    // Don't let calling code try to dereference the factory if the bean isn't a factory. 
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { 
      throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); 
    } 
 
    // Now we have the bean instance, which may be a normal bean or a FactoryBean. 
    // If it's a FactoryBean, we use it to create a bean instance, unless the 
    // caller actually wants a reference to the factory. 
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { 
      return beanInstance; 
    } 
 
    Object object = null; 
    if (mbd == null) { 
      object = getCachedObjectForFactoryBean(beanName); 
    } 
    if (object == null) { 
      // Return bean instance from factory. 
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance; 
      // Caches object obtained from FactoryBean if it is a singleton. 
      if (mbd == null && containsBeanDefinition(beanName)) { 
        mbd = getMergedLocalBeanDefinition(beanName); 
      } 
      boolean synthetic = (mbd != null && mbd.isSynthetic()); 
      object = getObjectFromFactoryBean(factory, beanName, !synthetic); 
    } 
    return object; 
  } 

  可以看出來(lái),如果是普通bean,就直接返回了,而如果是FactoryBean,最終調(diào)用會(huì)調(diào)用factory.getObject從而返回具體對(duì)象。如果將整個(gè)spring看做一個(gè)抽象工廠(chǎng),生產(chǎn)抽象的bean時(shí),則FactoryBean就是具體工廠(chǎng),生產(chǎn)你需要的對(duì)象。
  spring中FactoryBean用法很多,舉個(gè)比較常見(jiàn)的例子,集成hibernate的sessionFactory時(shí)一般會(huì)注入LocalSessionFactoryBean,但是這個(gè)sessionFactory實(shí)際上不是普通的bean,可以簡(jiǎn)單在配置文件中注入就能生產(chǎn),它有很多定制的部分,于是spring讓這個(gè)bean成為一個(gè)FactoryBean并控制其生產(chǎn)的對(duì)象。


 

相關(guān)文章

  • Java8新特性Stream流詳解

    Java8新特性Stream流詳解

    Java8 Stream使用的是函數(shù)式編程模式,如同它的名字一樣,它可以被用來(lái)對(duì)集合進(jìn)行鏈狀流式的操作,本文就將帶著你如何使用 Java 8 不同類(lèi)型的 Stream 操作,同時(shí)還將了解流的處理順序,以及不同順序的流操作是如何影響運(yùn)行時(shí)性能的
    2023-07-07
  • 關(guān)于maven:pom文件的使用解析

    關(guān)于maven:pom文件的使用解析

    這篇文章主要介紹了關(guān)于maven:pom文件的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • spring監(jiān)視器actuator配置應(yīng)用

    spring監(jiān)視器actuator配置應(yīng)用

    這篇文章主要介紹了spring監(jiān)視器actuator配置應(yīng)用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • SWT(JFace)Group(分組顯示)

    SWT(JFace)Group(分組顯示)

    SWT(JFace)體驗(yàn)之Group(分組顯示)
    2009-06-06
  • spring boot發(fā)簡(jiǎn)單文本郵件案例

    spring boot發(fā)簡(jiǎn)單文本郵件案例

    這篇文章主要介紹了spring boot發(fā)簡(jiǎn)單文本郵件案例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Spring AOP注解案例及基本原理詳解

    Spring AOP注解案例及基本原理詳解

    這篇文章主要介紹了Spring AOP注解案例及基本原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • MyBatis動(dòng)態(tài)SQL表達(dá)式詳解

    MyBatis動(dòng)態(tài)SQL表達(dá)式詳解

    動(dòng)態(tài)SQL可以省略很多拼接SQL的步驟,使用類(lèi)似于JSTL方式,下面這篇文章主要給大家介紹了關(guān)于Mybatis動(dòng)態(tài)SQL特性的相關(guān)資料,文字通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • 基于RestTemplate的使用方法(詳解)

    基于RestTemplate的使用方法(詳解)

    下面小編就為大家?guī)?lái)一篇基于RestTemplate的使用方法(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Maven優(yōu)雅的添加第三方Jar包的方法

    Maven優(yōu)雅的添加第三方Jar包的方法

    下面小編就為大家?guī)?lái)一篇Maven優(yōu)雅的添加第三方Jar包的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • Java基礎(chǔ)Map集合詳析

    Java基礎(chǔ)Map集合詳析

    這篇文章主要介紹了Java基礎(chǔ)Map集合詳析,主要通過(guò)介紹Map集合的常用方法、Map的獲取方法的一些相關(guān)資料展開(kāi)內(nèi)容,需要的小伙伴可以參考一下
    2022-04-04

最新評(píng)論