1. 程式人生 > >Spring cache資料(三。註釋驅動的 Spring cache 快取介紹)

Spring cache資料(三。註釋驅動的 Spring cache 快取介紹)

概述

Spring 3.1 引入了激動人心的基於註釋(annotation)的快取(cache)技術,它本質上不是一個具體的快取實現方案(例如 EHCache 或者 OSCache),而是一個對快取使用的抽象,通過在既有程式碼中新增少量它定義的各種 annotation,即能夠達到快取方法的返回物件的效果。

Spring 的快取技術還具備相當的靈活性,不僅能夠使用 SpEL(Spring Expression Language)來定義快取的 key 和各種 condition,還提供開箱即用的快取臨時儲存方案,也支援和主流的專業快取例如 EHCache 整合。

其特點總結如下:

  • 通過少量的配置 annotation 註釋即可使得既有程式碼支援快取
  • 支援開箱即用 Out-Of-The-Box,即不用安裝和部署額外第三方元件即可使用快取
  • 支援 Spring Express Language,能使用物件的任何屬性或者方法來定義快取的 key 和 condition
  • 支援 AspectJ,並通過其實現任何方法的快取支援
  • 支援自定義 key 和自定義快取管理者,具有相當的靈活性和擴充套件性

本文將針對上述特點對 Spring cache 進行詳細的介紹,主要通過一個簡單的例子和原理介紹展開,然後我們將一起看一個比較實際的快取例子,最後會介紹 spring cache 的使用限制和注意事項。OK,Let ’ s begin!

原來我們是怎麼做的

這裡先展示一個完全自定義的快取實現,即不用任何第三方的元件來實現某種物件的記憶體快取。

場景是:對一個賬號查詢方法做快取,以賬號名稱為 key,賬號物件為 value,當以相同的賬號名稱查詢賬號的時候,直接從快取中返回結果,否則更新快取。賬號查詢服務還支援 reload 快取(即清空快取)。

首先定義一個實體類:賬號類,具備基本的 id 和 name 屬性,且具備 getter 和 setter 方法

清單 1. Account.java
 package cacheOfAnno; 

 public class Account { 
   private int id; 
   private String name; 
  
   public Account(String name) { 
     this.name = name; 
   } 
   public int getId() { 
     return id; 
   } 
   public void setId(int id) { 
     this.id = id; 
   } 
   public String getName() { 
     return name; 
   } 
   public void setName(String name) { 
     this.name = name; 
   } 
 }

然後定義一個快取管理器,這個管理器負責實現快取邏輯,支援物件的增加、修改和刪除,支援值物件的泛型。如下:

清單 2. MyCacheManager.java
 package oldcache; 

 import java.util.Map; 
 import java.util.concurrent.ConcurrentHashMap; 

 public class MyCacheManager<T> { 
   private Map<String,T> cache = 
       new ConcurrentHashMap<String,T>(); 
  
   public T getValue(Object key) { 
     return cache.get(key); 
   } 
  
   public void addOrUpdateCache(String key,T value) { 
     cache.put(key, value); 
   } 
  
   public void evictCache(String key) {// 根據 key 來刪除快取中的一條記錄
     if(cache.containsKey(key)) { 
       cache.remove(key); 
     } 
   } 
  
   public void evictCache() {// 清空快取中的所有記錄
     cache.clear(); 
   } 
 }

好,現在我們有了實體類和一個快取管理器,還需要一個提供賬號查詢的服務類,此服務類使用快取管理器來支援賬號查詢快取,如下:

清單 3. MyAccountService.java
 package oldcache; 

 import cacheOfAnno.Account; 

 public class MyAccountService { 
   private MyCacheManager<Account> cacheManager; 
  
   public MyAccountService() { 
     cacheManager = new MyCacheManager<Account>();// 構造一個快取管理器
   } 
  
   public Account getAccountByName(String acctName) { 
     Account result = cacheManager.getValue(acctName);// 首先查詢快取
     if(result!=null) { 
       System.out.println("get from cache..."+acctName); 
       return result;// 如果在快取中,則直接返回快取的結果
     } 
     result = getFromDB(acctName);// 否則到資料庫中查詢
     if(result!=null) {// 將資料庫查詢的結果更新到快取中
       cacheManager.addOrUpdateCache(acctName, result); 
     } 
     return result; 
   } 
  
   public void reload() { 
     cacheManager.evictCache(); 
   } 
  
   private Account getFromDB(String acctName) { 
     System.out.println("real querying db..."+acctName); 
     return new Account(acctName); 
   } 
 }

現在我們開始寫一個測試類,用於測試剛才的快取是否有效

清單 4. Main.java
 package oldcache; 

 public class Main { 

   public static void main(String[] args) { 
     MyAccountService s = new MyAccountService(); 
     // 開始查詢賬號
     s.getAccountByName("somebody");// 第一次查詢,應該是資料庫查詢
     s.getAccountByName("somebody");// 第二次查詢,應該直接從快取返回
    
     s.reload();// 重置快取
     System.out.println("after reload..."); 
    
     s.getAccountByName("somebody");// 應該是資料庫查詢
     s.getAccountByName("somebody");// 第二次查詢,應該直接從快取返回
    
   } 

 }

按照分析,執行結果應該是:首先從資料庫查詢,然後直接返回快取中的結果,重置快取後,應該先從資料庫查詢,然後返回快取中的結果,實際的執行結果如下:

清單 5. 執行結果
 real querying db...somebody// 第一次從資料庫載入
 get from cache...somebody// 第二次從快取載入
 after reload...// 清空快取
 real querying db...somebody// 又從資料庫載入
 get from cache...somebody// 從快取載入

可以看出我們的快取起效了,但是這種自定義的快取方案有如下劣勢:

  • 快取程式碼和業務程式碼耦合度太高,如上面的例子,AccountService 中的 getAccountByName()方法中有了太多快取的邏輯,不便於維護和變更
  • 不靈活,這種快取方案不支援按照某種條件的快取,比如只有某種型別的賬號才需要快取,這種需求會導致程式碼的變更
  • 快取的儲存這塊寫的比較死,不能靈活的切換為使用第三方的快取模組

如果你的程式碼中有上述程式碼的影子,那麼你可以考慮按照下面的介紹來優化一下你的程式碼結構了,也可以說是簡化,你會發現,你的程式碼會變得優雅的多!

Hello World,註釋驅動的 Spring Cache

Hello World 的實現目標

本 Hello World 類似於其他任何的 Hello World 程式,從最簡單實用的角度展現 spring cache 的魅力,它基於剛才自定義快取方案的實體類 Account.java,重新定義了 AccountService.java 和測試類 Main.java(注意這個例子不用自己定義快取管理器,因為 spring 已經提供了預設實現)

需要的 jar 包

為了實用 spring cache 快取方案,在工程的 classpath 必須具備下列 jar 包。

圖 1. 工程依賴的 jar 包圖
圖 1. 工程依賴的 jar 包圖

注意這裡我引入的是最新的 spring 3.2.0.M1 版本 jar 包,其實只要是 spring 3.1 以上,都支援 spring cache。其中 spring-context-*.jar 包含了 cache 需要的類。

定義實體類、服務類和相關配置檔案

實體類就是上面自定義快取方案定義的 Account.java,這裡重新定義了服務類,如下:

清單 6. AccountService.java
 package cacheOfAnno; 

 import org.springframework.cache.annotation.CacheEvict; 
 import org.springframework.cache.annotation.Cacheable; 

 public class AccountService { 
   @Cacheable(value="accountCache")// 使用了一個快取名叫 accountCache 
   public Account getAccountByName(String userName) { 
     // 方法內部實現不考慮快取邏輯,直接實現業務
     System.out.println("real query account."+userName); 
     return getFromDB(userName); 
   } 
  
   private Account getFromDB(String acctName) { 
     System.out.println("real querying db..."+acctName); 
     return new Account(acctName); 
   } 
 }

注意,此類的 getAccountByName 方法上有一個註釋 annotation,即 @Cacheable(value=”accountCache”),這個註釋的意思是,當呼叫這個方法的時候,會從一個名叫 accountCache 的快取中查詢,如果沒有,則執行實際的方法(即查詢資料庫),並將執行的結果存入快取中,否則返回快取中的物件。這裡的快取中的 key 就是引數 userName,value 就是 Account 物件。“accountCache”快取是在 spring*.xml 中定義的名稱。

好,因為加入了 spring,所以我們還需要一個 spring 的配置檔案來支援基於註釋的快取

清單 7. Spring-cache-anno.xml
 <beans xmlns="http://www.springframework.org/schema/beans" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:cache="http://www.springframework.org/schema/cache"
	xmlns:p="http://www.springframework.org/schema/p"
   xsi:schemaLocation="http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/cache 
     http://www.springframework.org/schema/cache/spring-cache.xsd"> 
    
   <cache:annotation-driven />

   <bean id="accountServiceBean" class="cacheOfAnno.AccountService"/> 
 
    <!-- generic cache manager --> 
   <bean id="cacheManager" 
   class="org.springframework.cache.support.SimpleCacheManager">
     <property name="caches"> 
       <set> 
         <bean 
           class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
           p:name="default" /> 
        
         <bean 
           class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
           p:name="accountCache" /> 
       </set> 
     </property> 
   </bean> 
 </beans>

注意這個 spring 配置檔案有一個關鍵的支援快取的配置項:<cache:annotation-driven />,這個配置項預設使用了一個名字叫 cacheManager 的快取管理器,這個快取管理器有一個 spring 的預設實現,即 org.springframework.cache.support.SimpleCacheManager,這個快取管理器實現了我們剛剛自定義的快取管理器的邏輯,它需要配置一個屬性 caches,即此快取管理器管理的快取集合,除了預設的名字叫 default 的快取,我們還自定義了一個名字叫 accountCache 的快取,使用了預設的記憶體儲存方案 ConcurrentMapCacheFactoryBean,它是基於 java.util.concurrent.ConcurrentHashMap 的一個記憶體快取實現方案。

OK,現在我們具備了測試條件,測試程式碼如下:

清單 8. Main.java
 package cacheOfAnno; 

 import org.springframework.context.ApplicationContext; 
 import org.springframework.context.support.ClassPathXmlApplicationContext; 

 public class Main { 
   public static void main(String[] args) { 
     ApplicationContext context = new ClassPathXmlApplicationContext( 
        "spring-cache-anno.xml");// 載入 spring 配置檔案
    
     AccountService s = (AccountService) context.getBean("accountServiceBean"); 
     // 第一次查詢,應該走資料庫
     System.out.print("first query..."); 
     s.getAccountByName("somebody"); 
     // 第二次查詢,應該不查資料庫,直接返回快取的值
     System.out.print("second query..."); 
     s.getAccountByName("somebody"); 
     System.out.println(); 
   } 
 }

上面的測試程式碼主要進行了兩次查詢,第一次應該會查詢資料庫,第二次應該返回快取,不再查資料庫,我們執行一下,看看結果

清單 9. 執行結果
 first query...real query account.somebody// 第一次查詢
 real querying db...somebody// 對資料庫進行了查詢
 second query...// 第二次查詢,沒有列印資料庫查詢日誌,直接返回了快取中的結果

可以看出我們設定的基於註釋的快取起作用了,而在 AccountService.java 的程式碼中,我們沒有看到任何的快取邏輯程式碼,只有一行註釋:@Cacheable(value="accountCache"),就實現了基本的快取方案,是不是很強大?

如何清空快取

好,到目前為止,我們的 spring cache 快取程式已經執行成功了,但是還不完美,因為還缺少一個重要的快取管理邏輯:清空快取,當賬號資料發生變更,那麼必須要清空某個快取,另外還需要定期的清空所有快取,以保證快取資料的可靠性。

為了加入清空快取的邏輯,我們只要對 AccountService.java 進行修改,從業務邏輯的角度上看,它有兩個需要清空快取的地方

  • 當外部呼叫更新了賬號,則我們需要更新此賬號對應的快取
  • 當外部呼叫說明重新載入,則我們需要清空所有快取
清單 10. AccountService.java

點選檢視程式碼清單

清單 11. Main.java

點選檢視程式碼清單

清單 12. 執行結果
 first query...real querying db...somebody 
 second query... 
 start testing clear cache... 
 real querying db...somebody1 
 real querying db...somebody2 
 real update db...somebody1 
 real querying db...somebody1 
 real querying db...somebody1 
 real querying db...somebody2

結果和我們期望的一致,所以,我們可以看出,spring cache 清空快取的方法很簡單,就是通過 @CacheEvict 註釋來標記要清空快取的方法,當這個方法被呼叫後,即會清空快取。注意其中一個 @CacheEvict(value=”accountCache”,key=”#account.getName()”),其中的 Key 是用來指定快取的 key 的,這裡因為我們儲存的時候用的是 account 物件的 name 欄位,所以這裡還需要從引數 account 物件中獲取 name 的值來作為 key,前面的 # 號代表這是一個 SpEL 表示式,此表示式可以遍歷方法的引數物件,具體語法可以參考 Spring 的相關文件手冊。

如何按照條件操作快取

前面介紹的快取方法,沒有任何條件,即所有對 accountService 物件的 getAccountByName 方法的呼叫都會起動快取效果,不管引數是什麼值,如果有一個需求,就是隻有賬號名稱的長度小於等於 4 的情況下,才做快取,大於 4 的不使用快取,那怎麼實現呢?

Spring cache 提供了一個很好的方法,那就是基於 SpEL 表示式的 condition 定義,這個 condition 是 @Cacheable 註釋的一個屬性,下面我來演示一下

清單 13. AccountService.java(getAccountByName 方法修訂,支援條件)
 @Cacheable(value="accountCache",condition="#userName.length() <= 4")// 快取名叫 accountCache 
 public Account getAccountByName(String userName) { 
 // 方法內部實現不考慮快取邏輯,直接實現業務
 return getFromDB(userName); 
 }

注意其中的 condition=”#userName.length() <=4”,這裡使用了 SpEL 表示式訪問了引數 userName 物件的 length() 方法,條件表示式返回一個布林值,true/false,當條件為 true,則進行快取操作,否則直接呼叫方法執行的返回結果。

清單 14. 測試方法
 s.getAccountByName("somebody");// 長度大於 4,不會被快取
 s.getAccountByName("sbd");// 長度小於 4,會被快取
 s.getAccountByName("somebody");// 還是查詢資料庫
 s.getAccountByName("sbd");// 會從快取返回
清單 15. 執行結果
 real querying db...somebody 
 real querying db...sbd 
 real querying db...somebody

可見對長度大於 4 的賬號名 (somebody) 沒有快取,每次都查詢資料庫。

如果有多個引數,如何進行 key 的組合

假設 AccountService 現在有一個需求,要求根據賬號名、密碼和是否傳送日誌查詢賬號資訊,很明顯,這裡我們需要根據賬號名、密碼對賬號物件進行快取,而第三個引數“是否傳送日誌”對快取沒有任何影響。所以,我們可以利用 SpEL 表示式對快取 key 進行設計

清單 16. Account.java(增加 password 屬性)
 private String password; 
 public String getPassword() { 
   return password; 
 } 
 public void setPassword(String password) { 
   this.password = password; 
 }
清單 17. AccountService.java(增加 getAccount 方法,支援組合 key)
 @Cacheable(value="accountCache",key="#userName.concat(#password)") 
 public Account getAccount(String userName,String password,boolean sendLog) { 
   // 方法內部實現不考慮快取邏輯,直接實現業務
   return getFromDB(userName,password); 
  
 }

注意上面的 key 屬性,其中引用了方法的兩個引數 userName 和 password,而 sendLog 屬性沒有考慮,因為其對快取沒有影響。

清單 18. Main.java
 public static void main(String[] args) { 
   ApplicationContext context = new ClassPathXmlApplicationContext( 
      "spring-cache-anno.xml");// 載入 spring 配置檔案
  
   AccountService s = (AccountService) context.getBean("accountServiceBean"); 
   s.getAccount("somebody", "123456", true);// 應該查詢資料庫
   s.getAccount("somebody", "123456", true);// 應該走快取
   s.getAccount("somebody", "123456", false);// 應該走快取
   s.getAccount("somebody", "654321", true);// 應該查詢資料庫
   s.getAccount("somebody", "654321", true);// 應該走快取
 }

上述測試,是採用了相同的賬號,不同的密碼組合進行查詢,那麼一共有兩種組合情況,所以針對資料庫的查詢應該只有兩次。

清單 19. 執行結果
 real querying db...userName=somebody password=123456 
 real querying db...userName=somebody password=654321

和我們預期的一致。

如何做到:既要保證方法被呼叫,又希望結果被快取

根據前面的例子,我們知道,如果使用了 @Cacheable 註釋,則當重複使用相同引數呼叫方法的時候,方法本身不會被呼叫執行,即方法本身被略過了,取而代之的是方法的結果直接從快取中找到並返回了。

現實中並不總是如此,有些情況下我們希望方法一定會被呼叫,因為其除了返回一個結果,還做了其他事情,例如記錄日誌,呼叫介面等,這個時候,我們可以用 @CachePut 註釋,這個註釋可以確保方法被執行,同時方法的返回值也被記錄到快取中。

清單 20. AccountService.java
 @Cacheable(value="accountCache")// 使用了一個快取名叫 accountCache 
 public Account getAccountByName(String userName) { 
   // 方法內部實現不考慮快取邏輯,直接實現業務
   return getFromDB(userName); 
 } 
 @CachePut(value="accountCache",key="#account.getName()")// 更新 accountCache 快取
 public Account updateAccount(Account account) { 
   return updateDB(account); 
 } 
 private Account updateDB(Account account) { 
   System.out.println("real updating db..."+account.getName()); 
   return account; 
 }
清單 21. Main.java
 public static void main(String[] args) { 
   ApplicationContext context = new ClassPathXmlApplicationContext( 
      "spring-cache-anno.xml");// 載入 spring 配置檔案
  
   AccountService s = (AccountService) context.getBean("accountServiceBean"); 
  
   Account account = s.getAccountByName("someone"); 
   account.setPassword("123"); 
   s.updateAccount(account); 
   account.setPassword("321"); 
   s.updateAccount(account); 
   account = s.getAccountByName("someone"); 
   System.out.println(account.getPassword()); 
 }

如上面的程式碼所示,我們首先用 getAccountByName 方法查詢一個人 someone 的賬號,這個時候會查詢資料庫一次,但是也記錄到快取中了。然後我們修改了密碼,呼叫了 updateAccount 方法,這個時候會執行資料庫的更新操作且記錄到快取,我們再次修改密碼並呼叫 updateAccount 方法,然後通過 getAccountByName 方法查詢,這個時候,由於快取中已經有資料,所以不會查詢資料庫,而是直接返回最新的資料,所以列印的密碼應該是“321”

清單 22. 執行結果
 real querying db...someone 
 real updating db...someone 
 real updating db...someone 
 321

和分析的一樣,只查詢了一次資料庫,更新了兩次資料庫,最終的結果是最新的密碼。說明 @CachePut 確實可以保證方法被執行,且結果一定會被快取。

@Cacheable、@CachePut、@CacheEvict 註釋介紹

通過上面的例子,我們可以看到 spring cache 主要使用兩個註釋標籤,即 @Cacheable、@CachePut 和 @CacheEvict,我們總結一下其作用和配置方法。

表 1. @Cacheable 作用和配置方法
@Cacheable 的作用 主要針對方法配置,能夠根據方法的請求引數對其結果進行快取
@Cacheable 主要的引數
value 快取的名稱,在 spring 配置檔案中定義,必須指定至少一個 例如:
@Cacheable(value=”mycache”) 或者 
@Cacheable(value={”cache1”,”cache2”}
key 快取的 key,可以為空,如果指定要按照 SpEL 表示式編寫,如果不指定,則預設按照方法的所有引數進行組合 例如:
@Cacheable(value=”testcache”,key=”#userName”)
condition 快取的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進行快取 例如:
@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
表 2. @CachePut 作用和配置方法
@CachePut 的作用 主要針對方法配置,能夠根據方法的請求引數對其結果進行快取,和 @Cacheable 不同的是,它每次都會觸發真實方法的呼叫
@CachePut 主要的引數
value 快取的名稱,在 spring 配置檔案中定義,必須指定至少一個 例如:
@Cacheable(value=”mycache”) 或者 
@Cacheable(value={”cache1”,”cache2”}
key 快取的 key,可以為空,如果指定要按照 SpEL 表示式編寫,如果不指定,則預設按照方法的所有引數進行組合 例如:
@Cacheable(value=”testcache”,key=”#userName”)
condition 快取的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進行快取 例如:
@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
表 3. @CacheEvict 作用和配置方法
@CachEvict 的作用 主要針對方法配置,能夠根據一定的條件對快取進行清空
@CacheEvict 主要的引數
value 快取的名稱,在 spring 配置檔案中定義,必須指定至少一個 例如:
@CachEvict(value=”mycache”) 或者 
@CachEvict(value={”cache1”,”cache2”}
key 快取的 key,可以為空,如果指定要按照 SpEL 表示式編寫,如果不指定,則預設按照方法的所有引數進行組合 例如:
@CachEvict(value=”testcache”,key=”#userName”)
condition 快取的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才清空快取 例如:
@CachEvict(value=”testcache”,
condition=”#userName.length()>2”)
allEntries 是否清空所有快取內容,預設為 false,如果指定為 true,則方法呼叫後將立即清空所有快取 例如:
@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation 是否在方法執行前就清空,預設為 false,如果指定為 true,則在方法還沒有執行的時候就清空快取,預設情況下,如果方法執行丟擲異常,則不會清空快取 例如:
@CachEvict(value=”testcache”,beforeInvocation=true)

基本原理

和 spring 的事務管理類似,spring cache 的關鍵原理就是 spring AOP,通過 spring AOP,其實現了在方法呼叫前、呼叫後獲取方法的入參和返回值,進而實現了快取的邏輯。我們來看一下下面這個圖:

圖 2. 原始方法呼叫圖
圖 2. 原始方法呼叫圖

上圖顯示,當客戶端“Calling code”呼叫一個普通類 Plain Object 的 foo() 方法的時候,是直接作用在 pojo 類自身物件上的,客戶端擁有的是被呼叫者的直接的引用。

而 Spring cache 利用了 Spring AOP 的動態代理技術,即當客戶端嘗試呼叫 pojo 的 foo()方法的時候,給他的不是 pojo 自身的引用,而是一個動態生成的代理類

圖 3. 動態代理呼叫圖
圖 3. 動態代理呼叫圖

如上圖所示,這個時候,實際客戶端擁有的是一個代理的引用,那麼在呼叫 foo() 方法的時候,會首先呼叫 proxy 的 foo() 方法,這個時候 proxy 可以整體控制實際的 pojo.foo() 方法的入參和返回值,比如快取結果,比如直接略過執行實際的 foo() 方法等,都是可以輕鬆做到的。

相關推薦

Spring cache資料註釋驅動Spring cache 快取介紹

概述 Spring 3.1 引入了激動人心的基於註釋(annotation)的快取(cache)技術,它本質上不是一個具體的快取實現方案(例如 EHCache 或者 OSCache),而是一個對快取使用的抽象,通過在既有程式碼中新增少量它定義的各種 annotation,即能夠達到快取

Sping cache 資料Spring4.1新特性——Spring快取框架增強

Spring 4.1提供了對jcache的支援,並對cache抽象部分進行了一些簡單的增強。在整合jcache時是非常費勁的,版本之間各種不相容,不建議用於正式環境,在正式環境中可以使用如Guava Cache或Ehcache。   jcache依賴:

【常用晶片】ULN2003工作原理及中文資料例項:STM32驅動28BYJ48步進電機

ULN2003的基本介紹ULN2003的概述ULN2003是高耐壓、大電流複合電晶體陣列,由七個矽NPN 複合電晶體組成。一般採用DIP—16 或SOP—16 塑料封裝。ULN2003的主要特點:ULN2003 的每一對達林頓都串聯一個2.7K 的基極電阻,在5V 的工作電壓

依賴注入的兩種常用方式(構造器和Setter)與注入內容(裝配資料)——Spring IOC/DI

本章主要講解一下Spring中依賴注入方式,接上一章依賴注入原理和方式: https://blog.csdn.net/qq_34598667/article/details/83315669 依賴注入常用的兩種方式以及注入的內容(裝配資料) Spring通過DI(依賴注入)實現I

spring面試題:註解+資料訪問

Spring註解 1. 什麼是基於Java的Spring註解配置? 給一些註解的例子. 基於Java的配置,允許你在少量的Java註解的幫助下,進行你的大部分Spring配置而非通過XML檔案。 以@Configuration 註解為例,它用來標記類可以當做

Spring 新手教程 註入和自己主動裝配

文件 auto 進行 上下文 xxx -s 重要 mls 上下 Spring註入是指在啟動Spring容器載入bean配置的時候。對類變量的賦值。 兩種經常使用註入方式:設值註入和構造註入 以下就這部分知識看代碼以及代碼中的註解: 1、首先看S

Spring Data HelloWorld

system out factor 環境搭建 spring string rep ret gda 在 Spring Data 環境搭建(二) 的基礎之上 我們改動 http://www.cnblogs.com/fzng/p/7253068.html 定義個一個接口 繼承

Spring Boot學習

src pack art tin pre size -s script jar Spring boot實戰 —— Hello Word 1、創建maven項目 2、pom.xml文件 <?xml version="1.0" encoding="UTF-8"?>

Spring Boot教程十四使用Redis數據庫2

分享圖片 target object docs int cpp eas 序列 lean 除了String類型,實戰中我們還經常會在Redis中存儲對象,這時候我們就會想是否可以使用類似RedisTemplate<String, User>來初始化並進行操作。但是

Spring Boot教程十五使用MongoDB數據庫1

frame 既然 artifact html ace 數據庫 支持 高度 官網 MongoDB簡介 MongoDB是一個基於分布式文件存儲的數據庫,它是一個介於關系數據庫和非關系數據庫之間的產品,其主要目標是在鍵/值存儲方式(提供了高性能和高度伸縮性)和傳統的RDBMS系統

Spring框架深入--事務

ssi new port 復讀 控制 級別 實現 inter 就是 一、事務的概念   1、事務是什麽    (1)、作為單個邏輯工作單元執行的一系列操作(一組SQL會成為一個事務),是並發控制的單位,要麽全部成功,要麽全部失敗    (2)、如銀行轉賬(需要兩個up

spring-springmvc搭建springMVC添加對靜態資源訪問的支持及對Fastjson的支持

gmv port ack register repos servle 配置 als img 1.添加對靜態資源.js/.img/.css的訪問 方式有3種: 1,更改springmvc 的DispatherServlet的urlpattern的路徑改為“/*

Spring整合MyBatissqlSessionFactory創建

ger tab var 其他 結合 mit 註入 處理 sources 摘要: 本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。 目錄 一、SqlSessionFactoryBean的初始化 二、獲取 Sq

Spring原始碼解析——元件註冊3

@Scope設定元件作用域 import com.ken.domain.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Config

使用Tensorflow來讀取訓練自己的資料

本文詳解training.py是如何編寫的。 import os import numpy as np import tensorflow as tf import input_data import model N_CLASSES = 2 # 二分類問題,只有是還是否,即0,1 IMG_W

Spring Data Jpa

Spring Data Jpa介紹 A、Spring Data JPA 是 Spring 基於 ORM 框架、JPA 規範的基礎上封裝的套 JPA 應用框架, 可使開發者用極簡的程式碼即可實現對資料的訪問和操作。它提供了包括增刪改查等在內的常用功能, 且易於擴充套件!學習

Spring 學習歷程

Bean容器初始化 基礎 org.springframework.beans org.springframework.context BeanFactory提供配置結構和基本功能,載入並初始化Bean ApplicationContext儲存了Bean物件,並且

Spring Cloud Config:基於JDBC搭建配置中心

1、簡介 本文主要內容是基於jdbc搭建配置中心,使應用從配置中心讀取配置資訊併成功註冊到註冊中心,關於配置資訊表結構僅供參考,大家可以根據具體需要進行擴充套件。 2、Config Server 搭建 2.1、Maven 依賴 因為需要從資料庫讀取配置檔案,所以需要新增M

【python】爬蟲篇:python使用psycopg2批量插入資料

本人菜雞,有什麼錯誤,還望大家批評指出,最近在更新python的爬蟲系列,○( ^皿^)っHiahiahia… 該系列暫時總共有3篇文章,連線如下 【python】爬蟲篇:python連線postgresql(一):https://blog.csdn.net/lsr40/article/de

Spring MVC學習

新建一個web project專案 嚴重: Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML docum