Spring學習筆記(1)----簡單的實例 --------------------------------- 首先需要准備Spring包,可從官方網站上下載。 下載解壓后,必須的兩個包是spring.jar和commons-logging.jar。此外為了便於測試加入了JUnit包。 在Myeclipse中創建Java項目。 編寫一個接口類,為了簡單,只加入了一個方法。 Java代碼 1.package com.szy.spring.interfacebean; 2. 3.public interface PersonBean 4.{ 5. void show(); 6.} 然后寫一個類實現這個接口。 Java代碼 1.package com.szy.spring.implbean; 2.import com.szy.spring.interfacebean.PersonBean; 3. 4.public class UserBean implements PersonBean 5.{ 6. 7. public void show() 8. { 9. System.out.println("Hello Kuka"); 10. } 11. 12.} 以上的過程我們再熟悉不過了,下面開始加入Spring的內容了。首先從下載的Sping包中找到配置文件,刪除不需要的,找到最原始的部分: Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. 10.</beans> 我們在配置文件中加入我們的bean信息 Xml代碼 1.<bean id="userBean" class="com.szy.spring.implbean.UserBean" /> 其中id作為標識符,class為類的包路徑。 這樣我們的配置文件就寫好了,完整的配置文件呢如下。 Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. 10. <bean id="userBean" class="com.szy.spring.implbean.UserBean" /> 11.</beans> 最后我們創建一個測試類測試: Java代碼 1.package com.szy.spring.test; 2. 3.import org.junit.Test; 4.import org.springframework.context.ApplicationContext; 5.import org.springframework.context.support.ClassPathXmlApplicationContext; 6.import com.szy.spring.interfacebean.PersonBean; 7. 8. 9.public class TestClass 10.{ 11. @Test 12. public void testMethod() throws Exception 13. { 14. //讀取配置文件 15. ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 16. //獲取UserBean的實例 17. PersonBean bean=(PersonBean)ctx.getBean("userBean"); 18. //調用方法 19. bean.show(); 20. } 21.} 運行,輸入如下結果: 結果代碼 1.Hello Kuka Ok,我們的第一個Spring程序成功運行。 Sping學習筆記(2)----實例化Bean的三種方式 ------------------------------------------- Spring的實例化Bean有三種方式: 使用類構造器直接實例化 使用靜態工廠的方法實例化 使用實例工廠方法實例化 三種方式對應的配置如下 Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <!-- 使用類構造器直接實例化 --> 10. <bean id="userBean1" class="com.szy.spring.implbean.UserBean" /> 11. <!-- 使用靜態工廠的方法實例化 --> 12. <bean id="userBean2" class="com.szy.spring.factory.BeanFactory" factory-method="UserBeanService" /> 13. <!-- 使用實例工廠方法實例化 --> 14. <bean id="factory" class="com.szy.spring.factory.BeanFactory" /> 15. <bean id="userBean3" factory-bean="factory" factory-method="getUserBeanService" /> 16.</beans> 其中BeanFactory類的代碼如下 Java代碼 1.package com.szy.spring.factory; 2. 3.import com.szy.spring.implbean.UserBean; 4.import com.szy.spring.interfacebean.PersonBean; 5. 6.public class BeanFactory 7.{ 8. //使用靜態工廠的方法實例化使用 9. public static PersonBean UserBeanService() 10. { 11. return new UserBean(); 12. } 13. 14. public PersonBean getUserBeanService() 15. { 16. return new UserBean(); 17. } 18.} 在這三種方式中我們最常用的還是第一種。 Spring學習筆記(3)----編碼剖析Spring管理Bean的原理 -------------------------------------------------- Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <bean id="userBean" class="com.szy.spring.implbean.UserBean" /> 10.</beans> Spring的配置文件中記錄了類的包路徑,因此我們首先是要讀入配置文件。在配置文件中Bean有id和class兩個屬性,我們首先定義一個Bean類,包含這兩個屬性: Java代碼 1.package com.szy.spring.implbean; 2. 3.public class Bean 4.{ 5. private String id; 6. private String className; 7. public String getId() 8. { 9. return id; 10. } 11. public void setId(String id) 12. { 13. this.id = id; 14. } 15. public String getClassName() 16. { 17. return className; 18. } 19. public void setClassName(String className) 20. { 21. this.className = className; 22. } 23. 24.} 25. 由於配置文件是xml文件,在這里使用Jdom包操作xml文件,讀入配置文件中的Bean信息。 Java代碼 1./** 2. * 讀取xml配置文件 3. * @param fileName 配置文件名 4. */ 5. private void readXML(String fileName) 6. { 7. // 尋找配置文件 8. URL xmlPath = this.getClass().getClassLoader().getResource(fileName); 9. Document doc = null; 10. Element root = null; 11. try 12. { 13. SAXBuilder sb = new SAXBuilder(false); 14. doc = sb.build(new FileInputStream(new File(xmlPath.toURI()))); 15. // 設置命名空間 16. Namespace xhtml = Namespace.getNamespace("xhtml", 17. "http://www.springframework.org/schema/beans"); 18. root = doc.getRootElement(); // 獲取根元素 19. List<Element> list = root.getChildren("bean", xhtml); //獲取全部bean節點 20. for (Element element : list)// 遍歷節點,取得每個節點的屬性 21. { 22. String id = element.getAttributeValue("id"); 23. String className = element.getAttributeValue("class"); 24. Bean bean = new Bean(); 25. bean.setId(id); 26. bean.setClassName(className); 27. beanList.add(bean); 28. } 29. } catch (Exception e) 30. { 31. e.printStackTrace(); 32. } 33. 34. } 其中beanList是一個List對象,因為在配置文件中存在很多Bean。 得到了所有的Bean對象后,下面就實例化每個Bean對象,結果存放在Map對象中。 Java代碼 1./** 2. * bean的實例化 3. */ 4. private void instanceBeans() 5. { 6. for (Bean bean : beanList) 7. { 8. try 9. { 10. if (bean.getClassName() != null && !"".equals(bean.getClassName().trim())) 11. beanObject.put(bean.getId(), Class.forName(bean.getClassName()).newInstance()); 12. } catch (Exception e) 13. { 14. e.printStackTrace(); 15. } 16. } 17. 18. } 其中beanObject為Map對象。 最后再加入一個方法,方便外部能獲取Map中的對象 Java代碼 1./** 2. * 獲取bean實例 3. * @param beanName 配置文件中bean的Id 4. * @return 5. */ 6. public Object getBean(String beanName) 7. { 8. return this.beanObject.get(beanName); 9. } 完整的MyClassPathXMLApplicationContext見附件中的代碼。 下面測試MyClassPathXMLApplicationContext類。 Java代碼 1.@Test 2. public void testMethod() throws Exception 3. { 4. //讀取配置文件 5. MyClassPathXMLApplicationContext ctx=new MyClassPathXMLApplicationContext("applicationContext.xml"); 6. //獲取UserBean的實例 7. PersonBean bean=(PersonBean)ctx.getBean("userBean"); 8. //調用方法 9. bean.show(); 10. } 輸出結果 結果代碼 1.Hello Kuka 成功。 上面僅是簡單的演示了Spring管理Bean的原理,但是在實際操作中還需要考慮很對其它因素。 Spring學習筆記(4)----Bean節點信息配置 --------------------------------------- 默認情況下,Spring的Ioc容器啟動時會初始化bean,但是我們可以指定Bean節點的lazy-init="true",來延遲初始化bean。這時候,只有第一次獲取bean才會初始化bean。如 Xml代碼 1.<bean id="userBean" class="com.szy.spring.implbean.UserBean" lazy-init="true" /> 如果想對所有的bean有應用延遲初始化,可以在跟節點beans設置default-lazy-init="true",如下: Xml代碼 1.<beans default-lazy-init="true"....> 此外,如果我們還想UserBean在實例化是調用初始化方法時,我們可以加入“init-method="init"”屬性,其中init為Userbean中的init()方法,與之對應,“destroy-method="destroy"”為銷毀屬性。 在Spring中我們通過getBean(name)方法獲得實例,那么我們每次獲取的實例化對象是一個還是多個呢? 我們可以通過“==”進行測試 Java代碼 1.ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 2.PersonBean bean1=(PersonBean)ctx.getBean("userBean"); 3.PersonBean bean2=(PersonBean)ctx.getBean("userBean"); 4.System.out.println(bean1==bean2); 運行輸出結果為:true 這說明了Bean交給sping容器管理之后,Bean默認情況下是單實例的。 如果我們想每次通過getBean(name)方法獲得實例是一個新的實例化對象該怎么辦呢? 在配置文件中節點bean有一個屬性scope,只要我們配置如下即可: Xml代碼 1.<bean id="userBean" class="com.szy.spring.implbean.UserBean" scope="prototype" /> 在運行測試代碼,輸出結果為:false Spring學習筆記(5)----依賴注入的簡單實現 ----------------------------------------- Spring的核心機制是依賴注入。依賴注入讓bean與bean之間以配置文件組織在一起,而不是以硬編碼的方式耦合在一起。依賴注入(Dependency Injection)和控制反轉(Inversion of Control)是同一個概念。具體含義是:當某個角色(可能是一個Java實例,調用者)需要另一個角色(另一個Java實例,被調用者)的協助時,在傳統的程序設計過程中,通常由調用者來創建被調用者的實例。但在Spring里,創建被調用者的工作不再由調用者來完成,因此稱為控制反轉;創建被調用者實例的工作通常由Spring容器來完成,然后注入調用者,因此也稱為依賴注入。管是依賴注入,還是控制反轉,都說明Spring采用動態、靈活的方式來管理各種對象。對象與對象之間的具體實現互相透明。 下面通過簡單的實例演示依賴注入。 項目中主要包含一下一個文件: UserDAO是一個接口,包含了一個方法: Java代碼 1.package com.szy.spring.dao; 2. 3.public interface UserDAO 4.{ 5. void show(); 6.} 而UserDAO4MySqlImpl和UserDAO4OracleImpl實現了UserDAO中的方法。 Java代碼 1.package com.szy.spring.dao; 2.public class UserDAO4MySqlImpl implements UserDAO 3.{ 4. public void show() 5. { 6. System.out.println("MySqlDAO Implement"); 7. } 8.} Java代碼 1.package com.szy.spring.dao; 2.public class UserDAO4OracleImpl implements UserDAO 3.{ 4. public void show() 5. { 6. System.out.println("OracleDAO Implement"); 7. } 8.} UserService是另外一個包中的接口, Java代碼 1.package com.szy.spring.service; 2. 3.public interface UserService 4.{ 5. void show(); 6.} UserServiceImpl實現了這個接口, Java代碼 1.package com.szy.spring.service; 2. 3.import com.szy.spring.dao.UserDAO; 4. 5.public class UserServiceImpl implements UserService 6.{ 7. private UserDAO userDAO; 8. 9. public void show() 10. { 11. userDAO.show(); 12. } 13. 14. public UserDAO getUserDAO() 15. { 16. return userDAO; 17. } 18. public void setUserDAO(UserDAO userDAO) 19. { 20. this.userDAO = userDAO; 21. } 22.} 但是在實現這個接口中,調用了UserDAO中的方法。一般情況下我們需要在這里實例化一個UserDAO對象,比如 Java代碼 1.UserDAO userDAO=new UserDAO4MySqlImpl(); 這樣的話耦合度就比較高,通過spring我們可以降低耦合度。 在Sping的配置文件中,我們需要這樣配置 Java代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <bean id="mySqlDAO" class="com.szy.spring.dao.UserDAO4MySqlImpl"/> 10. <bean id="oracleDAO" class="com.szy.spring.dao.UserDAO4OracleImpl"/> 11. <bean id="userService" class="com.szy.spring.service.UserServiceImpl"> 12. <!--構造方法注入 13. <property name="userDAO" ref="mySqlDAO"></property> 14. --> 15. <property name="userDAO" ref="oracleDAO"></property> 16. </bean> 17.</beans> 下面我們測試 Java代碼 1.ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 2. UserService service=(UserService)ctx.getBean("userService"); 3. service.show(); 輸入內容為 輸出代碼 1.OracleDAO Implement 如果我們想實用Mysql數據庫呢? 此時我們只要修改配置文件即可,而不需要修改Java文件。 Xml代碼 1.<property name="userDAO" ref="mySqlDAO"></property> Spring學習筆記(6)----編碼剖析Spring依賴注入的原理 --------------------------------------------------- 在Spring學習筆記(3)中剖析了Spring管理Bean的原理,下面解釋下Spring依賴注入的原理 在進行依賴注入時,我們的配置文件如下配置: Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <bean id="mySqlDAO" class="com.szy.spring.dao.UserDAO4MySqlImpl"/> 10. <bean id="oracleDAO" class="com.szy.spring.dao.UserDAO4OracleImpl"/> 11. <bean id="userService" class="com.szy.spring.service.UserServiceImpl"> 12. <!--構造方法注入 13. <property name="userDAO" ref="mySqlDAO"></property> 14. --> 15. <property name="userDAO" ref="oracleDAO"></property> 16. </bean> 17.</beans> 根據配置文件信息,我們首先需要建立一個Bean類,用來保存bean節點的信息: Java代碼 1.package com.szy.spring.bean; 2. 3.import java.util.List; 4. 5.public class Bean 6.{ 7. private String id; 8. private String className; 9. private List<Property> propertyList; 10. public Bean(String id, String className, List<Property> propertyList) 11. { 12. super(); 13. this.id = id; 14. this.className = className; 15. this.propertyList = propertyList; 16. } 17. public String getId() 18. { 19. return id; 20. } 21. public void setId(String id) 22. { 23. this.id = id; 24. } 25. public String getClassName() 26. { 27. return className; 28. } 29. public void setClassName(String className) 30. { 31. this.className = className; 32. } 33. public List<Property> getPropertyList() 34. { 35. return propertyList; 36. } 37. public void setPropertyList(List<Property> propertyList) 38. { 39. this.propertyList = propertyList; 40. } 41.} 此外,由於bean下存在property信息,因此我們還需要建立property類 Java代碼 1.package com.szy.spring.bean; 2. 3.public class Property 4.{ 5. private String name; 6. private String ref; 7. 8. public Property(String name, String ref) 9. { 10. super(); 11. this.name = name; 12. this.ref = ref; 13. } 14. public String getName() 15. { 16. return name; 17. } 18. public void setName(String name) 19. { 20. this.name = name; 21. } 22. public String getRef() 23. { 24. return ref; 25. } 26. public void setRef(String ref) 27. { 28. this.ref = ref; 29. } 30. 31.} 在Spring學習筆記(3)中,我們在讀取xml文件時bean節點下面是不存在property節點的,因此在這里我們需要修改readXML()方法: Java代碼 1./** 2. * 讀取xml配置文件 3. * @param fileName 配置文件名 4. */ 5. private void readXML(String fileName) 6. { 7. // 尋找配置文件 8. URL xmlPath = this.getClass().getClassLoader().getResource(fileName); 9. Document doc = null; 10. Element root = null; 11. try 12. { 13. SAXBuilder sb = new SAXBuilder(false); 14. doc = sb.build(new FileInputStream(new File(xmlPath.toURI()))); 15. // 設置命名空間 16. Namespace xhtml = Namespace.getNamespace("xhtml", 17. "http://www.springframework.org/schema/beans"); 18. root = doc.getRootElement(); // 獲取根元素 19. List<Element> bList = root.getChildren("bean", xhtml); //獲取全部bean節點 20. for (Element beanElement : bList)// 遍歷節點,取得每個節點的屬性 21. { 22. String id = beanElement.getAttributeValue("id"); 23. String className = beanElement.getAttributeValue("class"); 24. //獲得每個bean下面的屬性 25. List<Element> pList = beanElement 26. .getChildren("property", xhtml); 27. List<Property> propertyList = new ArrayList<Property>(); //存儲屬性信息 28. if (pList.size() > 0) //如果存在屬性 29. { 30. for (Element propertyElement : pList) //遍歷屬性節點 31. { 32. String name = propertyElement.getAttributeValue("name"); 33. String ref = propertyElement.getAttributeValue("ref"); 34. Property property = new Property(name, ref); 35. propertyList.add(property); //保存屬性節點 36. } 37. } 38. Bean bean = new Bean(id, className, propertyList); 39. beanList.add(bean); 40. } 41. 42. } catch (Exception e) 43. { 44. e.printStackTrace(); 45. } 46. } 讀取完配置文件后我們還是需要對bean進行實例化的,這方法和Spring學習筆記(3)中的instanceBeans()方法一樣。下面就是我們需要給bean屬性進行注入,實現方法如下: Java代碼 1./** 2. * 為bean對象的屬性注入值 3. */ 4. public void injectObject() 5. { 6. for (Bean bean : beanList) 7. { 8. Object object = beanObject.get(bean.getId()); //獲取bean的實例 9. if (object != null) 10. { 11. try 12. { 13. PropertyDescriptor[] ps = Introspector.getBeanInfo( 14. object.getClass()).getPropertyDescriptors(); //取得bean的屬性描述 15. for (Property property : bean.getPropertyList()) //獲取bean節點的屬性 16. { 17. for (PropertyDescriptor properdesc : ps) 18. { 19. if (property.getName().equals(properdesc.getName())) 20. { 21. Method setter = properdesc.getWriteMethod();//獲取屬性的setter方法 ,private 22. if (setter != null) 23. { 24. Object value = beanObject.get(property.getRef()); //取得值 25. setter.setAccessible(true); //設置為允許訪問 26. setter.invoke(object, value);//把引用對象注入到屬性 27. } 28. break; 29. } 30. } 31. } 32. } catch (Exception e) 33. { 34. e.printStackTrace(); 35. } 36. } 37. } 我們進行測試: Java代碼 1.MyClassPathXMLApplicationContext ctx=new MyClassPathXMLApplicationContext("applicationContext.xml"); 2. UserService service=(UserService)ctx.getBean("userService"); 3. service.show(); 運行輸出 結果代碼 1.OracleDAO Implement 上面僅是簡單的演示了Spring依賴注入的原理,但是Spring學習筆記(7)----裝配各種集合類型的屬性在實際操作中還需要考慮很對其它因素,在此就不進行討論了。 Spring學習筆記(7)----裝配各種集合類型的屬性 --------------------------------------------- 前面已經介紹了如何給屬性注入對象,下面介紹一下如何裝配集合類型的屬性 1.Set類型 Java代碼 1.private Set<String> sets=new HashSet<String>(); 2.//我們需要給它添加set方法 3.public Set<String> getSets() 4. { 5. return sets; 6. } 7. public void setSets(Set<String> sets) 8. { 9. this.sets = sets; 10. } 11.public Set<String> showSet() 12. { 13. return sets; 14. } 然后根據屬性修改配置文件 Xml代碼 1.<bean id="userService" class="com.szy.spring.service.UserServiceImpl"> 2. <property name="sets"> 3. <set> 4. <value>Set1</value> 5. <value>Set2</value> 6. <value>Set3</value> 7. </set> 8. </property> 9. 10.</bean> 與以前不同的是我們在property下面添加了<set></set> 這樣就能裝配set類型的屬性 2.List類型 List類型的屬性和Set類型的方法一樣,主要是把配置文件中的set修改成list。 Java代碼 1.private List<String> lists=new ArrayList<String>(); 2.public List<String> getLists() 3. { 4. return lists; 5. } 6. public void setLists(List<String> lists) 7. { 8. this.lists = lists; 9. } 10.public List<String> showList() 11. { 12. return lists; 13. } 配置文件修改如下 Xml代碼 1.<bean id="userService" class="com.szy.spring.service.UserServiceImpl"> 2.<property name="lists"> 3. <list> 4. <value>List1</value> 5. <value>List2</value> 6. <value>List3</value> 7. </list> 8. </property> 9. </bean> 3.Properties類型 Java代碼 1.private Properties properties=new Properties(); 2.public void setProperties(Properties properties) 3. { 4. this.properties = properties; 5. } 6.public Properties getProperties() 7. { 8. return properties; 9. } 10.public Properties showProperties() 11. { 12. return properties; 13. } 配置文件需要如下配置 Xml代碼 1.<bean id="userService" class="com.szy.spring.service.UserServiceImpl"> 2.<property name="properties"> 3. <props> 4. <prop key="key1">Properties1</prop> 5. <prop key="key2">Properties2</prop> 6. <prop key="key3">Properties3</prop> 7. </props> 8. </property> 9. </bean> 10. 4.Map類型 Java代碼 1.private Map<String, String> maps=new HashMap<String, String>(); 2.public List<String> getLists() 3. { 4. return lists; 5. } 6. public void setLists(List<String> lists) 7. { 8. this.lists = lists; 9. } 10.public Map<String, String> showMaps() 11. { 12. return maps; 13. } 配置文件做相應的配置 Xml代碼 1.<bean id="userService" class="com.szy.spring.service.UserServiceImpl"> 2.lt;property name="maps"> 3. <map> 4. <entry key="key1" value="Map1"></entry> 5. <entry key="key2" value="Map2"></entry> 6. <entry key="key3" value="Map3"></entry> 7. </map> 8. </property> 9.</bean> 這樣就完成了對Map類型的屬性進行裝配。 Spring學習筆記(8)----屬性注入的方式 -------------------------------------- Spring中屬性注入的方式有三種: 1.使用屬性setter方法注入 2.使用構造器注入 3.使用注解方式注入 使用屬性setter方法注入 使用屬性setter方法注入就是給屬性添加set()方法,在前面都是使用這種方法。 Java代碼 1.package com.szy.spring.service; 2. 3.import com.szy.spring.dao.PersonDao; 4. 5.public class UserServiceImplBySetter implements UserService 6.{ 7. private PersonDao personDao; 8. 9. public void show() 10. { 11. personDao.show(); 12. } 13. public PersonDao getPersonDao() 14. { 15. return personDao; 16. } 17. public void setPersonDao(PersonDao personDao) 18. { 19. this.personDao = personDao; 20. } 21.} 然后在配置文件中如下配置 Xml代碼 1.<bean id="personDao" class="com.szy.spring.dao.PersonDaoBean"/> 2. <!-- 使用屬性Setter方法注入配置 --> 3. <bean id="userService1" class="com.szy.spring.service.UserServiceImplBySetter"> 4. <property name="personDao" ref="personDao"></property> 5. </bean> 使用構造器注入 使用構造器注入就是在類中添加含參構造函數 Java代碼 1.package com.szy.spring.service; 2. 3.import com.szy.spring.dao.PersonDao; 4. 5.public class UserServiceImplConstructor implements UserService 6.{ 7. private PersonDao personDao; 8. private String name; 9. 10. public UserServiceImplConstructor() 11. { 12. } 13. 14. public UserServiceImplConstructor(PersonDao personDao, String name) 15. { 16. this.personDao = personDao; 17. this.name = name; 18. } 19. 20. public void show() 21. { 22. personDao.show(); 23. System.out.println("name屬性:"+name); 24. } 25.} 下面就是在配置文件中添加配置信息,給每個參數注入值 Xml代碼 1.<bean id="personDao" class="com.szy.spring.dao.PersonDaoBean"/> 2. <!-- 使用構造器參數方法注入配置 --> 3. <bean id="userService2" class="com.szy.spring.service.UserServiceImplConstructor"> 4. <constructor-arg index="0" type="com.szy.spring.dao.PersonDao" ref="personDao"/> 5. <constructor-arg index="1" value="Kuka"/> 6. </bean> 注意:constructor-arg index是從0開始的 使用注解方式注入 如果使用前面的兩種方法,配置文件將會顯得很臃腫,因此我們可以使用注解的方式注入,使用注解方式注入有兩種方法,第一種使用javax.annotation.Resource中提供的注解方式方法如下: Java代碼 1.package com.szy.spring.service; 2. 3.import javax.annotation.Resource; 4. 5.import com.szy.spring.dao.PersonDao; 6. 7.public class UserServiceImplByAnnotation4Resource implements UserService 8.{ 9. //@Resource默認是按照名稱裝配,找不到與名稱匹配的bean時按類型裝配 10. @Resource(name="personDao")private PersonDao personDao; 11. 12. public void show() 13. { 14. personDao.show(); 15. } 16.// 下面方法同樣可以 17.// @Resource 18.// public void setPersonDao(PersonDao personDao) 19.// { 20.// this.personDao = personDao; 21.// } 22. 23.} 此時配置文件要做相應的改變 Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd 8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 9. <context:annotation-config/> 10. <bean id="personDao" class="com.szy.spring.dao.PersonDaoBean"/> 11. <bean id="userService" class="com.szy.spring.service.UserServiceImplByAnnotation4Autowired"> 12. </bean> 13.</beans> 注意添加這句配置信息 <context:annotation-config/> 第二中方式就是使用spring提供的注解方式 org.springframework.beans.factory.annotation.Autowired; 注入使用時需要導入spring目錄lib\j2ee\common-annotations.jar這個包 使用方法如下: Java代碼 1.package com.szy.spring.service; 2. 3.import org.springframework.beans.factory.annotation.Autowired; 4.import org.springframework.beans.factory.annotation.Qualifier; 5. 6.import com.szy.spring.dao.PersonDao; 7. 8.public class UserServiceImplByAnnotation4Autowired implements UserService 9.{ 10. //@Autowired默認使用類型進行裝配, 11. @Autowired private PersonDao personDao; 12.// 如果使用按名稱進行裝配,則需要如下 13.// @Autowired @Qualifier("personDao")private PersonDao personDao; 14. public void show() 15. { 16. personDao.show(); 17. } 18. 19.} 配置文件和上面一樣。 在使用時建議使用@Resource,因為@Resource不依賴於spring框架。 Spring學習筆記(9)----讓Spring自動掃描和管理Bean ------------------------------------------------- Java代碼 1.package com.szy.spring.service; 2. 3.import org.springframework.stereotype.Service; 4. 5.import com.szy.spring.dao.PersonDao; 6.@Service("service") 7.public class UserServiceImpl implements UserService 8.{ 9. private PersonDao personDaoBean; 10. 11. public void show() 12. { 13. personDaoBean.show(); 14. } 15. 16. public void setPersonDaoBean(PersonDao personDaoBean) 17. { 18. this.personDaoBean = personDaoBean; 19. } 20.} 在前面的例子中,都是使用XML的bean定義來使用組件,在大的項目中,通常會有上百個組件,如果這些組件采用xml的bean定義來配置,顯然會使配置文件顯得很臃腫,查找和維護起來不方便。Spring2.5為我們引入了組件自動掃描機制,它可以在類路徑下尋找標記了@Component、@Service、@Controller、@Repository注解的類,並把這些類納入到spring容器中管理,它的作用和在xml中使用bean節點配置組件一樣。要使用自動掃描機制,我們需要把配置文件如下配置: Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <context:component-scan base-package="com.szy.spring"></context:component-scan> 10.</beans> 其中base-package為需要掃描的包(包括子包) @Service用於標注業務層的組件,@Controller用於標注控制層組件(如struts中的action),@Repository用於標注數據訪問組件,即DAO組件,而@Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。但是在目前的spring版本中,這幾個注解的作用是一樣的,但是在以后可能會進行區分。 下面把先前的例子修改一下: 首先是PersonDaoBean類,修改如下 Java代碼 1.package com.szy.spring.dao; 2. 3.import org.springframework.stereotype.Repository; 4. 5.@Repository 6.//告訴spring這個類要交給spring管理, 7.public class PersonDaoBean implements PersonDao 8.{ 9. public void show() 10. { 11. System.out.println("執行PersonDaoBean中的add()方法"); 12. } 13.} 然后是UserServiceImpl類 Java代碼 1.package com.szy.spring.service; 2. 3.import org.springframework.stereotype.Service; 4. 5.import com.szy.spring.dao.PersonDao; 6.@Service 7.//把這個類交給spring管理,作為服務了。 8.public class UserServiceImpl implements UserService 9.{ 10. private PersonDao personDaoBean; 11. 12. public void show() 13. { 14. personDaoBean.show(); 15. } 16. 17. public void setPersonDaoBean(PersonDao personDaoBean) 18. { 19. this.personDaoBean = personDaoBean; 20. } 21. 22. public PersonDao getPersonDaoBean() 23. { 24. return personDaoBean; 25. } 26.} 下面我們進行測試,原來的測試代碼是userServiceImpl Java代碼 1.ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 2. UserService service=(UserService)ctx.getBean("userService"); 3. service.show(); 其中userService是我們在配置文件中配置的bean的id。但是如今我們並沒有id這個屬性,在spring2.5中,默認的id是類的名稱,但是開后是小寫,也就是userServiceImpl,因此測試代碼應修改如下: Java代碼 1.AbstractApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 2. UserService service=(UserService)ctx.getBean("userServiceImpl"); 3. System.out.println(service); 如果我們想自己命名的話,則只需在注解后加上括號,里面寫入你希望的名字,如 @Service("userService")。 在spring中默認的是之生成一個bean實例,如果我們想每次調用都產生一個實例,則標注需如下配置 @Service @Scope("prototype") 在xml中我們還可以配置初始化方法和銷毀方法,使用標注后只需如下標注 Java代碼 1.@PostConstruct 2. public void init() 3. { 4. System.out.println("初始化"); 5. } 6. @PreDestroy 7. public void destory() 8. { 9. System.out.println("銷毀"); 10. } 使用注解后,我們的xml文件變得十分簡單,因此建議Spring學習筆記(10)----公共屬性的注入配置大家在以后的開發中使用注解。 Spring學習筆記(10)----公共屬性的注入配置 ------------------------------------------- 假設我們定義了四個bean類,其代碼分別如下: Java代碼 1.package com.szy.spring.bean; 2. 3.public class Bean1 { 4. private Bean2 bean2; 5. private Bean3 bean3; 6. private Bean4 bean4; 7. 8. public Bean2 getBean2() 9. { 10. return bean2; 11. } 12. public void setBean2(Bean2 bean2) 13. { 14. this.bean2 = bean2; 15. } 16. public Bean3 getBean3() 17. { 18. return bean3; 19. } 20. public void setBean3(Bean3 bean3) 21. { 22. this.bean3 = bean3; 23. } 24. public Bean4 getBean4() 25. { 26. return bean4; 27. } 28. public void setBean4(Bean4 bean4) 29. { 30. this.bean4 = bean4; 31. } 32.} Java代碼 1.package com.szy.spring.bean; 2. 3.public class Bean2 4.{ 5. private int id; 6. private String name; 7. private String password; 8. 9. public int getId() 10. { 11. return id; 12. } 13. public void setId(int id) 14. { 15. this.id = id; 16. } 17. public String getName() 18. { 19. return name; 20. } 21. public void setName(String name) 22. { 23. this.name = name; 24. } 25. public String getPassword() 26. { 27. return password; 28. } 29. public void setPassword(String password) 30. { 31. this.password = password; 32. } 33.} Java代碼 1.package com.szy.spring.bean; 2. 3.public class Bean3 4.{ 5. private int id; 6. private String name; 7. 8. public int getId() 9. { 10. return id; 11. } 12. public void setId(int id) 13. { 14. this.id = id; 15. } 16. public String getName() 17. { 18. return name; 19. } 20. public void setName(String name) 21. { 22. this.name = name; 23. } 24.} Java代碼 1.package com.szy.spring.bean; 2. 3.public class Bean4 4.{ 5. private int age; 6. 7. public int getAge() 8. { 9. return age; 10. } 11. public void setAge(int age) 12. { 13. this.age = age; 14. } 15.} 按照正常的思路,我們下面就要給每個類進行屬性的注入,配置文件如下設置: Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <bean id="bean1" class="com.szy.spring.bean.Bean1"> 10. <property name="bean2" ref="bean2"/> 11. <property name="bean3"> 12. <ref bean="bean3"/> 13. </property> 14. <property name="bean4" ref="bean4"/> 15. </bean> 16. 17. <bean id="bean2" class="com.szy.spring.bean.Bean2"> 18. <property name="id" value="100"/> 19. <property name="name"> 20. <value>kuka</value> 21. </property> 22. <property name="password" value="123"/> 23. </bean> 24. 25. <bean id="bean3" class="com.szy.spring.bean.Bean3"> 26. <property name="id" value="100"/> 27. <property name="name" value="kuka"/> 28. </bean> 29. 30. <bean id="bean4" class="com.szy.spring.bean.Bean4"> 31. <property name="age" value="22"/> 32. </bean> 33.</beans> 我們進行測試: Java代碼 1.@Test 2. public void testMethod() throws Exception 3. { 4. ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 5. Bean1 bean1 = (Bean1)ctx.getBean("bean1"); 6. 7. System.out.println("bean1.bean2.id=" + bean1.getBean2().getId()); 8. System.out.println("bean1.bean2.name=" + bean1.getBean2().getName()); 9. System.out.println("bean1.bean2.password=" + bean1.getBean2().getPassword()); 10. System.out.println("bean1.bean3.id=" + bean1.getBean3().getId()); 11. System.out.println("bean1.bean3.name=" + bean1.getBean3().getName()); 12. System.out.println("bean1.bean4.age=" + bean1.getBean4().getAge()); 13. } 正常輸出我們所預期的信息,但是我們觀察發現bean2和bean3的部分屬性的配置信息是相同的,這僅是兩個bean,如果是多個bean的話我們要修改就好修改多處,因此我們可以把這些公共的部分提出出來,進行抽象。這個在Spring中是支持的。我們在建立一個配置文件,命名為:applicationCommon.xml,其內容如下配置 Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <bean id="beanAbstract" abstract="true"> 10. <property name="id" value="100"/> 11. <property name="name" value="kuka"/> 12. </bean> 13. 14. <bean id="bean2" class="com.szy.spring.bean.Bean2" parent="beanAbstract"> 15. <property name="password" value="123"/> 16. </bean> 17. 18. <bean id="bean3" class="com.szy.spring.bean.Bean3" parent="beanAbstract"/> 19. 20.</beans> beanAbstract就是我們抽象出來的,設置abstract="true"屬性后就不需要指定class屬性。 我們把原來配置文件里的關於bean2和bean3節點注釋掉。 下面進行測試,在這里要注意由於我們使用了兩個配置文件,因此我們在讀取是要寫兩個配置文件名。我們查看ClassPathXmlApplicationContext源文件發現其有個構造函數參數是string數組,因此我們可以把這個配置文件名放在數組里面。此外我們還有另外一種實現方法,兩個配置文件一個叫applicationContext.xml,另一個applicationCommon.xml,公共部分是applicationC*.xml,下面我們就可以這樣進行測試: Java代碼 1.@Test 2. public void testMethod() throws Exception 3. { 4. ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationC*.xml"); 5. Bean1 bean1 = (Bean1)ctx.getBean("bean1"); 6. 7. System.out.println("bean1.bean2.id=" + bean1.getBean2().getId()); 8. System.out.println("bean1.bean2.name=" + bean1.getBean2().getName()); 9. System.out.println("bean1.bean2.password=" + bean1.getBean2().getPassword()); 10. System.out.println("bean1.bean3.id=" + bean1.getBean3().getId()); 11. System.out.println("bean1.bean3.name=" + bean1.getBean3().getName()); 12. System.out.println("bean1.bean4.age=" + bean1.getBean4().getAge()); 13. } 如果我們bean2的name屬性的值不是kuka,那么我們只需在applicationCommon.xml文件的bean2節點下再添加property屬性即可 Xml代碼 1.<property name="name" value="coolszy"/> Spring學習筆記(11)----自定義屬性編輯器 ------------------------------------------- 前面我們所定義的屬性都是幾本的屬性,如果我們定義一個屬性是Date類型,例如如下類中: Java代碼 1.package com.szy.spring.bean; 2. 3.import java.util.Date; 4. 5.public class Bean { 6. private Date date; 7. 8. public Date getDate() 9. { 10. return date; 11. } 12. public void setDate(Date date) 13. { 14. this.date = date; 15. } 16.} 按照我們以前學過的知識我們需要在配置文件中給該屬性注入值 Xml代碼 1.<bean id="bean" class="com.szy.spring.bean.Bean"> 2. <property name="date" value="2009-11-21"/> 3. </bean> 下面我們測試是否成功注入值 Java代碼 1.ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 2. Bean bean = (Bean)ctx.getBean("bean"); 3. System.out.println(bean.getDate()); 運行包如下異常 Exception代碼 1.org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bean' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property 'date'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [java.util.Date] for property 'date': no matching editors or conversion strategy found 通過錯誤提示信息我們得知spring不能將string轉換成date類型,沒有匹配的編輯器或者轉換機制。 如果想實現string轉換成Date,那么我們自己需要寫一個屬性編輯器 我們新建一個類DatePropertyEditor,這個類要繼承PropertyEditorSupport類。 我們需要復寫這個類中的setAsText方法,其中text參數就是配置文件中的值。我們的任務就是把text轉換成date類型的值。 Java代碼 1.package com.szy.spring.util; 2. 3.import java.beans.PropertyEditorSupport; 4.import java.text.SimpleDateFormat; 5.import java.util.Date; 6. 7.public class DatePropertyEditor extends PropertyEditorSupport 8.{ 9. 10. @Override 11. public void setAsText(String text) throws IllegalArgumentException 12. { 13. String format="yyyy-MM-dd"; 14. SimpleDateFormat sdf=new SimpleDateFormat(format); 15. try 16. { 17. Date date=sdf.parse(text); 18. this.setValue(date); //把轉換后的值傳過去 19. } catch (Exception e) 20. { 21. e.printStackTrace(); 22. } 23. } 24. 25.} 寫完編輯器后我們還需要把編輯器注入到spring中。 為了方便管理我們再新建一個配置文件applicationEditor.xml,用來配置屬性編輯器 Xml代碼 1.<?xml version="1.0" encoding="UTF-8"?> 2.<beans xmlns="http://www.springframework.org/schema/beans" 3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4. xmlns:context="http://www.springframework.org/schema/context" 5. xmlns:tx="http://www.springframework.org/schema/tx" 6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 7. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 8. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 9. <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> 10. <!-- 把值注入到CustomEditorConfigurer的 Map類型的customEditors屬性--> 11. <property name="customEditors"> 12. <map> 13. <entry key="java.util.Date"> 14. <!-- 內部bean只供自己使用 --> 15. <bean class="com.szy.spring.util.DatePropertyEditor"/> 16. </entry> 17. </map> 18. </property> 19. </bean> 20. 21.</beans> 下面我們修改下測試代碼已讀取所有的配置文件 Java代碼 1.ApplicationContext ctx=new ClassPathXmlApplicationContext("application*.xml"); 2. Bean bean = (Bean)ctx.getBean("bean"); 3. System.out.println(bean.getDate()); 最后測試,成功輸出時間。 剛才我們在配置文件中時間的格式是2009-11-21,如果我們修改成2009/11/21呢? 運行報錯:Unparseable date: "2009/11/21" 這時我們需要修改屬性編輯器類文件的格式了,很麻煩。既然spring支持注入,那么我們為什么不對格式進行注入呢? 修改屬性編輯器類: Java代碼 1.package com.szy.spring.util; 2. 3.import java.beans.PropertyEditorSupport; 4.import java.text.SimpleDateFormat; 5.import java.util.Date; 6. 7.public class DatePropertyEditor extends PropertyEditorSupport 8.{ 9. 10. private String format; 11. @Override 12. public void setAsText(String text) throws IllegalArgumentException 13. { 14. 15. SimpleDateFormat sdf=new SimpleDateFormat(format); 16. try 17. { 18. Date date=sdf.parse(text); 19. this.setValue(date); //把轉換后的值傳過去 20. } catch (Exception e) 21. { 22. e.printStackTrace(); 23. } 24. } 25. public String getFormat() 26. { 27. return format; 28. } 29. public void setFormat(String format) 30. { 31. this.format = format; 32. } 33.} 同時給該類對應的bean添加屬性節點 Xml代碼 1.<bean class="com.szy.spring.util.DatePropertyEditor"> 2. <property name="format" value="yyyy/MM/dd"></property> 3. </bean> 下次只要我們修改配置文件即可,靈活性很大。 Spring學習筆記(12)----靜態代理模式分析演示 -------------------------------------------- 代理模式分為靜態代理和動態代理。靜態代理就是我們自己定義的代理類,動態代理是程序在運行時生成的代理類。 下面演示下靜態代理類。首先我們要定義一個接口: Java代碼 1.package com.szy.spring; 2. 3.public interface UserManager 4.{ 5. public void addUser(String username,String password); 6. public void deleteUser(int userId); 7. public void modifyUser(int userId,String username,String password); 8. public void findUser(int userId); 9.} 比較常見的對用戶進行增刪改查。 下面我們常見一個實現類,實現這個接口。 Java代碼 1.package com.szy.spring; 2. 3.public class UserManagerImpl implements UserManager 4.{ 5. 6. public void addUser(String username, String password) 7. { 8. System.out.println("--------UserManagerImpl.addUser()----------"); 9. } 10. 11. public void deleteUser(int userId) 12. { 13. System.out.println("--------UserManagerImpl.deleteUser()----------"); 14. } 15. 16. public void findUser(int userId) 17. { 18. System.out.println("--------UserManagerImpl.findUser()----------"); 19. } 20. 21. public void modifyUser(int userId, String username, String password) 22. { 23. System.out.println("--------UserManagerImpl.modifyUser()----------"); 24. } 25.} 每個方法僅僅是輸出一句話。 下面我們定義一個客戶端類來調用這些方法。 Java代碼 1.package com.szy.spring; 2. 3.public class Client 4.{ 5. public static void main(String[] args) 6. { 7. UserManager userManager=new UserManagerImpl(); 8. userManager.addUser("coolszy", "kuka"); 9. } 10.} 運行正常輸出我們期望的結果。 下面我們需要加入安全性檢查,就是調用方法前我們需要進行驗證,比較常見的就是權限驗證,驗證用戶是否擁有權限, 比較常見的做法就是在UserManagerImpl類中定義一個檢查安全性的方法: Java代碼 1.public void checkSecurity() 2. { 3. System.out.println("--------UserManagerImpl.checkSecurity()----------"); 4. } 然后在每個方法中都要調用這個方法。但是這樣不符合開-閉原則(Open-Closed principle,簡稱OCP)。因此我們可以使用代理類來實現這個功能。代理模式很顯著的特征就是和目標對象的接口一致。在代理類中我們可以控制目標對象。要控制目標對象我們必須有一個目標對象的引用。為了靈活我們可以把目標對象傳到方法中,而不是在方法中實例化。同時我們把安全性檢查的代碼也放到代理類中,在調用每個方法之前調用這個檢查方法,通過代理對我們以前的類沒有破壞。 Java代碼 1.package com.szy.spring; 2. 3.public class UserManagerImplProxy implements UserManager 4.{ 5. private UserManager userManager; 6. 7. public UserManagerImplProxy(UserManager userManager) 8. { 9. this.userManager = userManager; 10. } 11. public void addUser(String username, String password) 12. { 13. checkSecurity(); 14. this.userManager.addUser(username, password); 15. } 16. public void deleteUser(int userId) 17. { 18. checkSecurity(); 19. this.userManager.deleteUser(userId); 20. } 21. public String findUser(int userId) 22. { 23. checkSecurity(); 24. return this.userManager.findUser(userId); 25. } 26. public void modifyUser(int userId, String username, String password) 27. { 28. checkSecurity(); 29. this.userManager.modifyUser(userId, username, password); 30. } 31. public void checkSecurity() 32. { 33. System.out.println("--------UserManagerImpl.checkSecurity()----------"); 34. } 35.} 下面修改客戶端類。 Java代碼 1.UserManager userManager=new UserManagerImplProxy(new UserManagerImpl()); 2. userManager.addUser("coolszy", "kuka"); 這樣總的來說比較靈活。這個依賴關系是我們自己做的,我們完全可以交給spring處理。 按照上面的這種做法有一個缺點,如果接口中方法很多,那么我們實現每一個方法都要添加檢查方法checkSecurity(),影響了我們的業務處理。采用靜態代理模式我們是沒法解決的,這時我們需要使用AOP思想。 Spring學習筆記(13)----動態代理模式分析演示 ----------------------------------------------- 上一節演示的是靜態代理模式,本節演示的是靜態代理模式,既然是動態,那么就不存在UserManagerImplProxy類。 使用動態代理我們需要聲明一個類SecurityHandler,這個類要實現InvocationHandler接口。 在類中定義一個產生動態代理的方法newProxy();同時把我們驗證的代碼放到這個類中。通過SecurityHandler,當我們調用方法時默認會調用SecurityHandler類invoke方法,我們在這個方法中進行安全性檢查,檢查通過后在調用真實的方法。需要注意的是目標對象接口中的部分方法是存在返回值的。 Java代碼 1.package com.szy.spring; 2. 3.import java.lang.reflect.InvocationHandler; 4.import java.lang.reflect.Method; 5.import java.lang.reflect.Proxy; 6. 7.public class SecurityHandler implements InvocationHandler 8.{ 9. private Object targetObject; 10. 11. public Object newProxy(Object targetObject) 12. { 13. this.targetObject=targetObject; 14. //返回動態代理 15. return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 16. targetObject.getClass().getInterfaces(), 17. this); 18. } 19. public Object invoke(Object proxy, Method method, Object[] args) 20. throws Throwable 21. { 22. checkSecurity(); 23. Object ret=null; 24. try 25. { 26. //調用目標對象的真實方法 27. ret=method.invoke(this.targetObject, args); 28. //ret接受存在的返回值,不存在返回值則為Null 29. } catch (Exception e) 30. { 31. e.printStackTrace(); 32. } 33. return null; 34. } 35. public void checkSecurity() 36. { 37. System.out.println("--------UserManagerImpl.checkSecurity()----------"); 38. } 39.} 使用這種方式維護起來相對比較好,我想進行安全性檢查就進行,不想就不進行,很方便。 下面進行客戶端調用 Java代碼 1.package com.szy.spring; 2. 3.public class Client 4.{ 5. public static void main(String[] args) 6. { 7. SecurityHandler handler=new SecurityHandler(); 8. //創建代理對象 9. UserManager userManager=(UserManager)handler.newProxy(new UserManagerImpl()); 10. userManager.addUser("coolszy", "kuka"); 11. } 12.} Spring學習筆記(14)----使用CGLIB實現AOP功能 ----------------------------------------------- 接着這上面的例子,在上面的例子中我們的UserManagerImpl類是實現了UserManager接口,如果UserManagerImpl沒有實現任何接口要怎么辦呢?應為創建代理對象時我們需要指定接口的。 Java代碼 1.Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 2. targetObject.getClass().getInterfaces(), 3. this); 由於沒有時間接口,因此我們是不能這樣創建代理接口的,這是我們需要借助第三方包來實現。在spring中提供了cglib-nodep-2.1_3.jar包。我們通過cglib創建代理對象。 下面就通過實例演示通過cglib創建代理對象。 首先創建CGlibProxyFactory,實現MethodInterceptor接口,接口中有一個intercept方法,當代理對象的方法被調用時會調用這個方法。 Java代碼 1.package com.szy.spring; 2. 3.import java.lang.reflect.Method; 4.import net.sf.cglib.proxy.Enhancer; 5.import net.sf.cglib.proxy.MethodInterceptor; 6.import net.sf.cglib.proxy.MethodProxy; 7. 8. 9.public class CGlibProxyFactory implements MethodInterceptor 10.{ 11. private Object targetObject; 12. 13. public Object newProxy(Object targetObject) 14. { 15. this.targetObject=targetObject; 16. Enhancer enhancer=new Enhancer(); 17. enhancer.setSuperclass(this.targetObject.getClass()); 18. enhancer.setCallback(this); 19. //返回代理對象 20. return enhancer.create(); 21. } 22. 23. /** 24. * proxy 帶來對象本身 25. * method 被攔截到的方法 26. * args 方法的參數 27. * methodProxy 方法的代理對象 28. */ 29. public Object intercept(Object proxy, Method method, Object[] args, 30. MethodProxy methodProxy) throws Throwable 31. { 32. checkSecurity(); 33. Object ret=null; 34. try 35. { 36. //調用目標對象的真實方法 37. ret=method.invoke(this.targetObject, args); 38. //ret接受存在的返回值,不存在返回值則為Null 39. } catch (Exception e) 40. { 41. e.printStackTrace(); 42. } 43. return ret; 44. } 45. public void checkSecurity() 46. { 47. System.out.println("--------UserManagerImpl.checkSecurity()----------"); 48. } 49.} 其實整個代碼很前面的很相似,只是創建代理對象的方法不一樣。 測試代碼: Java代碼 1.CGlibProxyFactory factory=new CGlibProxyFactory(); 2. //創建代理對象,這是這個代理對象是UserManagerImpl的子類 3. UserManagerImpl userManager=(UserManagerImpl)factory.newProxy(new UserManagerImpl()); 4. userManager.addUser("coolszy", "kuka"); 上面演示的幾個事例是不借助與任何框架的情況下實現AOP的方法。 Spring學習筆記(15)----使用Spring的注解方式實現AOP ----------------------------------------------------- 下面介紹使用Spring框架進行AOP編程。 首先我們需要導入需要的jar包: 1.aspectjrt.jar 2.aspectjweaver.jar 3.cglib-nodep-2.1_3.jar 在spring中有兩種方式實現面向切面編程,一種是基於XML配置,另一種是使用注解份額方式,在實際開放中我們可以任選其中的一種即可。 首先介紹下使用注解方式進行AOP開發。 要使用注解方式,我們需要打開注解處理器 Xml代碼 1.<aop:aspectj-autoproxy/> 我們還是使用前面介紹的接口: Java代碼 1.package com.szy.spring; 2. 3.public interface UserManager 4.{ 5. 6. public abstract void addUser(String username, String password); 7. 8. public abstract void deleteUser(int userId); 9. 10. public abstract String findUser(int userId); 11. 12. public abstract void modifyUser(int userId, String username, String password); 13. 14.} 實現這個接口: Java代碼 1.package com.szy.spring; 2. 3.public class UserManagerImpl implements UserManager 4.{ 5. 6. public void addUser(String username, String password) 7. { 8. System.out.println("--------UserManagerImpl.addUser()----------"); 9. } 10. 11. public void deleteUser(int userId) 12. { 13. System.out.println("--------UserManagerImpl.deleteUser()----------"); 14. } 15. 16. public String findUser(int userId) 17. { 18. System.out.println("--------UserManagerImpl.findUser()----------"); 19. return null; 20. } 21. 22. public void modifyUser(int userId, String username, String password) 23. { 24. System.out.println("--------UserManagerImpl.modifyUser()----------"); 25. } 26.} 下面我們定義一個切面類,由於我們使用的是注解方式,因此我們使用@Aspect來標識它是切面類。在切面類中我們要定義切入點,切入點是用來定義我們要攔截的方法。在切入點定義中使用了AOP表達式語言,下面通過實例簡單解釋一下: 表達式解釋代碼 1.@Pointcut("execution (* com.szy.spring..*.*(..))") 2.execution:代表執行 3.第一個*:代表返回值類型,使用*代表任何類型的返回值 4.com.szy.spring:代表包名 5...:代表其底下的子包也進行攔截 6.第二個*:代表對哪個類進行攔截,*代表所有類 7.第三個*:代表方法 8.(..):代表方法的蠶食有無都可以 現在我們要對UserManagerImpl類下的所有方法進行攔截,則切入點如下表示: Java代碼 1.@Pointcut("execution (* com.szy.spring.UserManagerImpl.*(..))") 2. 3.private void anyMethod() //定義切入點 4. { 5. } 其中切入點的名稱是下面方法的名稱aynMethod(),包括括號。 下面我們定義通知,通知分為前置通知、后置通知、意外通知、等。通知分為前置通知、后置通知、意外通知、最終通知和環繞通知等。 演示前置通知, Java代碼 1.@Before("anyMethod()") //括號內為切入點名稱 2. public void doBefore() 3. { 4. System.out.println("----------------執行前置通知-----------------"); 5. } 6. 7. @AfterReturning("anyMethod()") 8. public void doAfterReturning() 9. { 10. System.out.println("----------------執行后置通知-----------------"); 11. } Java代碼 1. @After("anyMethod()") 2. public void doAfter() 3. { 4. System.out.println("----------------執行最終通知-----------------"); 5. } 6. 7. @AfterThrowing("anyMethod()") 8. public void doAfterThrowing() 9. { 10. System.out.println("----------------執行意外通知-----------------"); 11. } 12. 13. @Around("anyMethod()") 14. public Object doAround(ProceedingJoinPoint pjp) throws Throwable 15. { 16. System.out.println("----------------進入判斷方法-----------------"); 17. Object result=pjp.proceed(); //該方法必須被執行 18. System.out.println("----------------退出判斷方法-----------------"); 19. return result; 20. } 我們把切面交給spring管理,要交給spring管理我們可以在配置文件同進行bean配置,或者使用掃描的方式。 Xml代碼 1.<bean id="interceptor" class="com.szy.spring.Interceptor"/> 下面我們進行測試 Java代碼 1.ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); 2. UserManager manager=(UserManager)context.getBean("userManager"); 3. manager.addUser("coolszy", "kuka"); 按照我們的設計,輸入的結果應為 ----------------執行前置通知----------------- ----------------進入判斷方法----------------- --------UserManagerImpl.addUser()---------- ----------------執行后置通知----------------- ----------------執行最終通知----------------- ----------------退出判斷方法----------------- Spring學習筆記(16)----使用Spring配置文件實現AOP ---------------------------------------------- 前面介紹了使用注解的方式,下面介紹使用配置文件的方式實現AOP。 使用配置方式,Interceptor類中不包含任何注解。 Java代碼 1.package com.szy.spring; 2. 3.import org.aspectj.lang.ProceedingJoinPoint; 4. 5.public class Interceptor 6.{ 7. public void doBefore() 8. { 9. System.out.println("----------------執行前置通知-----------------"); 10. } 11. 12. public void doAfterReturning() 13. { 14. System.out.println("----------------執行后置通知-----------------"); 15. } 16. 17. public void doAfter() 18. { 19. System.out.println("----------------執行最終通知-----------------"); 20. } 21. 22. public void doAfterThrowing() 23. { 24. System.out.println("----------------執行意外通知-----------------"); 25. } 26. 27. public Object doAround(ProceedingJoinPoint pjp) throws Throwable 28. { 29. System.out.println("----------------進入判斷方法-----------------"); 30. Object result=pjp.proceed(); //該方法必須被執行 31. System.out.println("----------------退出判斷方法-----------------"); 32. return result; 33. } 34.} 緊着這我們在配置文件中配置切面、切入點、通知等: Xml代碼 1.<bean id="aspetbean" class="com.szy.spring.Interceptor"/> 2. <aop:config> 3. <aop:aspect id="aspet" ref="aspetbean"> 4. <aop:pointcut id="cut" expression="execution (* com.szy.spring.UserManagerImpl.*(..))"/> 5. <aop:before pointcut-ref="cut" method="doBefore"/> 6. <aop:after-returning pointcut-ref="cut" method="doAfterReturning"/> 7. <aop:after pointcut-ref="cut" method="doAfter"/> 8. <aop:after-throwing pointcut-ref="cut" method="doAfterThrowing"/> 9. <aop:around pointcut-ref="cut" method="doAround"/> 10. </aop:aspect> 11. </aop:config> 運行測試代碼輸入正常結果。 在實際開發中AOP一般用於權限設置等。 Spring學習筆記(17)----使用Spring注解方式管理事務 -------------------------------------------------- 使用Spring+JDBC集成步驟如下: *配置數據源,例如: Xml代碼 1.<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 2. <property name="driverClassName" value="com.mysql.jdbc.Driver"/> 3. <property name="url" value="jdbc:mysql://localhost:3306/test"/> 4. <property name="username" value="root"/> 5. <property name="password" value="123456"/> 6. <!-- 連接池啟動時的初始值 --> 7. <property name="initialSize" value="1"/> 8. <!-- 連接池的最大值 --> 9. <property name="maxActive" value="100"/> 10. <!-- 最大空閑值.當經過一個高峰時間后,連接池可以慢慢將已經用不到的連接慢慢釋放一部分,一直減少到maxIdle為止 --> 11. <property name="maxIdle" value="2"/> 12. <!-- 最小空閑值.當空閑的連接數少於閥值時,連接池就會預申請去一些連接,以免洪峰來時來不及申請 --> 13. <property name="minIdle" value="1"/> 14. </bean> *配置事務,配置事務時,需要在xml配置文件中引入用於聲明事務的tx命名空間,事務的配置有兩種方式:注解方式和基於XML配置的方式 下面演示下使用Spring注解方式管理事務 首先在配置文件中配置Spring提供的事務管理器 Xml代碼 1.<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 2. <!-- 指定數據源 --> 3. <property name="dataSource" ref="dataSource"/> 4. </bean> 由於會使用注解方式,因此我們要打開注解處理器,對注解進行解析 Xml代碼 1.<tx:annotation-driven transaction-manager="txManager"/> 這樣我們的配置文件配置完成,下面我們在Mysql中建立一張表, Sql代碼 1.create table users 2.( 3. id int(11) not null auto_increment, 4. username varchar(20) not null, 5. primary key (id) 6.) 根據數據庫,我們創建javabean Java代碼 1.package com.szy.spring.bean; 2./** 3. * @author coolszy 4. * @time Dec 6, 2009 2:13:33 PM 5. */ 6.public class User 7.{ 8. private int id; 9. private String username; 10. public int getId() 11. { 12. return id; 13. } 14. public void setId(int id) 15. { 16. this.id = id; 17. } 18. public String getUsername() 19. { 20. return username; 21. } 22. public void setUsername(String username) 23. { 24. this.username = username; 25. } 26.} 然后創建DAO接口,在DAO中提供幾個方法: Java代碼 1.package com.szy.spring.dao; 2. 3.import java.util.List; 4. 5.import com.szy.spring.bean.User; 6. 7.public interface UserDAO 8.{ 9. public void save(User user); 10. public void update(User user); 11. Public User getUser(int id); 12. public void delete(int id); 13. public List<User> getAllUsers(); 14.} 實現這個接口 Java代碼 1.package com.szy.spring.dao.impl; 2. 3.import java.util.List; 4. 5.import com.szy.spring.bean.User; 6.import com.szy.spring.service.UserService; 7. 8./** 9. * @author coolszy 10. * @time Dec 6, 2009 2:19:22 PM 11. */ 12.public class UserDAOImpl implements UserDAO 13.{ 14. 15. public void delete(int id) 16. { 17. 18. } 19. 20. public List<User> getAllUsers() 21. { 22. return null; 23. } 24. 25. public User getUser(int id) 26. { 27. 28. } 29. 30. public void save(User user) 31. { 32. 33. } 34. 35. public void update(User user) 36. { 37. 38. } 39. 40.} 下面把這個類交給Spring管理 Xml代碼 1.<bean id="userDAO" class="com.szy.spring.dao.impl.UserDAOImpl"/> 由於要通過數據源對表進行操作,因此在DAO中添加數據源。 Java代碼 1.private DataSource dataSource; 2. 3. public void setDataSource(DataSource dataSource) 4. { 5. this.dataSource = dataSource; 6. } 然后在配置文件中進行配置 Xml代碼 1.<bean id="userDAO" class="com.szy.spring.service.impl.UserDAOImpl"> 2. <property name="dataSource" ref="dataSource"/> 3. </bean> 這樣我們就把數據源注入到類中。 在UserDAOImpl類中我們提供了dataSource,這樣我們就可以對數據庫進行操作,但是不推薦直接使用dataSource,建議使用JdbcTemplate Java代碼 1.private JdbcTemplate jdbcTemplate; 2. public void setDataSource(DataSource dataSource) 3. { 4. //this.dataSource = dataSource; 5. this.jdbcTemplate=new JdbcTemplate(dataSource); 6. } 下面我們使用jdbcTemplate對數據庫進行增刪改查,詳細代碼見附件。 Java代碼 1.package com.szy.spring.dao.impl; 2. 3.import java.util.List; 4. 5.import javax.sql.DataSource; 6. 7.import org.springframework.jdbc.core.JdbcTemplate; 8. 9.import com.szy.spring.bean.User; 10.import com.szy.spring.dao.UserDAO; 11. 12./** 13. * @author coolszy 14. * @time Dec 6, 2009 2:19:22 PM 15. */ 16.public class UserDAOImpl implements UserDAO 17.{ 18. //private DataSource dataSource; 19. private JdbcTemplate jdbcTemplate; 20. public void setDataSource(DataSource dataSource) 21. { 22. //this.dataSource = dataSource; 23. this.jdbcTemplate=new JdbcTemplate(dataSource); 24. } 25. 26. public void delete(int id) 27. { 28. jdbcTemplate.update("delete from users where id=?", new Object[]{id}, 29. new int[]{java.sql.Types.INTEGER}); 30. } 31. 32. public List<User> getAllUsers() 33. { 34. return (List<User>)jdbcTemplate.query("select * from users", new UserRowMapper()); 35. } 36. 37. public User getUser(int id) 38. { 39. return (User)jdbcTemplate.queryForObject("select * from users where id=?", new Object[]{id}, 40. new int[]{java.sql.Types.INTEGER}, new UserRowMapper()); 41. 42. } 43. 44. public void save(User user) 45. { 46. jdbcTemplate.update("insert into users(username) values(?)", new Object[]{user.getUsername()}, 47. new int[]{java.sql.Types.VARCHAR}); 48. 49. } 50. 51. public void update(User user) 52. { 53. jdbcTemplate.update("update users set username=? where id=?", new Object[]{user.getUsername(),user.getId()}, 54. new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER}); 55. 56. } 57. 58.} 編寫測試代碼,代碼運行正常。 在我們實現的每個方法中如delete()方法,如果delete方法是這樣 Java代碼 1.public void delete(int id) 2. { 3. jdbcTemplate.update("delete from users where id=?", new Object[]{id}, 4. new int[]{java.sql.Types.INTEGER}); 5.jdbcTemplate.update("delete from users where id=?", new Object[]{id}, 6. new int[]{java.sql.Types.INTEGER}); 7. 8. } 9. 這樣每條語句都會在各自的事務中執行,並不能保證在同一使用中執行,為了保證在同一事務中執行,我們應使用Spring容器提供的聲明事務,我們在UserDAOImpl 類上加入@Transactional,表示該類受Spring事務管理。如果該類中每個方法不需要事務管理,如getUser方法,則在該方法前加入 Java代碼 1.@Transactional(propagation=Propagation.NOT_SUPPORTED) PS:在上面的配置文件中我們在配置文件中指明了驅動類等信息,如果我們想寫在配置文件中要怎么配置能,首先我們編寫配置文件, Jdbc.properties代碼 1.driverClassName=com.mysql.jdbc.Driver 2.url=jdbc\:mysql\://localhost\:3306/test 3.username=root 4.password=123456 5.initialSize=1 6.maxActive=100 7.maxIdle=2 8.minIdle=1 然后Spring的配置文件需進行如下配置: Xml代碼 1.<context:property-placeholder location="classpath:jdbc.properties"/> 2. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 3. <property name="driverClassName" value="${driverClassName}"/> 4. <property name="url" value="${url}"/> 5. <property name="username" value="${username}"/> 6. <property name="password" value="${password}"/> 7. <property name="initialSize" value="${initialSize}"/> 8. <property name="maxActive" value="${maxActive}"/> 9. <property name="maxIdle" value="${maxIdle}"/> 10. <property name="minIdle" value="${minIdle}"/> 11. </bean> 這樣就可以從屬性文件中讀取到配置信息。 Spring學習筆記(18)----使用Spring配置文件實現事務管理 ------------------------------------------------------- 由於我們要攔截UserDAOImpl中的方法,因此我們需要在配置文件中配置信息,在配置文件中使用了AOP技術來攔截方法。 Xml代碼 1.<aop:config> 2. <aop:pointcut id="transactionPointcut" expression="execution(* com.szy.spring.dao.impl..*.*(..))"/> 3. <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut"/> 4. </aop:config> 5. <tx:advice id="txAdvice" transaction-manager="txManager"> 6. <tx:attributes> 7. <!-- 如果連接的方法是以get開頭的方法,則不使用事務 --> 8. <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/> 9. <tx:method name="*"/> 10. </tx:attributes> 11. </tx:advice> 這樣Spring就能對這個類進行事務管理。 下面我們測試下數據庫操作是否在同一事務中執行。 假設我們的delete方法如下: Java代碼 1.public void delete(int id) 2. { 3. jdbcTemplate.update("delete from users where id=?", new Object[]{id}, 4. new int[]{java.sql.Types.INTEGER}); 5. jdbcTemplate.update("delete from users1 where id=10"); 6. } 在第二條刪除語句中,users1表是不存在的,如果兩次update語句是在兩個事務中執行,則第一條能成功執行,並且數據庫中該id的記錄已經被刪除,而第二條由於不存在該表不能正常刪除。如果在同一事務中執行,由於第二條update出錯,數據庫中不能刪除任何記錄。 測試代碼: Java代碼 1.@Test 2. public void testDelete() 3. { 4. userDAO.delete(5); 5. } 程序報錯,同時id=5的記錄沒有被刪除。如果我們把配置文件中關於事務配置的信息給注釋掉,再次測試,程序同樣報錯,但是id=5的記錄被成功刪除掉,這說明這兩條update語句是在兩個不同的事務中運行。 PS:在平時開發中,Spring團隊建議使用注解的方式進行配置,這樣配置文件顯得精簡,同時也會做到精確控制。