目錄
文章目錄
-
- 目錄
- 前言
- 下載下傳Spring 依賴
- 導入Spring相關jar包
- IOC 容器
- IOC 容器Bean的操作
-
- Bean管理操作有兩種方式
- xml配置檔案中``标簽介紹
- Spring DI 的實作方式:屬性注入和構造注入Book類: (依賴注入)
- Spring 執行個體化:bean(service與dao為案例)
- Spring 執行個體化:嵌套bean與級聯指派建立對象(一對多為案例)
- Spring 執行個體化:集合資料注入
- Spring 執行個體化:提取List集合、Map對象的資料注入
- Spring 執行個體化:工廠Bean(FactoryBean)
- Spring Bean的作用域
- Spring Bean的生命周期
- Spring Bean自動注入
-
- 什麼是自動注入?
- Bean自動注入使用方法
- Spring Bean自動注入druid連接配接池
- Spring Annotation (注解)
-
- 注解注入Bean
-
- 配置注解掃描和注解掃描規則幾種方式
-
- 方式一:指定包路徑掃描
- 方式二:規則掃描定向注解
- 方式三:規則掃描反向注解(過濾注解)
- 注解Bean測試
- 注解屬性注入
-
- @Autowired根據類型來注入屬性值 (service和dao為案例)
- @Qualifier根據Bean名稱注入屬性,與@Autowired 注解配合使用(service和dao為案例)
- @Resource根據Bean名稱注入屬性,預設按照 Bean 執行個體名稱進行裝配
- Spring 使用配置類代替配置檔案
- AOP 面向切面程式設計
-
- AOP JDK動态代理
- AspectJ開發AOP
- AspectJ 注解操作
-
- AspectJ 注解介紹
- AspectJ 注解切入點表達式介紹
- AspectJ 注解的使用
- AspectJ 配置檔案操作
- Spring JDBCTemplate操作資料庫
-
- 什麼是JDBCTemplate?
- 導入相關jar包
- JDBCTemplate使用執行個體
- JDBCTemplate 操作資料庫(增、删、改)
- JDBCTemplate 操作資料庫(查詢、批量操作)
- Spring 事務操作
-
- 事務的特性(ACID)
- Spring事務管理API
-
- PlatformTransactionManager 接口介紹
- TransactionDefinition 接口介紹
- @Transactional 注解
- 案例:
- Spring使用配置類代替xml配置檔案
- Spring5 架構新功能
-
- Spring5 架構日志
- Spring5 架構核心容器支援@Nullable 注解
- Spring5 核心容器支援函數式風格 GenericApplicationContext
- Spring5 支援整合 JUnit5
前言
Spring 是輕量級開源的JavaEE架構,它可以解決企業應用開發的複雜性。Spring 有兩個核心部分分别是 控制反轉(Inversion of Control 簡稱:IOC)、面向切面程式設計(Aspect Oriented Programming 簡稱:Aop),所謂的IOC則是把建立對象的過程交給 Spring 進行管理。而AOP則是對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
下載下傳Spring 依賴
- 首先進入Spring官網找到Projects下的Spring Framework。
- 在Spring Framework中可以檢視Spring GA 穩定版本;進入Github。
- 在Github中找到Access to Binaries裡的 Spring Framework Artifacts點選。
- 找到Downloading a Distribution點選 https://repo.spring.io位址。
- 找到release/org/springframework/spring,複制的路徑拼接到repo.spring.io後面:https://repo.spring.io/release/org/springframework/
- 下載下傳所需的spring版本
導入Spring相關jar包
commons-logging.jar 可以在mvnrepository上下載下傳
IOC 容器
所謂的IOC則是把建立對象的過程交給 Spring 進行管理,實作低耦合。
- IOC底層原理:xml解析、工廠模式、反射。
- Spring提供IOC容器實作兩接口方式:
- BeanFactory:是 Spring 内部的使用接口,不推薦開發人員使用 。加載配置檔案時候不會建立對象,在擷取對象(使用)才去建立對象。
- ApplicationContext:BeanFactory 接口的子接口,提供更多更強大的功能,推薦開發人 員使用,加載配置檔案時就會把配置檔案中的所有對象進行建立。
- FileSystemXmlApplicationContext(String str) 實作類:某磁盤内的檔案位址。
- ClassPathXmlApplicationContext(String str)實作類:src下某個檔案名。
IOC 容器Bean的操作
Bean管理操作有兩種方式
Bean管理有兩個操作:Spring 建立對象、Spring 注入屬性。
xml配置檔案中 <bean>
标簽介紹
<bean>
屬性 | 描述 |
---|---|
id | 是一個 Bean 的唯一辨別符,Spring 容器對 Bean 的配置和管理都通過該屬性完成 |
name | Spring 容器同樣可以通過此屬性對容器中的 Bean 進行配置和管理,name 屬性中可以為 Bean 指定多個名稱,每個名稱之間用逗号或分号隔開 |
class | 該屬性指定了 Bean 的具體實作類,它必須是一個完整的類名,使用類的全限定名 |
scope | 用于設定 Bean 執行個體的作用域,其屬性值有 singleton(單例)、prototype(原型)、request、session 和 global Session。其預設值是 singleton |
constructor-arg | 元素的子元素,可以使用此元素傳入構造參數進行執行個體化。該元素的 index 屬性指定構造參數的序号(從 0 開始),type 屬性指定構造參數的類型 |
property | 元素的子元素,用于調用 Bean 執行個體中的 Set 方法完成屬性指派,進而完成依賴注入。該元素的 name 屬性指定 Bean 執行個體中的相應屬性名 |
ref | 和 等元素的子元索,該元素中的 bean 屬性用于指定對 Bean 工廠中某個 Bean 執行個體的引用 |
value | 和 等元素的子元素,用于直接指定一個常量值 |
list | 用于封裝 List 或數組類型的依賴注入 |
set | 用于封裝 Set 類型屬性的依賴注入 |
map | 用于封裝 Map 類型屬性的依賴注入 |
entry | 元素的子元素,用于設定一個鍵值對。其 key 屬性指定字元串類型的鍵值,ref 或 value 子元素指定其值 |
-
标簽屬性介紹:(bean子标簽)<property>
屬性 詳情 name Java類中所對應的屬性名稱。 value 要指派的屬性。 ref xml中bean标簽的id,也就是xml檔案中的一個對象。 -
标簽有參構造器介紹:(bean子标簽)<constructor-arg>
屬性 詳情 name 有參構造器中對應的名稱。 value 要指派的屬性。 index 有參構造器中第幾個參數。
Spring DI 的實作方式:屬性注入和構造注入Book類: (依賴注入)
public class Book {
private String name;
public Book(String name) {this.name = name;}
public void setName(String name) {this.name = name;}
public String getName() {return name;}
}
xml檔案:
- 使用setter方法注入屬性。
<bean id="book" class="com.tmsklst.spring5.Book"> <property name="name" value="托馬斯·克裡斯特"></property> </bean>
- 使用有參構造器注入屬性。
<bean id="book" class="com.tmsklst.spring5.Book"> <constructor-arg name="name" value="托馬斯·克裡斯特"></constructor-arg> </bean>
- 字面量設定null值
<bean id="book" class="com.tmsklst.spring5.Book"> <property name="name"> <null/> </property> </bean>
- 屬性值包含特殊符号
<bean id="book" class="com.tmsklst.spring5.Book"> <property name="name"> <value><![CDATA[<<夏洛克·福爾摩斯>>]]></value> </property> </bean>
Spring 執行個體化:bean(service與dao為案例)
- 建立UserDaoImpl類:
public class UserDaoImpl implements UserDao { @Override public void update() { System.out.println("userDaoImpl update............."); } }
- 建立UserServiceImpl類:(注意:需要個屬性添加set方法)
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void add() { System.out.println("UserServiceImpl add.............."); userDao.update(); } }
- 建立bean.xml配置檔案:
<!-- service對象的建立 --> <bean id="UserService" class="com.tmsklst.service.impl.UserServiceImpl"> <!-- 注入service對象 --> <property name="userDao" ref="UserDao"></property> </bean> <!-- dao對象的建立 --> <bean id="UserDao" class="com.tmsklst.dao.impl.UserDaoImpl"></bean>
- 測試:
public void newInstanceTest() { //加載配置檔案 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); //擷取配置檔案對象 UserServiceImpl userService = context.getBean("UserService", UserServiceImpl.class); userService.add(); }
Spring 執行個體化:嵌套bean與級聯指派建立對象(一對多為案例)
- 建立部門類Dept:
public class Dept { private String dname; public void setDname(String dname) { this.dname = dname; } @Override public String toString() { return "Dept{" +"dname='" + dname + '\'' + '}'; } }
- 建立員工類Emp:
public class Emp { private String ename; private String gender; private Dept dept;//員工屬于一個部門,使用對象形式表示 public Dept getDept() { //級聯指派所需的get方法 return dept; } public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } public void setDept(Dept dept) { this.dept = dept; } public void add() { System.out.println(ename + "::" + gender + "::" + dept); } }
- 建立bean.xml配置檔案:(嵌套)
或 (級聯指派 注意:在emp類中一定要生成dept屬性的get方法)<bean id="emp" class="com.tmsklst.pojo.Emp"> <!-- 普通屬性 --> <property name="ename" value="托馬斯·克裡斯特"></property> <property name="gender" value="男"></property> <!-- 對象屬性 --> <property name="dept"> <bean id="dept" class="com.tmsklst.pojo.Dept"> <property name="dname" value="技術部"></property> </bean> </property> </bean>
<bean id="emp" class="com.tmsklst.pojo.Emp"> <!-- 普通屬性 --> <property name="ename" value="托馬斯·克裡斯特"></property> <property name="gender" value="男"></property> <!-- 級聯指派 --> <property name="dept" ref="dept"></property> <property name="dept.dname" value="财務部"></property> </bean> <bean id="dept" class="com.tmsklst.pojo.Dept"></bean>
- 測試:
public void newInstanceTest() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Emp emp = context.getBean("emp", Emp.class); emp.add(); }
Spring 執行個體化:集合資料注入
- 建立Student類:
public class Student { //數組屬性 private String[] array; //List屬性 private List<String> list; //set屬性 private Set<String> set; //Map屬性 private Map<String,String> map; //List對象屬性 private List<User> userList; public void setArray(String[] courses) { this.array = courses; } public void setList(List<String> list) { this.list = list; } public void setSet(Set<String> set) { this.set = set; } public void setMap(Map<String, String> map) { this.map = map; } public void setUserList(List<User> userList) { this.userList = userList; } public void collectionToString() { System.out.println("array:" + Arrays.asList(array)); System.out.println("list:" + list); System.out.println("set:" + set); System.out.println("map:" + map); System.out.println("userList:" + userList); } }
- 建立xml配置檔案:
<!-- 集合屬性的注入 --> <bean id="student" class="com.tmsklst.collection.Student"> <!-- 數組注入 --> <property name="array"> <array> <value>array01</value> <value>array02</value> </array> </property> <!-- List注入 --> <property name="list"> <list> <value>list01</value> <value>list02</value> </list> </property> <!-- set注入 --> <property name="set"> <set> <value>set01</value> <value>set02</value> </set> </property> <!-- map注入 --> <property name="map"> <map> <entry key="key01" value="value01"></entry> <entry key="key02" value="value02"></entry> </map> </property> <!-- 對象list注入 --> <property name="userList"> <list> <ref bean="user1"></ref> <ref bean="user2"></ref> </list> </property> </bean> <bean id="user1" class="com.tmsklst.pojo.User"> <property name="name" value="托馬斯·克裡斯特"></property> </bean> <bean id="user2" class="com.tmsklst.pojo.User"> <property name="name" value="湯姆"></property> </bean>
Spring 執行個體化:提取List集合、Map對象的資料注入
- 建立Book類:
public class Book { private List<String> list; private Map<Integer,User> map; public void setList(List<String> list) { this.list = list; } public void setMap(Map<Integer, User> map) { this.map = map; } public void add() { System.out.println("list:" + list); System.out.println("map:" + map); } }
- 在配置檔案beans頭部标簽中引入名稱空間 util:
<beans xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd>
- 使用 util 标簽完成 list 集合與map集合對象的注入提取:
完整配置檔案:<!-- 建立user對象 --> <bean id="user1" class="com.tmsklst.pojo.User"> <property name="name" value="托馬斯·克裡斯特"></property> </bean> <bean id="user2" class="com.tmsklst.pojo.User"> <property name="name" value="湯姆"></property> </bean> <!-- 1.提取list集合類型屬性注入 --> <util:list id="bookList"> <value>九陽神功</value> <value>九陰正經</value> </util:list> <util:map id="bookMap"> <entry key="1"> <ref bean="user1"></ref> </entry> <entry key="2"> <ref bean="user2"></ref> </entry> </util:map> <!-- 2.提取list集合類型屬性注入的使用 --> <bean id="book" class="com.tmsklst.pojo.Book"> <property name="list" ref="bookList"></property> <property name="map" ref="bookMap"></property> </bean>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 建立user對象 --> <bean id="user1" class="com.tmsklst.pojo.User"> <property name="name" value="托馬斯·克裡斯特"></property> </bean> <bean id="user2" class="com.tmsklst.pojo.User"> <property name="name" value="湯姆"></property> </bean> <!-- 1.提取list集合類型屬性注入 --> <util:list id="bookList"> <value>九陽神功</value> <value>九陰正經</value> </util:list> <util:map id="bookMap"> <entry key="1"> <ref bean="user1"></ref> </entry> <entry key="2"> <ref bean="user2"></ref> </entry> </util:map> <!-- 2.提取list集合類型屬性注入的使用 --> <bean id="book" class="com.tmsklst.pojo.Book"> <property name="list" ref="bookList"></property> <property name="map" ref="bookMap"></property> </bean> </beans>
- 測試
public void collectionTest2() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Book book = context.getBean("book", Book.class); book.add(); }
Spring 執行個體化:工廠Bean(FactoryBean)
在配置檔案定義bean類型可以和傳回類型不一樣。
- 建立MyBean類,讓這個類作為工廠 bean,實作接口 FactoryBean
public class MyBean implements FactoryBean<User> { //傳回 Bean 的類型取決于 FactoryBean<T> 泛型值 @Override public User getObject() throws Exception { User user = new User(); return user; } }
- 第二步 xml配置
- 第三步 測試
public void myBeanTest() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); User myBean = context.getBean("myBean", User.class); System.out.println(myBean); }
Spring Bean的作用域
- 在 Spring 裡面,設定建立 bean 執行個體是單執行個體還是多執行個體。
- 在 Spring 裡面,預設情況下,bean 是單執行個體對象。
- 如何設定單執行個體還是多執行個體。
- 在 spring 配置檔案 bean 标簽裡面有屬性 scope 用于設定單執行個體還是多執行個體。
- scope 屬性:
- 預設值 singleton 表示是單執行個體對象。
- prototype 表示是多執行個體對象。
<bean scope="singleton"></bean> <bean scope="prototype"></bean>
- request 單執行個體對象。而對不同的 HTTP 請求,會傳回不同的執行個體,該作用域僅在目前 HTTP Request 内有效。(不常用)
- session 單執行個體對象。而對不同的 Session會話,會傳回不同的執行個體,該作用域僅在目前 HTTP Session 内有效。(不常用)
- singleton 和 prototype 差別
- 設定 scope 值是 singleton 時候,加載 spring 配置檔案時候就會建立單執行個體對象。
<bean id="user1" class="com.tmsklst.pojo.User" scope="singleton"></bean> <bean id="user2" class="com.tmsklst.pojo.User" scope="propertype"></bean>
public void Test() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); User singUser01 = context.getBean("user1", User.class); User singUser02 = context.getBean("user1", User.class); System.out.println(singUser01);//[email protected] System.out.println(singUser02);//[email protected] User proUser01 = context.getBean("user2", User.class); User proUser02 = context.getBean("user2", User.class); System.out.println(proUser01);//[email protected] System.out.println(proUser02);//[email protected] }
- 設定 scope 值是 prototype 時候,不是在加載 spring 配置檔案時候建立對象,在調用 getBean 方法時候建立多執行個體對象。
- 設定 scope 值是 singleton 時候,加載 spring 配置檔案時候就會建立單執行個體對象。
Spring Bean的生命周期
- 建立Order類 ,并在類中自定以兩個方法
與initMethod()
用于初始化和銷毀。destroyMethod()
public class Order { private String name; public Order() { System.out.println("第一步 建立Bean的執行個體"); } public void setName(String name) { this.name = name; System.out.println("第二步 設定屬性值"); } //初始化的方法 public void initMethod() { System.out.println("第三步 執行初始化方法"); } //銷毀方法 public void destroyMethod() { System.out.println("第五步 執行銷毀方法"); } }
- 建立MyBeanPost類 作為後置處理器并實作BeanPostProcessor接口。
public class MyBeanPost implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之前執行的方法"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之後執行的方法"); return bean; } }
- 建立xml配置檔案,在bean标簽中使用
與init-method
屬性分别指定Order類中的初始化方法與銷毀方法。destroy-method
<bean id="order" class="com.tmsklst.pojo.Order" init-method="initMethod" destroy-method="destroyMethod"> <property name="name" value="iPhont"></property> </bean> <!-- 配置後置處理器 --> <bean id="myBeanPost" class="com.tmsklst.pojo.MyBeanPost"></bean>
- 測試
public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Object order = context.getBean("order", Order.class); System.out.println("第四步 擷取建立bean執行個體對象"); System.out.println(order); //銷毀執行個體 context.close(); }
Spring Bean自動注入
什麼是自動注入?
根據指定裝配規則屬性名稱或者屬性類型,Spring自動将比對的屬性值進行注入。
Bean自動注入使用方法
給bean标簽添加屬性autowire:
- byType:根據 xml 中 bean的類型自動注入。(對多種同源類型無效)
- byName:根據 xml 中 bean的名稱自動注入。
<bean id="emp" class="com.tmsklst.autowire.Emp" autowire="byName"> <!-- 或 --> <bean id="emp" class="com.tmsklst.autowire.Emp" autowire="byType">
案例:
Emp類:
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"dept=" + dept +
'}';
}
public void test() {
System.out.println(dept);
}
}
Dep類:
xml配置檔案:
<bean id="emp" class="com.tmsklst.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.tmsklst.autowire.Dept"></bean>
測試:
public void test1() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp);
}
Spring Bean自動注入druid連接配接池
- 在src下建立jdbc.properties配置檔案
driverClassName=com.mysql.jdbc.Driver url=jdbc.mysql://localhost:3306/test username=root passowrd=root
- 在xml中新增名稱空間context
<beans xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
- 名稱空間引入配置檔案
- bean配置
<bean id="druid" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"></property> <property name="url" value="${url}"></property> <property name="username" value="${username}"></property> <property name="password" value="${password}"></property> </bean>
Spring Annotation (注解)
在 Spring 中,盡管使用 XML 配置檔案可以實作 Bean 的裝配工作,但如果應用中 Bean 的數量較多,會導緻 XML 配置檔案過于臃腫,進而給維護和更新帶來一定的困難。使用注解大大簡化了xml配置檔案。
注解格式:
@注解名稱(屬性名稱=屬性值,屬性名稱=屬性值。。。)
可包含多個屬性。
注解的使用範圍:類、方法、屬性。
所需依賴:spring-aop.jar
注解名稱 | 描述 |
---|---|
@Component | 可以使用此注解描述 Spring 中的 Bean,但它是一個泛化的概念,僅僅表示一個元件(Bean),并且可以作用在任何層次。使用時隻需将該注解标注在相應類上即可。 |
@Service | 通常作用在業務層(Service 層),用于将業務層的類辨別為 Spring 中的 Bean,其功能與 @Component 相同。 |
@Controller | 通常作用在控制層(如 Struts2 的 Action),用于将控制層的類辨別為 Spring 中的 Bean,其功能與 @Component 相同。 |
@Repository | 用于将資料通路層(DAO層)的類辨別為 Spring 中的 Bean,其功能與 @Component 相同。 |
@Autowired | 用于對 Bean 的屬性變量、屬性的 Set 方法及構造函數進行标注,配合對應的注解處理器完成 Bean 的自動配置工作。預設按照 Bean 的類型進行裝配。 |
@Qualifier | 與 @Autowired 注解配合使用,會将預設的按 Bean 類型裝配修改為按 Bean 的執行個體名稱裝配,Bean 的執行個體名稱由 @Qualifier 注解的參數指定。 |
@Resource | 其作用與 Autowired 一樣。其差別在于 @Autowired 預設按照 Bean 類型裝配,而 @Resource 預設按照 Bean 執行個體名稱進行裝配。 @Resource 中有兩個重要屬性:name 和 type。 Spring 将 name 屬性解析為 Bean 執行個體名稱,type 屬性解析為 Bean 執行個體類型。如果指定 name 屬性,則按執行個體名稱進行裝配;如果指定 type 屬性,則按 Bean 類型進行裝配。 如果都不指定,則先按 Bean 執行個體名稱裝配,如果不能比對,則再按照 Bean 類型進行裝配;如果都無法比對,則抛出 NoSuchBeanDefinitionException 異常。 |
@Value | 給普通屬性指派。 |
注解注入Bean
配置注解掃描和注解掃描規則幾種方式
方式一:指定包路徑掃描
使用context命名空間,通知Spring掃描指定目錄進行注解解析。(不同源的包用逗号隔開)
<context:component-scan base-package="com.tmsklst.annotation,
com.tmsklst1.dao,
com.tmsklst2.service" />
方式二:規則掃描定向注解
設定use-default-filters屬性為false:不使用預設掃描規則,自定義配置規則。
通過include-filter标簽指定注解:
- type:annotation(注解)。
- expression:注解包全路徑。
<context:component-scan base-package="com.tmsklst" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> </context:component-scan>
方式三:規則掃描反向注解(過濾注解)
通過exclude-filter标簽指定需要無視的注解:
- type:annotation(注解)。
- expression:注解包全路徑。(如果指定為Component,則該包下的Component注解不解析)
<context:component-scan base-package="com.tmsklst"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/> </context:component-scan>
注解Bean測試
- 使用context命名空間,通知Spring掃描指定目錄進行注解解析。
<context:component-scan base-package="com.tmsklst" use-default-filters="false" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> </context:component-scan>
-
建立UserService類,在類上方使用注解。注解裡的value值預設為類的名稱,且首字母小寫。
注解等同于:
<bean id="userService" class="com.tmsklst.service.UserService" />
@Component(value = "userService") public class UserService { public void add() { System.out.println("service add……"); } }
- 測試
public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); }
注解屬性注入
@Autowired根據類型來注入屬性值 (service和dao為案例)
- Service層:建立UserService類, 屬性上的 @Autowired注解會更具類型(UserDao)去Dao層找到相應的類。
@Service public class UserService { @Autowired private UserDao userDao; public void add() { System.out.println("service add……"); userDao.add(); } }
- Dao層:建立UserDao實作類,别忘了給實作類裝配bean(@Repository)
@Repository public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("UserDao 實作類一 add…………"); } }
@Qualifier根據Bean名稱注入屬性,與@Autowired 注解配合使用(service和dao為案例)
- Service層:建立UserService類, 屬性上的 @Autowired注解會更具類型(UserDao)去Dao層找到相應的類,當UserDao有多個實作類時,則加上@Qualifier注解,而value值是目标Bean名稱。
@Service public class UserService { @Autowired @Qualifier(value = "userDao2") private UserDao userDao; public void add() { System.out.println("service add……"); userDao.add(); } }
- Dao層:建立UserDao實作類,多個實作類需要定義value值(@Repository)
// 實作類一 @Repository(value = "userDaol") public class UserDaoImpl implements UserDao { @Override public void add() { System.out.println("UserDao 實作類一 add…………"); } } // 實作類二 @Repository(value = "userDao2") public class UserDaoImpl2 implements UserDao { @Override public void add() { System.out.println("UserDao 實作類二 add()…………"); } }
- 測試
public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); userService.add(); } /** [email protected] service add…… UserDao 實作類二 add()………… */
@Resource根據Bean名稱注入屬性,預設按照 Bean 執行個體名稱進行裝配
@Service
public class UserService {
@Resource(name = "userDao")
private UserDao userDao;
public void add() {
System.out.println("service add……");
userDao.add();
}
}
Spring 使用配置類代替配置檔案
建立一個SpringConfig類,使用@Configuration标注目前類為配置類,@ComponentScan指向解析注解的包。
@Configuration
@ComponentScan(basePackages = {"com.tmsklst5"})
public class SpringConfig {
}
AOP 面向切面程式設計
- 利用AOP(Aspect Oriented Programming)可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
- AOP 采取橫向抽取機制,取代了傳統縱向繼承體系的重複性代碼,其應用主要展現在事務處理、日志管理、權限控制、異常處理等方面。
AOP JDK動态代理
- JDK 動态代理是通過 JDK 中的 java.lang.reflect.Proxy 類實作的。
-
:傳回指定接口的代理類執行個體,該接口将方法調用分派給指定的調用處理程式。static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
- ClassLoader loader 參數:類的加載器。
- Class<?>[] interfaces參數:增強方法所在類的實作接口,支援多個接口。
- InvocationHandler h參數:實作InvocationHandler接口建立代理對象,增強代碼部分。
執行個體:
- 建立接口UserDao,在UserDao添加兩個方法,如下所示。
public interface UserDao { int add(int num1,int num2); String update(String name); }
- 建立UserDao的實作類UserDaoimpl,如下所示。
public class UserDaoimpl implements UserDao { @Override public int add(int num1, int num2) { System.out.println("第二:我是add方法原有邏輯……"); return num1 + num2; } @Override public String update(String name) { System.out.println("第二:我是uodate方法原有邏輯……"); return name; } }
- 建立JDKProxy類實作JDK動态代理。
public class JDKProxy { public static void main(String[] args) { /* 1.擷取需要擴充功能的接口 */ Class[] interfaces = {UserDao.class}; /* 2.建立接口實作類對象 */ UserDao userDaoimpl = new UserDaoimpl(); /* 3.使用Proxy類中的newProxyInstance方法動态代理。 參數:類的加載器、接口、實作了InvocationHandler接口的類對象,此處也可用匿名InvocationHandler接口。 傳回新的執行個體。 */ UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoimpl)); /* 8.使用新的執行個體調用方法 add()與 update() */ int add = userDaoProxy.add(10, 10); System.out.println("第四:addResult:" + add); String update = userDaoProxy.update("托馬斯·克裡斯特"); System.out.println("第四:updateResult:" + update); } } /* 4.建立實作了InvocationHandler接口類 */ class UserDaoProxy implements InvocationHandler { /* 5.接收目标類對象 */ private Object obj; /* 6.建立有參構造器,用于接收目标類對象 */ public UserDaoProxy(Object obj) { this.obj = obj; } /* 7.重寫invoke方法用于增強邏輯 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前處理 if ("add".equals(method.getName())) { System.out.println("第一:我是add方法之前執行…… " + method.getName() + ":傳遞參數" + Arrays.asList(args)); } if ("update".equals(method.getName())) { System.out.println("第一:我是update方法之前執行…… " + method.getName() + ":傳遞參數" + Arrays.asList(args)); } /* 9.調用invoke方法被增強的方法執行,參數:目标類對象、參數 */ Object invoke = method.invoke(obj, args); //方法之後處理 System.out.println("第三:方法之後執行……" + obj); return invoke; } }
AspectJ開發AOP
AspectJ 是一個基于 Java 語言的 AOP 架構,它擴充了 Java 語言。Spring 2.0 以後,新增了對 AspectJ 方式的支援,新版本的 Spring 架構,建議使用 AspectJ 方式開發 AOP。
AspectJ 開發AOP的兩種方式:
- 基于XML的聲明方式。
- 基于Annotation的聲明方式。
- 除了Spring Aop的jar包以外,還要導入與 AspectJ 相關jar包:
-
Spring 為 AspectJ 提供的實作。spring-aspects-5.2.6.RELEASE:
-
com.springsource.net.sf.cglib-2.2.0
-
com.springsource.org.aopalliance-1.0.0
-
AspectJ 提供的規範。com.springsource.org.aspectj.weaver-1.6.8.RELEASE:
-
AspectJ 注解操作
AspectJ 架構為 AOP 開發提供了另一種開發方式——基于 Annotation 的聲明式。AspectJ 允許使用注解定義切面、切入點和增強處理,而 Spring 架構則可以識别并根據這些注解生成 AOP 代理。
AspectJ 注解介紹
名稱 | 描述 |
---|---|
@Aspect | 定義一個切面。 |
@Before | 定義前置通知。(在被增強的方法之前執行) |
@AfterReturning | 定義後置通知。(在程式正常執行後執行) |
@AfterThrowing | 定義異常通知。(有異常時執行) |
@After | 定義最終通知。(不管是否異常,都執行) |
@Around | 定義環繞通知。(在被增強的方法前後執行)被此注解所定義的方法必須攜帶ProceedingJoinPoint類型的參數,通過ProceedingJoinPoint調用proceed()方法,執行被增強的方法。 |
@DeclareParents | 用于定義引介通知。 |
@Order | 在有多個切面的情況下,設定優先級。數值越小,優先級越高。 |
@Pointcut | 對相同切入點作抽取。(對切入點表達式做封裝)在其他切入點value值中調用被此注解标示的方法。 |
AspectJ 注解切入點表達式介紹
- 文法結構:@Before(value = “execution(【權限修飾符】【傳回值類型】【目标類全路徑】【方法名(【參數清單】)】)”)。
- *通配符:所有的。
- 沒有傳回值類型用空格代替。
- 執行個體1:對 aop.tmsklst.aspectJannotation.User 類的add方法增強。
execution(* aop.tmsklst.aspectJannotation.User.add(..))
- 執行個體2:對 aop.tmsklst.aspectJannotation.User 類的所有方法增強。
execution(* aop.tmsklst.aspectJannotation.User.*(..))
- 執行個體3:對 aop.tmsklst.aspectJannotation 包下的所有方法增強。
execution(* aop.tmsklst.aspectJannotation.*.*(..))
AspectJ 注解的使用
- 在配置檔案中使用context名稱空間啟用Annotation掃描,在使用aop名稱空間開啟AspectJ切面。
或 使用配置類替換配置檔案。<beans xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- Annotation掃描 --> <context:component-scan base-package="aop.tmsklst"></context:component-scan> <!-- 開啟AspectJ生成切面 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@ComponentScan @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) public class ConfigAop { }
- 被增強類
@Component public class User { public void add() { // int i = 1/0; //制造異常 System.out.println("add......"); } }
- 建立切面類,使用@Aspect注解表示目前類是切面類,用@Order設定優先級。
@Aspect //定義一個切面 @Order(1)//在有多個切面的情況下,設定優先級 @Component public class UserProxy { //相同切入點抽取 @Pointcut(value = "execution(* aop.tmsklst.aspectJannotation.User.add(..) )") public void pointcut() { } //@Before 注解表示作為前置通知 @Before(value = "pointcut())") public void defore() { System.out.println("defore...."); } //最終通知:不管在掃描情況下都執行 @After(value = "execution(* aop.tmsklst.aspectJannotation.User.add(..))") public void after() { System.out.println("after...."); } //後置通知:在程式正常執行後執行 @AfterReturning(value = "execution(* aop.tmsklst.aspectJannotation.User.add(..))") public void afterReturning() { System.out.println("afterReturning...."); } //異常通知:有異常時執行 @AfterThrowing(value = "execution(* aop.tmsklst.aspectJannotation.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing...."); } //環繞通知 @Around(value = "execution(* aop.tmsklst.aspectJannotation.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("環繞之前...."); //被增強的方法執行 proceedingJoinPoint.proceed(); System.out.println("環繞之後...."); } }
- 建立第二個切面類,使用@Aspect注解表示目前類是切面類,用@Order設定優先級。
@Aspect //定義一個切面 @Order(2)//在有多個切面的情況下,設定優先級 @Component public class PersonProxy { @Before(value = "execution(* aop.tmsklst.aspectJannotation.User.add(..))") public void before() { System.out.println("PersonProx before...."); } }
- 測試
public void testAno1() { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); User user = context.getBean("user", User.class); user.add(); } /* 執行結果 異常結果 環繞之前.... 環繞之前.... defore.... defore.... PersonProx before.... PersonProx before.... add...... after.... 環繞之後.... afterThrowing.... after.... afterReturning.... */
AspectJ 配置檔案操作
- 被增強類
public class Person { public void add() { System.out.println("add...."); } }
- 切面類
public class PersonProxy { public void before() { System.out.println("before...."); } }
- 在配置檔案中添加aop名稱空間。
<beans xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置AOP增強 --> <aop:config> <!-- 切入點 --> <aop:pointcut id="p" expression="execution(* aop.tuoyingtao.aspectJxml.Person.add(..))"></aop:pointcut> <!-- 切面 --> <aop:aspect ref="personProxy"> <!-- 增強方法 --> <aop:before method="before" pointcut-ref="p"></aop:before> </aop:aspect> </aop:config>
Spring JDBCTemplate操作資料庫
什麼是JDBCTemplate?
它是Spring架構對JDBC的封裝,使用JDBCTemplate更友善實作對資料庫操作。
導入相關jar包
- druid-1.1.9:連結池
- mysql-connector-java-5.1.7-bin:資料庫連接配接
- spring-tx-5.2.6.RELEASE:事務處理
- spring-jdbc-5.2.6.RELEASE:spring對jdbc的封裝
JDBCTemplate使用執行個體
- jdbc.properties 配置資料庫連接配接基本資訊。
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/user_db username=root passwprd=root
- Spring 配置檔案添加context名稱空間,引入jdbc.properties配置檔案,啟用注解解析,建立JdbcTemplate對象,并注傳入連結接池。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="jdbc.properties" /> <context:component-scan base-package="aop2.jdbctemplate"/> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}" /> <property name="url" value="${url}" /> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </bean> <!-- JdbcTemplate對象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!-- 注傳入連結接池 --> <property name="dataSource" ref="druidDataSource"/> </bean> </beans>
- BookDaoImpl類實作BookDao接口,并注入JdbcTemplate對象。
@Repository public class BookDaoImpl implements BookDao { //注入JDBCTemplate @Autowired private JdbcTemplate jdbcTemplate; }
- 在BookService類中注入BookDaoImpl類。
@Service public class BookService { //注入dao @Autowired private BookDao bookDao; }
JDBCTemplate 操作資料庫(增、删、改)
- 建立Book類
public class Book { private Integer id; private String userName; private String status; ………… }
- service層
@Service public class BookService { //注入dao @Autowired private BookDao bookDao; // 添加資料 public void addBook(Book book) { bookDao.add(book); } //修改資料 public void amendBook(Book book) { bookDao.amend(book); } //删除資料 public void deleteBook(Integer id) { bookDao.delete(id); } }
- dao層
@Repository public class BookDaoImpl implements BookDao { //注入JDBCTemplate @Autowired private JdbcTemplate jdbcTemplate; //插入資料 @Override public void add(Book book) { String sql = "insert into t_book(id,userName,status) values(?,?,?)"; Object[] args = {book.getId(),book.getUserName(),book.getStatus()}; int update = jdbcTemplate.update(sql, args); System.out.println(update); } //修改資料 @Override public void amend(Book book) { String sql = "update t_book set userName = ?, status = ? where id = ?"; Object[] args = {book.getUserName(),book.getStatus(),book.getId()}; int update = jdbcTemplate.update(sql, args); System.out.println(update); } //删除資料 @Override public void delete(Integer id) { String sql = "delete from t_book where id = ?"; int update = jdbcTemplate.update(sql, id); System.out.println(update); } }
- 測試
//插入資料 public void jdbcTemplateTest() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); BookService bookService = context.getBean("bookService", BookService.class); bookService.addBook(new Book(null,"托馬斯·克裡斯特","true")); } //修改資料 public void jdbcTemplateTest2() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); BookService bookService = context.getBean("bookService", BookService.class); bookService.amendBook(new Book(1,"Tom","false")); } //删除資料 public void jdbcTemplateTest3() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); BookService bookService = context.getBean("bookService", BookService.class); bookService.deleteBook(1); }
JDBCTemplate 操作資料庫(查詢、批量操作)
- service層
@Service public class BookService { //注入dao @Autowired private BookDao bookDao; public Integer findCount() { return bookDao.countTotal(); } public Book findBook(Integer id) { return bookDao.findBookInfo(id); } public List<Book> findAll() { return bookDao.findAllList(); } public void batcAdd(List<Object[]> batchArgs) { bookDao.batchAddBook(batchArgs); } }
- dao層
@Repository public class BookDaoImpl implements BookDao { //注入JDBCTemplate @Autowired private JdbcTemplate jdbcTemplate; //總共多少條記錄 @Override public Integer countTotal() { String sql = "select count(*) from t_book"; Integer integer = jdbcTemplate.queryForObject(sql, Integer.class); return integer; } //查詢詳情 @Override public Book findBookInfo(Integer id) { String sql = "select id, userName, status from t_book where id = ?"; Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id); return book; } //查詢清單 @Override public List<Book> findAllList() { String sql = "select id,userName,status from t_book"; List<Book> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class)); return query; } //批量添加(删除、修改類似) @Override public void batchAddBook(List<Object[]> batchArgs) { String sql = "insert into t_book(id,userName,status) values(?,?,?)"; int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs); System.out.println(Arrays.toString(ints)); } }
- 測試
@Test public void jdbcTemplateTest4() { Integer count = bookService.findCount(); System.out.println(count); } @Test public void jdbcTemplateTest6() { Book book = bookService.findBook(2); System.out.println(book); } @Test public void jdbcTemplateTest7() { List<Book> all = bookService.findAll(); Iterator<Book> iterator = all.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } @Test public void jdbcTemplateTest8() { List<Object[]> list = new ArrayList<>(); Object[] o1 = {null,"name11","true"}; Object[] o2 = {null,"name22","false"}; Object[] o3 = {null,"name33","true"}; list.add(o1); list.add(o2); list.add(o3); bookService.batcAdd(list); }
Spring 事務操作
事務是邏輯上的一組操作,要麼都執行,要麼都不執行。
事務的特性(ACID)
原子性(Atomicity):原子性是指事務是一個不可分割的工作機關,事務中的操作要麼都發生,要麼都不發生。一緻性(Consistency):事務必須使資料庫從一個一緻性狀态變換到另外一個一緻性狀态。
隔離性(Isolation):事務的隔離性是指一個事務的執行不能被其他事務幹擾,即一個事務内部的操作及使用的資料對并發的其他事務是隔離的,并發執行的各個事務之間不能互相幹擾。
持久性(Durability):持久性是指一個事務一旦被送出,它對資料庫中資料的改變就是永久性的,接下來的其他操作和資料庫故障不應該對其有任何影響。
Spring事務管理API
PlatformTransactionManager 接口介紹
PlatformTransactionManager接口表示事務管理器,為各個平台如JDBC、Hibernate等都提供了對應的事務管理器,更具不同的架構提供不同的實作類。
PlatformTransactionManager 接口中定義的三個方法:
public interface PlatformTransactionManager extends TransactionManager {
//根據指定的傳播行為,傳回目前活動的事務或建立一個新事務。
TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
//送出事務
void commit(TransactionStatus var1) throws TransactionException;
//對執行的事務進行復原
void rollback(TransactionStatus var1) throws TransactionException;
}
PlatformTransactionManager 接口對應不同架構的實作類
事務 | 描述 |
---|---|
| 使用Spring JDBC或者MyBatis進行持久化資料時使用。 |
| 使用Hibernate進行資料持久化時使用。 |
| 使用JPA進行資料持久化時使用。 |
| 使用JTA實作管理事務,在一個事務跨越多個資源時使用。 |
當我們使用JDBC或Mybatis進行資料持久化操作時,xml配置操作如下:
<!-- 事務管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入資料源 -->
<property name="dataSource" ref="DruidDataSource"/>
</bean>
TransactionDefinition 接口介紹
事務管理器接口 PlatformTransactionManager 通過
getTransaction(TransactionDefinition var1)
方法來得到一個事務,這個方法裡面的參數是 TransactionDefinition類 ,這個類就定義了一些基本的事務屬性。
@Transactional 注解
@Transactional 注解定義在類上表示目前類中所有方法都添加事務。若在方法上,則表示為此方法添加事務。
propagation 事務傳播行為:多事務方法直接進行調用,這個過程中事務是如何進行管理的。
ioslation 事務隔離級别:事務有特性成為隔離性,多事務操作之間不會産生影響。不考慮隔離性産生很多問題(髒讀、不可重複讀、幻讀)
隔離級别 | 描述 |
---|---|
READ UNCOMMITTED (讀未送出資料) | 允許事務讀取未被其它事務送出更改。髒讀、不可重複讀以及幻讀的問題都會出現。 |
READ COMMITED (讀已送出資料) | 隻允許事務讀取已經被其它事務送出的變更,可以避免髒讀。但不可重複讀和幻讀問題仍然可能出現。 |
REPEATABLE READ (可重複讀) | 確定事務可以多次從一個字段中讀取相同的值。 在這個事務持續期間,禁止其他事務對這個字段進行更新,可以避免髒讀和不可重複讀。但幻讀的問題仍然存在。 |
SERIALIZABLE (串行化) | 確定事務可以從一個表中讀取相同的值。 在這個事務持續期間。禁止其他事務對該表執行插入、更新、删除操作,所有并發問題都可以避免,但性能十分低下。 |
timeout 逾時時間:事務需要在一定時間内進行送出,如果不送出進行復原。預設值是 -1(時間以秒機關計算)
readOnly 是否隻讀:讀:查詢操作,寫:添加修改删除操作。預設值 false。
rollbackFor 復原:設定出現哪些異常進行事務復原。
noRollbackFor 不復原:設定出現哪些異常不進行事務復原。
案例:
- 注解配置中添加tx命名空間
或 使用xml配置<beans xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 事務管理器 --> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入資料源 --> <property name="dataSource" ref="DruidDataSource"/> </bean> <!-- 開啟事務注解 --> <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
<!-- 事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入資料源 --> <property name="dataSource" ref="DruidDataSource"/> </bean> <!-- xml配置通知 --> <tx:advice id="txadvice"> <!-- 配置事務參數 --> <tx:attributes> <tx:method name="account*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- 配置切入點和切面 --> <aop:config> <!-- 配置切入點 --> <aop:pointcut id="pt" expression="execution(* spring.tm.service.UserService.*(..))"/> <!-- 配置切面 --> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/> </aop:config>
- service層(如果使用xml配置就需要添加@Transactional注解)
@Service @Transactional(readOnly = false,timeout = 1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ) public class UserService { @Autowired private UserDao userDaoImpl; public void accountMoney(Integer addId,Integer reduceId, BigDecimal money) { userDaoImpl.addMoney(addId,money); //模拟異常 int i = 10/0; userDaoImpl.reduceMoney(reduceId,money); } }
Spring使用配置類代替xml配置檔案
@Configuration//配置類
@ComponentScan(basePackages = "spring.tm")//元件掃描
@EnableTransactionManagement //開啟事務
public class AnnotationConfig {
//建立資料庫連結池
@Bean
public DataSource getDruidDataSource() {
try {
Properties properties = new Properties();
InputStream resourceAsStream =
ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
properties.load(resourceAsStream);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
return dataSource;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 建立JdbcTemplate對象
* @param dataSource 在IOC容器中更具類型找到DataSource對象
* @return
*/
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
/**
* 建立事務管理器
* @param dataSource 在IOC容器中更具類型找到DataSource對象
* @return
*/
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
Spring5 架構新功能
整個 Spring5 架構的代碼基于 Java8,運作時相容 JDK9,許多不建議使用的類和方法在代碼庫中已删除。
Spring5 架構日志
Spring5 已經移除 Log4jConfigListener,官方建議使用 Log4j2。
1. 導入jar包
2. 建立log4j2.xml配置檔案(名字是固定的)
<?xml version="1.0" encoding="UTF-8"?>
<!--日志級别以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration後面的status用于設定log4j2自身内部的資訊輸出,可以不設定,當設定成trace時,可以看到log4j2内部各種詳細輸出-->
<configuration status="INFO">
<!--先定義所有的appender-->
<appenders>
<!--輸出日志資訊到控制台-->
<console name="Console" target="SYSTEM_OUT">
<!--控制日志輸出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</console>
</appenders>
<!--然後定義logger,隻有定義了logger并引入的appender,appender才會生效-->
<!--root:用于指定項目的根日志,如果沒有單獨指定Logger,則會使用root作為預設的日志輸出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
Spring5 架構核心容器支援@Nullable 注解
@Nullable 注解可以使用在方法上面,屬性上面,參數上面,表示方法傳回可以為空,屬性值可以 為空,參數值可以為空
注解用在方法上面,方法傳回值可以為空。
@Nullable
String getId()
注解使用在方法參數裡面,方法參數可以為空。
注解使用在屬性上面,屬性值可以為空。
@Nullable
private String id;
Spring5 核心容器支援函數式風格 GenericApplicationContext
函數式風格建立對象,并交給Spring 進行管理。
public void genericApplicationContextTest() {
//1.建立GenericApplicationContext對象
GenericApplicationContext genericApplicationContext = new GenericApplicationContext();
//2.調用context的方法對象注冊
genericApplicationContext.refresh();
genericApplicationContext.registerBean(User.class,() -> new User());
genericApplicationContext.registerBean("myUser",User.class,() -> new User());
//3.擷取在spring注冊的對象
User user = (User) genericApplicationContext.getBean("spring.tm.pojo.User");
User user2 = (User) genericApplicationContext.getBean("myUser");
System.out.println(user);
System.out.println(user2);
}
Spring5 支援整合 JUnit5
整合 JUnit4
@RunWith(SpringJUnit4ClassRunner.class)//單元測試架構
@ContextConfiguration("classpath:ApplicationContext2.xml")//加載配置檔案
public class JTest4 {
@Autowired
private UserService userService;
@Test
public void test() {
userService.accountMoney(1001,1002,new BigDecimal(200));
}
}
整合 JUnit5
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath*:ApplicationContext2.xml")
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test() {
userService.accountMoney(1001,1002,new BigDecimal(300));
}
}
使用複合注解替代上面兩個注解完成整合。
@SpringJUnitConfig(locations = "classpath*:spring/tm/ApplicationContext2.xml")
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test() {
userService.accountMoney(1001,1002,new BigDecimal(300));
}
}