?傳送門 ==>B站遇見狂神說—Spring5教程
感謝狂神,學習視頻真的是通俗易懂???
筆記和練習只是跟著視頻整理的;有的知識點并沒有整理進來
ml
- 1.Spring概述
- 2. 控制反轉IOC
- 3.試試Spring
- 3.1 IOC創建物件的方式
- 3.2 Spring配置說明
- 3.3 DI (依賴注入)
- 3.3.1 set注入
- 3.3.2 (擴展) p命名set注入 ; c命名構造注入
- 3.4 Bean的作用域
- 3.5 自動裝配Bean
- 3.5.1 byName,byType自動裝配
- 3.5.2 使用注解實作裝配
- Spring注解開發
- 3.5.3 使用JavaConfig實作配置
- 4. 靜態代理模式
- 5. 動態代理模式
- 6.面向切面 AOP
- 方式1:使用原生的Spring API介面
- 方式 2;使用自定義 實作
- 方式3: 使用注解實作
- 7. 整合Mybatis
- 7.1Spring整合 Mybatis的方式一
- 7.2 Spring整合 Mybatis的方式二
- 8.宣告式事務
Spring 官網==>https://spring.io
Spring官方檔案==>https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html
本次使用的是Spring Web MVC
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
之后還可能用到spring jdbc
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
1.Spring概述
Spring是開源免費的輕量級的控制反轉(IOC)和面向切面(AOP)的容器框架;支持事務處理.
由7個模塊組成,

(Spring Boot) 構建一切,(Sprint Cloud)協調一切,(Spring Cloud Data Flow)連接一切
(Spring Boot)就像腳手架,可實作快速開發單個微服務;而學習它的前提是學習Spring和SpringMVC.
2. 控制反轉IOC
IOC理論推導
創建一個空的maven專案,洗掉src目錄;作為父級專案;
還是和之前一樣,先去檢查maven地址;

在pom.xml導包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!--測驗使用-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
可看到,下載結束后,出現了好幾個資源包

創建一個子級maven工程;


就用一個基礎的專案構建來說吧;
持久層介面UserDao;
public interface UserDao {
//查詢用戶;
void findUser();
}
持久層實作類UserDaoImpl;
public class UserDaoImpl implements UserDao{
public void findUser() {
System.out.println("默認呼叫的方法");
}
}
業務層介面UserService;
public interface UserService {
//查詢用戶;
void findUser();
}
業務層介面的實作類UserServiceImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao=new UserDaoImpl();
public void findUser() {
//在業務層呼叫持久層的方法;
userDao.findUser();
}
}
測驗呼叫
@Test
public void test(){
UserService userService=new UserServiceImpl();
userService.findUser();
}
這時輸出

而如果說,這時候又來需求了,持久層新增了一個實作類UserMySqlImpl
public class UserMySqlImpl implements UserDao{
public void findUser() {
System.out.println("MySql的方法");
}
}
那么如果說想要拿到這個需求的實作,就要在業務層的實作類UserServiceImpl中;去更改持久層的實作類改為UserMySqlImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao=new UserMySqlImpl();
public void findUser() {
//在業務層呼叫持久層的方法;
userDao.findUser();
}
}
測驗呼叫,即可

如果說又有一個新的需求,創建了一個新的持久層實作類UserOracleImpl;
public class UserOracleImpl implements UserDao{
public void findUser() {
System.out.println("Oracle方式");
}
}
那么就得去業務層UserServiceImpl中更改;
public class UserServiceImpl implements UserService{
private UserDao userDao=new UserOracleImpl();
public void findUser() {
//在業務層呼叫持久層的方法;
userDao.findUser();
}
}
然后測驗呼叫

在之前的業務中,用戶的需求可能會影響原來的代碼,就要根據用戶的需求更改代碼.
要是在UserServiceImpl中用set實作動態修改實作類;
public class UserServiceImpl implements UserService{
private UserDao userDao;
//控制反轉的原型,在業務層提供動態的用戶需求方法;
//用set實作動態注入值;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void findUser() {
//在業務層呼叫持久層的方法;
userDao.findUser();
}
}
在測驗執行的方法內,只需要呼叫setUserDao 方法,去更改里面的持久層實作類即可
public class MyTest {
@Test
public void test() {
UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDao(new UserMySqlImpl());
userService.findUser();
}
}

每使用set設定之前,程式是需要主動創建物件,控制權在開發者手中,使用了set注入后,程式不再具有主動性,變為被動的接受物件.
開發者不必管理物件的創建,系統耦合性降低,專注于業務的實作.
即控制反轉 IOC 的原型.
IOC的本質
控制反轉IOC 設計思想,而 DI(依賴注入)是實作IOC的一種方法,
在沒有使用IOC的程式,作為面向物件編程的語言,物件的創建和物件間的依賴關系是必須硬編碼在程式中,物件的創建由程式自己控制,
控制反轉后將物件的創建轉移到第三方, 獲取依賴物件的方式反轉.
3.試試Spring
ok新建一個物體類User;
public class User {
private String name;
public User(){
System.out.println("User類的無參構造");
}
public User(String name){
this.name=name;
System.out.println("User類的有參構造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
在resources目錄下創建beans.xml檔案
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--使用spring 創建物件;就是 bean-->
<!--這時的id就是變數名;class就是new的物件-->
<!--property: 可以為物件的屬性設定值-->
<bean id="user" class="com.lzq.pojo.User">
<property name="name" value="xiaozhi"/>
</bean>
</beans>
測驗
public class Test01 {
public static void main(String[] args) {
//獲取Spring得背景關系物件;
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//由于創建物件就是 Spring 中的bean; 獲取bean即可獲取物件;
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
}
輸出:
User類的無參構造
User{name='xiaozhi'}
可以看出,從始至終沒有使用new構造方法進行創建User類的物件;
但是實際上在xml組態檔中,已經被Spring創建物件了;且設定了屬性name的值;
程式本身不去創建物件,作為了被動的接收物件.
此程序就是控制反轉;IOC; 由Spring 創建 管理 裝配.

這里使用了set方法來進行注入的;若洗掉set方法;就無法得到屬性name.
設定value是針對于基本資料;

設定物體類顯示小葉子圖示;

再看看剛才的UserDao,實際上,根據需要就可以直接在組態檔修改即可.
ref: 會參考 在Spring中設定創建的物件

3.1 IOC創建物件的方式
剛在在測執行時;注意到,輸出有呼叫到無參構造方法;

那么如果將User類的無參構造方法去掉;即為User類寫個顯示的有參構造,默認隱式的無參構造就沒有了;

再次執行,出現例外提示;提示初始化例外;

在xml組態檔中也有提示

IOC創建物件時默認使用無參構造方法,
那么如果說想用有參構造方法呢,有三種方式;
方式1:使用index(下標) 指定有參構造方法的引數是第幾個; value 為引數賦值 ;
在beans.xml 檔案的bean標簽下的constructor-arg標簽中配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--方式1:使用 index(下標) 指定有參構造方法的引數是第幾個; value 為引數賦值 -->
<bean id="user" class="com.lzq.pojo.User">
<constructor-arg index="0" value="小智從零開始學Java"/>
</bean>
</beans>
執行,是呼叫了有參構造方法的;且為引數name賦值也取到了.

方式2:使用type 屬性 顯式的指定建構式引數的型別;value為引數賦值.
注意: 基本型別可直接寫;參考型別要注明類的地址;
例如官方檔案中是這么寫的.
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="2001"/>
<constructor-arg type="java.lang.String" value="Zara"/>
</bean>
ok,用方式2調有參構造方法,為user類創建物件.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--方式2: 使用 type屬性 顯式的指定建構式引數的型別; value 為引數賦值-->
<bean id="user" class="com.lzq.pojo.User">
<constructor-arg type="java.lang.String" value="方式二"/>
</bean>
</beans>
執行,使用成功;

方式 3: 直接使用 引數名name設定 ; value 引數賦值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--方式3: 使用引數名name; -->
<bean id="user" class="com.lzq.pojo.User" >
<constructor-arg name="name" value="方式3"/>
</bean>
</beans>
執行,使用成功;

還有就是,在pojo包下,再創建一個Student類;
public class Student {
private int age;
public Student() {
System.out.println("Student類的無參構造方法");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
注意;僅僅是在beans.xml為他用無參構造方法創建了物件;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--User類-->
<!--方式3: 使用引數名name; -->
<bean id="user" class="com.lzq.pojo.User" >
<constructor-arg name="name" value="方式3"/>
</bean>
<!--Student類-->
<bean id="student" class="com.lzq.pojo.Student">
</bean>
</beans>
誒,這里還是執行之前測驗User類的代碼;
public class Test01 {
public static void main(String[] args) {
//獲取Spring得背景關系物件;
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//由于創建物件就是 Spring 中的bean; 獲取bean即可獲取物件;
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
}
但是輸出結果時,發現Student類創建物件時呼叫的無參構造方法也有記錄;

實際上, Spring容器就像是一個婚介網站
在組態檔加載的時候,容器中管理的物件就已經初始化了.
3.2 Spring配置說明
別名
alias
比如說;為User類創建物件時的變數id user 取個別名u
<alias name="user" alias="u"/>

那么,在執行測驗時,使用別名也能獲取到這個User類的物件;

Bean的配置
細細看看<bean>標簽內的幾個配置標簽
id 就是 bean的唯一識別符號 ,也就相當于物件名;
class 即 bean 對應的全限定名==> 包名 +型別;
name 即 別名 ;且 可以寫多個別名,用逗號或者分號隔開即可
<bean id="user" class="com.lzq.pojo.User" name="u1,u2;u3">
</bean>
import標簽
一般在團隊開發中使用;可以將多個組態檔匯入合并為一個
<import resource="beans.xml"/>
<import resource="otherbeans.xml"/>
<import resource="otherbeans2.xml"/>
3.3 DI (依賴注入)
第一個就是建構式注入,也就是剛才在創建物件時修改呼叫有參無參構造方法時;就使用過了.
第二個就是set注入,這個很重要
依賴: = = > bean物件的創建依賴于Spring容器
注入: = => bean物件中的所有屬性,由容器注入.
3.3.1 set注入
用一個復雜的案例看看這個set注入吧
新建一個Adderss類
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
新建一個Student類
public class Student {
private String name;
//這里的Address是自定義的類;
private Address address;
private String[] books;
private List<String> hobby;
private Map<String,String> card;
private Set<String> games;
private String friend;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getFriend() {
return friend;
}
public void setFriend(String friend) {
this.friend = friend;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.toString() +
", books=" + Arrays.toString(books) +
", hobby=" + hobby +
", card=" + card +
", games=" + games +
", friend='" + friend + '\'' +
", info=" + info +
'}';
}
}
在resources 目錄下創建applicationContext.xml;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--為Address類創建物件-->
<bean id="address" class="com.xiaozhi.pojo.Address">
<property name="address" value="陜西"/>
</bean>
<!--為Student類創建物件-->
<bean id="student" class="com.xiaozhi.pojo.Student">
<property name="name" value="小智"/>
<!--自定義參考型別 -->
<property name="address" ref="address"/>
<!--陣列型別的 books-->
<property name="books">
<array>
<value>演算法圖解</value>
<value>大話資料結構</value>
<value>劍指Offer</value>
<value>java核心技術</value>
</array>
</property>
<!--list型別的 hobby-->
<property name="hobby">
<list>
<value>吃飯</value>
<value>睡覺</value>
<value>學習</value>
<value>敲代碼</value>
</list>
</property>
<!--map型別的 card-->
<property name="card">
<map>
<entry key="電卡" value="123456789"/>
<entry key="水卡" value="223456789"/>
<entry key="燃氣卡" value="000000000"/>
</map>
</property>
<!--set型別的 games-->
<property name="games">
<set>
<value>Fortnite</value>
<value>OverWatch</value>
</set>
</property>
<!--null型別的 friend-->
<property name="friend" >
<null/>
</property>
<!--Properties型別的 info-->
<property name="info">
<props>
<prop key="性別">男</prop>
<prop key="電話">123654</prop>
</props>
</property>
</bean>
</beans>
執行測驗輸出,不同型別的屬性賦值均取到;
public class Test03 {
public static void main(String[] args) {
//讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取Student類的 bean;
Student student = (Student) applicationContext.getBean("student");
System.out.println(student.toString());
}
}

3.3.2 (擴展) p命名set注入 ; c命名構造注入
p: 命名空間注入,可直接注入屬性和值
注意在beans標簽的頭部需要匯入這個xml約束
xmlns:p="http://www.springframework.org/schema/p"
物體類User
public class User {
private String name;
private int age;
public User() {
System.out.println("無參構造方法");
}
public User(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有參構造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
組態檔
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--創建User類的物件 p: 命名空間注入,可直接注入屬性和值-->
<bean id="user" class="com.xiaozhi.pojo.User" p:name="小智" p:age="21"/>
</beans>
getBean(“物件”,型別)
若在第二個引數處指明使用的型別,就不用強制轉換型別了;
public class Test04 {
public static void main(String[] args) {
//讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
//獲取User類的 bean;
User user = applicationContext.getBean("user",User.class);
System.out.println(user.toString());
}
}
輸出
無參構造方法
User{name='小智', age=21}
c: 命名空間注入,可直接注入構造方法的引數與值
注意在beans標簽的頭部需要匯入這個xml約束
xmlns:c="http://www.springframework.org/schema/c"
在組態檔中使用
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--可直接 使用構造方法的 引數-->
<bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21"/>
<!--也可使用 構造方法的 引數的索引-->
<bean id="user2" class="com.xiaozhi.pojo.User" c:_0="阿杰" c:_1="21"/>
</beans>
測驗執行
public class Test04 {
public static void main(String[] args) {
//讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
//獲取User類的 bean;
User user1 = applicationContext.getBean("user1",User.class);
User user2 = applicationContext.getBean("user2",User.class);
System.out.println(user1.toString());
System.out.println(user2.toString());
}
}
輸出:
有參構造方法
有參構造方法
User{name='小智', age=21}
User{name='阿杰', age=21}
3.4 Bean的作用域
singleton(默認值) 單例模式:在 Spring 中只存在一個 bean 實體
即使不寫也是默認存在的.
<bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21" scope="singleton"/>

比如說,我在執行這邊分別獲取兩次bean;兩次取到到的bean是同一個

prototype:原型模式 getBean()的時候都會 new Bean()
<bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21" scope="prototype"/>

還是剛才的執行例子;兩次取到的物件不一致了.

request:每次 http 請求都會創建一個 bean, 僅用于 WebApplicationContext環境
session:同一個 http session 共享一個 Bean, 不同 Session 使用不同的 Bean, 使用環境同上
3.5 自動裝配Bean
自動裝配是Spring為滿足bean依賴的一種方式;由Spring在背景關系中自動尋找,自動裝配bean.
有三種裝配方式;
在xml顯示的手動裝配;
在java中顯示地裝配
隱式的自動裝配
首先設計幾個類
Cat類
public class Cat {
public void shoot(){
System.out.println("阿貓說喵喵");
}
}
Dog類
public class Dog {
public void shoot(){
System.out.println("阿狗說汪汪");
}
}
Person類
public class Person {
private Cat cat;
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
配置applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--配置Cat類和Dog類的bean-->
<bean id="cat" class="com.xiaozhi.pojo.Cat"/>
<bean id="dog" class="com.xiaozhi.pojo.Dog"/>
<!--配置Person類的bean-->
<bean id="person" class="com.xiaozhi.pojo.Person">
<property name="name" value="小智"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
</beans>
測驗呼叫
public class Test04 {
public static void main(String[] args) {
//讀取applicationContext.xml組態檔;獲取Spring的背景關系物件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取User類的 bean;
Person person = applicationContext.getBean("person", Person.class);
person.getCat().shoot();
person.getDog().shoot();
}
}
輸出
阿貓說喵喵
阿狗說汪汪
3.5.1 byName,byType自動裝配
使用byName時,需要保證所有的bean 的id是唯一的,且bean是需要與自動注入的屬性的set方法一致;
使用byType時,需要保證所有bean的class唯一; 且bean要和自動注入的屬性的型別保持一致.
先看看byName
需要在applicationContext.xml中更改配置Person類的bean;
直接用autowire="byName" 屬性
自動在容器的背景關系中查找,與自己物件的set方法后的值對應的bean.
<!--配置Cat類和Dog類的bean-->
<bean id="cat" class="com.xiaozhi.pojo.Cat"/>
<bean id="dog" class="com.xiaozhi.pojo.Dog"/>
<!--配置Person類的bean-->
<bean id="person" class="com.xiaozhi.pojo.Person" autowire="byName">
<property name="name" value="小智"/>
</bean>

在執行后,依然可輸出

但是,配置Cat類和Dog類的bean時,修改id;
<!--配置Cat類和Dog類的bean-->
<bean id="cat456" class="com.xiaozhi.pojo.Cat"/>
<bean id="dog666" class="com.xiaozhi.pojo.Dog"/>
<!--配置Person類的bean-->
<bean id="person" class="com.xiaozhi.pojo.Person" autowire="byName">
<property name="name" value="小智"/>
</bean>
誒,執行時就出現例外了

這個說明什么呢;
只要配置的類的bean的id ; 和這個想要自動裝配bean 的類中的set方法名字后面的名稱一致,它就能自動裝配bean了.
再看看 byType
和byName設定時差不多
需要在applicationContext.xml中更改配置Person類的bean;
設定autowire="byType"
自動在容器的背景關系中查找;對應類的屬性中的型別相同的bean
<!--配置Cat類和Dog類的bean-->
<bean id="cat456" class="com.xiaozhi.pojo.Cat"/>
<bean id="dog666" class="com.xiaozhi.pojo.Dog"/>
<!--配置Person類的bean-->
<!--byType 對應類的屬性中的型別相同的bean-->
<bean id="person" class="com.xiaozhi.pojo.Person" autowire="byType">
<property name="name" value="小智"/>
</bean>
雖然這里的id是和set方法后面的名稱不一致的;但是仍然可以執行成功;

但是有個問題啊;你這邊一旦創建多個bean;就不行了;
byType需要保證這里的型別要是唯一的

但是,用了byType后,你甚至可以把裝配的bean的id給省略了

3.5.2 使用注解實作裝配
需要匯入相關xml配置約束;配置注解的支持
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
配置xml檔案
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="cat" class="com.xiaozhi.pojo.Cat"/>
<bean id="dog" class="com.xiaozhi.pojo.Dog"/>
<bean id="person" class="com.xiaozhi.pojo.Person"/>
<!--注意開啟注解支持-->
<context:annotation-config/>
</beans>
直接在Person類的屬性cat和dog處使用注解即可;@Autowired
@Autowired先執行byType
不過還是建議在setter方法上使用注解.

同樣地裝配成功了

擴展
(1) @Nullable 注解,在欄位處標記后,該欄位可以為null
(2) 仔細看看注解==@Autowired==;注意到后面是可以寫引數required (默認為true)的;
要是顯示地定義了 @Autowired(required = false) ,那么說明此欄位的物件可以為null
package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
(3) 如果xml檔案中同一個物件被多個bean使用;使用@Autowired無法按型別找到;’
這時就需要使用注解 @Qualifier(value=" ") 配合注解@Autowired;指定唯一的bean物件注入

(4) 使用注解 @Resource ,java的原生注解; 它是根據class來找的.
@Resource先執行byName
如果xml檔案中同一個物件被多個bean使用;@Resource還可以加引數 @Resource(name=" ")

Spring注解開發
spring后,先保證匯入 aop的包
且注解有約束和支持
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--指定掃描的包-->
<context:component-scan base-package="com.xiaozhi.pojo"/>
<!--注意開啟注解支持-->
<context:annotation-config/>
</beans>
bean的注入
在類上使用注解 @Component 可以代替xml檔案中的配置bean
比如說這里使用注解就相當于
<bean id="user" class="com.xiaozhi.pojo.User"/>

屬性的注入
在屬性的欄位上使用注解 @Value(“賦值”) 即可
比如說這里使用了注解就相當于
<bean id="user" class="com.xiaozhi.pojo.User">
<property name="name" value="小智"/>
<property name="age" value="21"/>
</bean>

實際上; 注解 @Component 還有衍生的幾個注解;
一般在dao層使用注解 @Repository ; 表示倉庫;
在service層使用注解 @Service ;
在controller 層 使用 注解 @Controller
對于作用域還可使用注解 @Scope ;里面可傳參value指定所用域范圍.
3.5.3 使用JavaConfig實作配置
這部分不使用spring的組態檔;
之前僅作為spring的子專案,但在spring4之后是作為核心功能.
在一個類上使用注解 @Configuration ;該注解的底層已使用了注解@Component; 他也被spring接管了;表示該類為一個配置類
使用注解@ComponentScan("com.xiaozhi.pojo")配置包掃描;配置包掃描后,其實默認的id就是類名的小寫了;
注解 @Bean 就相當于組態檔的bean標簽;方法名相當于id;方法的回傳值相當于class 屬性;
注解 @Import(“其他組態檔類”) 可用來合并組態檔.
注意獲取物件時,要先用AnnotationConfigApplicationContext獲取背景關系物件;
物體類User
//注解表名該類被spring接管;注入bean;
@Component
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
//該注解為屬性賦值;
@Value("小智")
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
@Value("21")
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
配置類UserConfig
//該注解的底層已使用了注解@Component; 他也被spring接管了;
//表示該類為一個配置類
@Configuration
//配置包掃描;
@ComponentScan("com.xiaozhi.pojo")
public class UserConfig {
//配置bean;
//方法名相當于之前組態檔的bean標簽的id 屬性
//方法的回傳值相當于class 屬性;
@Bean
public User getUser(){
return new User();
}
}
執行;
public class Test06 {
public static void main(String[] args) {
//用注解的方式獲取的背景關系物件
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserConfig.class);
//獲取物件;
User user = applicationContext.getBean("getUser", User.class);
System.out.println(user);
}
}
可輸出
User{name='小智', age=21}
4. 靜態代理模式
代碼模式原型

關于靜態代理
抽象角色 = => 介面或 抽象類
真實角色 = => 被代理的角色
代理角色 = => 代理真實角色, 代理真實角色后,會做出附屬操作
客戶 = => 訪問代理物件
(1)可以使真實角色的操作簡單;不用去關注公共業務;而公共業務交給代理角色;實作了業務的分工;公共業務發生擴展時,方便集中管理.
(2)缺點: 一個真實角色就要產生一個代理角色;代碼量翻倍;開發效率會變低.
第一個例子;面向中介去租房;
租房介面
//租房
public interface Rent {
public void rent();
}
房東物體類
//房東
public class Host implements Rent{
public void rent() {
System.out.println("房東出租房子");
}
}
代理中介
//代理中介
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent() {
seeHouse();
host.rent();
contract();
fee();
}
//看房子;
public void seeHouse(){
System.out.println("由中介帶著看房");
}
//收費;
public void fee(){
System.out.println("收中介費用");
}
//簽合同
public void contract(){
System.out.println("和中介簽合同");
}
}
租房的客戶
//租房的人 =,我
public class Me {
public static void main(String[] args) {
Host host=new Host();
Proxy proxy = new Proxy(host);
//直接面向代理中介;
proxy.rent();
}
}
直接執行客戶租房
由中介帶著看房
房東出租房子
和中介簽合同
收中介費用

例子2:
比如說原有一個抽象業務介面
UserService
//抽象的業務;
public interface UserService {
void addUser();
void deleteUser();
void updateUser();
void findUser();
}
有他的實作類UserServiceImpl
//真實物件;
public class UserServiceImpl implements UserService{
public void addUser() {
System.out.println("添加用戶");
}
public void deleteUser() {
System.out.println("洗掉用戶");
}
public void updateUser() {
System.out.println("更新用戶");
}
public void findUser() {
System.out.println("查詢用戶");
}
}
業務已經跑起來了,但是需要一個額外的擴展功能;這時就需要一個代理類;
UserServiceProxy
//代理人; 可擴展功能;并不影響原來的業務功能;
public class UserServiceProxy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void addUser() {
log("add添加");
userService.addUser();
}
public void deleteUser() {
log("delete洗掉");
userService.deleteUser();
}
public void updateUser() {
log("update更新");
userService.updateUser();
}
public void findUser() {
log("find查詢");
userService.findUser();
}
//模擬使用日志;
public void log(String str){
System.out.println("[模擬日志]=>使用的是"+str+"方法");
}
}
那么用戶在實作時,只要走代理類的功能;既保證了原有的業務功能,也有新的擴展功能;
public class Me {
public static void main(String[] args) {
UserServiceImpl userService=new UserServiceImpl();
//使用代理角色;
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setUserService(userService);
userServiceProxy.addUser();
userServiceProxy.deleteUser();
userServiceProxy.updateUser();
userServiceProxy.findUser();
}
}
輸出
[模擬日志]=>使用的是add添加方法
添加用戶
[模擬日志]=>使用的是delete洗掉方法
洗掉用戶
[模擬日志]=>使用的是update更新方法
更新用戶
[模擬日志]=>使用的是find查詢方法
查詢用戶
5. 動態代理模式
代理類是動態生成的,
基于介面是 -->JDK動態代理 ;
基于類–> cglib
java的位元組碼實作時–>javasist
動態 代理介面,對應一類業務.
java.lang.reflect
Interface InvocationHandler
是由代理實體的呼叫處理程式實作的介面 ,
其中有一個invoke方法;
Object
invoke(Object proxy, 方法 method, Object[ ] args)
處理代理實體上的方法呼叫并回傳結果,

java.lang.reflect
Class Proxy
Proxy提供了創建動態代理類和實體的靜態方法,它也是由這些方法創建的所有動態代理類的超類,

為某個介面創建代理Foo :
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
newInstance(handler); 或更簡單地:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);

案例;
還是剛才的userservice,userimpl案例;
但是代理類動態生成
//動態生成代理類;
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的介面;
private Object object;
public void setObject(Object object){
this.object=object;
}
//生成代理類;
public Object findProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
//處理代理實體,回傳結果;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
//動態代理本質,用反射實作;
Object res=method.invoke(object,args);
return res;
}
//模擬日志的方法;
public void log(String str){
System.out.println("[模擬日志]=>使用的是"+str+"方法");
}
}
在用戶呼叫時;
public class Me {
public static void main(String[] args) {
//真實的角色; UserServiceImpl
UserServiceImpl userService=new UserServiceImpl();
//并不存在的代理角色;
ProxyInvocationHandler pI=new ProxyInvocationHandler();
//設定需要代理的物件;
pI.setObject(userService);
//動態得到代理類;
UserService proxy = (UserService) pI.findProxy();
proxy.addUser();
proxy.findUser();
proxy.deleteUser();
proxy.updateUser();
}
}
輸出
[模擬日志]=>使用的是addUser方法
添加用戶
[模擬日志]=>使用的是findUser方法
查詢用戶
[模擬日志]=>使用的是deleteUser方法
洗掉用戶
[模擬日志]=>使用的是updateUser方法
更新用戶
6.面向切面 AOP
AOP (Aspect Oriented Programming)意為:面向切面編程,通過預編譯方式和運行期動態代理實作程式功能的統一維護的一種技術,AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的重要內容,是函式式編程的一種衍生范型,利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率,


使用spring實作AOP,先用maven導包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式1:使用原生的Spring API介面
創建UserService介面
//抽象的業務;
public interface UserService {
void addUser();
void deleteUser();
void updateUser();
void findUser();
}
實作類UserServiceImpl
//真實物件;
public class UserServiceImpl implements UserService{
public void addUser() {
System.out.println("添加用戶");
}
public void deleteUser() {
System.out.println("洗掉用戶");
}
public void updateUser() {
System.out.println("更新用戶");
}
public void findUser() {
System.out.println("查詢用戶");
}
}
模擬前置日志BeforeLog
//模擬前置日志;
public class BeforeLog implements MethodBeforeAdvice {
/**
*
* @param method 要執行的目標物件方法;
* @param objects 引數
* @param target 目標物件
* @throws Throwable
*/
public void before(Method method, Object[] objects, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被執行");
}
}
模擬后置日志
//模擬后置日志;
public class AfterLog implements AfterReturningAdvice {
/**
*
* @param returnValue 回傳值
* @param method 要執行的目標物件方法;
* @param objects 引數
* @param target 目標物件
* @throws Throwable
*/
public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
System.out.println(method.getName()+"執行后,回傳"+returnValue);
}
}
在applicationContext.xml中配置
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注冊bean-->
<bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
<bean id="beforeLog" class="com.xiaozhi.log.BeforeLog"/>
<bean id="afterLog" class="com.xiaozhi.log.AfterLog"/>
<!--方式1 原生api介面-->
<!--配置aop-->
<aop:config>
<!--切入點 要執行的位置 execution(回傳值 類名 方法名)
(..)兩個點代表可以有任意個引數 -->
<aop:pointcut id="point" expression="execution(* com.xiaozhi.service.UserServiceImpl.*(..))"/>
<!--執行環繞增加-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="point"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
</aop:config>
</beans>
執行輸出
public class Test08 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean;
//動態代理的是介面;
UserService userService = context.getBean("userServiceImpl", UserService.class);
//呼叫方法;
userService.addUser();
userService.deleteUser();
userService.findUser();
userService.updateUser();
}
}
輸出
com.xiaozhi.service.UserServiceImpl的addUser方法被執行
添加用戶
addUser執行后,回傳null
com.xiaozhi.service.UserServiceImpl的deleteUser方法被執行
洗掉用戶
deleteUser執行后,回傳null
com.xiaozhi.service.UserServiceImpl的findUser方法被執行
查詢用戶
findUser執行后,回傳null
com.xiaozhi.service.UserServiceImpl的updateUser方法被執行
更新用戶
updateUser執行后,回傳null
方式 2;使用自定義 實作
不用去實作介面,直接自定義類MyLog
public class MyLog {
public void beforeLog(){
System.out.println("========模擬執行前置========");
}
public void afterLog(){
System.out.println("========模擬執行后置========");
}
}
在applicationContext.xml中配置
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注冊bean-->
<bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
<bean id="myLog" class="com.xiaozhi.mydiy.MyLog"/>
<!--方式2;使用自定義的類-->
<!--配置aop-->
<aop:config>
<!--使用自定義的切面-->
<aop:aspect ref="myLog">
<!--配置切入點-->
<aop:pointcut id="point" expression="execution(* com.xiaozhi.service.UserServiceImpl.*(..))"/>
<!--配置方法-->
<aop:before method="beforeLog" pointcut-ref="point"/>
<aop:after method="afterLog" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
測驗執行;同樣可執行
========模擬執行前置========
添加用戶
========模擬執行后置========
========模擬執行前置========
洗掉用戶
========模擬執行后置========
========模擬執行前置========
查詢用戶
========模擬執行后置========
========模擬執行前置========
更新用戶
========模擬執行后置========
方式3: 使用注解實作
自定義的類,用注解標注為切面
//使用注解實作;
//@Aspect 標注該類是個切面;
@Aspect
public class MyAnnotation {
//注意使用的是 import org.aspectj.lang.annotation.Before;包下的
@Before("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
public void beforeLog(){
System.out.println("========注解方式模擬執行前置========");
}
//import org.aspectj.lang.annotation.After;
@After("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
public void afterLog(){
System.out.println("========注解方式模擬執行后置========");
}
//在環繞增強時,可給定引數,表示獲取處理切入的點
@Around("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("在環繞之前");
Signature signature = pjp.getSignature();
System.out.println("獲取資訊=>"+signature);
Object proceed = pjp.proceed();
System.out.println("執行方法=>"+proceed);
System.out.println("環繞后");
}
}
在組態檔中,只需要加注解支持即可;
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--方式三 使用注解-->
<!--注冊bean-->
<bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
<bean id="myAnnotation" class="com.xiaozhi.annotation.MyAnnotation"/>
<!--開啟注解支持-->
<aop:aspectj-autoproxy/>
</beans>
執行也可實作
在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.addUser()
========注解方式模擬執行前置========
添加用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后
在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.deleteUser()
========注解方式模擬執行前置========
洗掉用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后
在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.findUser()
========注解方式模擬執行前置========
查詢用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后
在環繞之前
獲取資訊=>void com.xiaozhi.service.UserService.updateUser()
========注解方式模擬執行前置========
更新用戶
========注解方式模擬執行后置========
執行方法=>null
環繞后
7. 整合Mybatis
官方檔案mybatis-spring整合檔案
https://mybatis.org/spring/zh/index.html
需要用到的包
<dependencies>
<!--測驗包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--資料庫驅動連接-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!-- spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--spring -jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--aop-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!--mybatis-spring整合-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
</dependencies>
先回顧一下Mybatis;

注意需要在pom.xml組態檔中配置資源指向地址
<!--為防止資源匯出失敗;在build中需要配置resources-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
創建工具類MybatisUtils;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory=null;
//在呼叫工具類時就執行;
static {
try {
//獲取SqlSessionFactory物件;
//獲得組態檔;
String resource = "mybatis-config.xml";
//使用流讀取資源;
InputStream inputStream = Resources.getResourceAsStream(resource);
//加載資源流;
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//從 SqlSessionFactory 中獲取 SqlSession;
public static SqlSession getSqlSession(){
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
}
物體類User
//物體類User;
//使用lombok插件的注解;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
持久層介面UserMapper
public interface UserMapper {
//查詢方法;
public List<User> findUser();
}
持久層組態檔UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--這里mapper的空間對應創建的持久層介面;-->
<mapper namespace="com.xiaozhi.dao.UserMapper">
<select id="findUser" resultType="user">
select * from user;
</select>
</mapper>
核心組態檔mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心組態檔-->
<configuration>
<!--引入外部組態檔-->
<properties resource="db.properties"/>
<!--設定標準日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--使用包掃描的方式 ;物體類的別名默認為首字母小寫的類名-->
<typeAliases>
<package name="com.xiaozhi.pojo"/>
</typeAliases>
<!--environments:配置的環境,可以配置多個-->
<environments default="development">
<environment id="development">
<!--transactionManager:事務管理;這里默認使用JDBC-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--加載連接資料庫的重要欄位屬性-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--系結介面-->
<mappers>
<mapper resource="com/xiaozhi/dao/UserMapper.xml"/>
</mappers>
</configuration>
與資料庫互動的屬性檔案db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username=root
password=123456
測驗執行搭建環境
public class Test09 {
@Test
public void testFindUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//getmapper;
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> allUser = userMapper.findUser();
//遍歷結果;
for (User user : allUser) {
System.out.println(user);
}
//關閉sqlSession;
sqlSession.close();
}
}
測驗成功;

7.1Spring整合 Mybatis的方式一
新建UserMapper介面的實作類UserMapperImpl
public class UserMapperImpl implements UserMapper{
//操作是用sqlSession執行的;
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> findUser() {
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
return userMapper.findUser();
}
}
直接新建spring-dao.xml組態檔
撰寫資料源配置;sqlSessionFactory配置;SqlSessionTemplate配置;將實作類UserMapperImpl的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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--使用Spring的資料源替換mybatis-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSessionFactory配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--系結Mybatis 組態檔-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/xiaozhi/dao/UserMapper.xml"/>
<property name="typeAliases" value="com.xiaozhi.pojo.User"/>
</bean>
<!-- SqlSessionTemplate 即使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!--將實作類的bean注冊進來-->
<bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
這么一來,工具類MybatisUtils可直接省略;
且Mybatis的核心組態檔mybatis-config.xml也不用去寫太多的配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心組態檔-->
<configuration>
<!--設定標準日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
測驗執行
//整合Mybatis后;
@Test
public void testFindUser2(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
//獲取bean
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> user = userMapper.findUser();
for (User user1 : user) {
System.out.println(user1);
}
}
輸出

7.2 Spring整合 Mybatis的方式二
在寫UserMapper介面的實作類UserMapperImpl時,可繼承一個類SqlSessionDaoSupport;用來提供 SqlSession ;呼叫 getSqlSession()方法即可得到SqlSessionTemplate
省略了手動注入SqlSession
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> findUser() {
SqlSession sqlSession = getSqlSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
return userMapper.findUser();
}
}
且在配置bean時,用ref參考指向 賦值即可
<bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
執行測驗,查詢成功

8.宣告式事務

在UserMapper介面再添加幾個方法
public interface UserMapper {
//查詢方法;
public List<User> findUser();
//添加用戶
public void addUser(User user);
//洗掉用戶
public void deleteUser(int id);
}
在UserMapper.xml中撰寫sql陳述句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--這里mapper的空間對應創建的持久層介面;-->
<mapper namespace="com.xiaozhi.dao.UserMapper">
<!--查詢用戶-->
<select id="findUser" resultType="user">
select * from user;
</select>
<!--添加用戶-->
<insert id="addUser" parameterType="user">
insert into user values (#{id},#{name},#{password});
</insert>
<!--洗掉用戶-->
<delete id="deleteUser" parameterType="_int">
delete from user where id=#{id}
</delete>
</mapper>
UserMapper介面的實作類UserMapperImpl
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
public List<User> findUser() {
UserMapper userMapper=getSqlSession().getMapper(UserMapper.class);
User user=new User(16,"石榴號","dsaasd");
//添加用戶;
userMapper.addUser(user);
//洗掉用戶;
userMapper.deleteUser(16);
return userMapper.findUser();
}
public void addUser(User user) {
getSqlSession().getMapper(UserMapper.class);
}
public void deleteUser(int id) {
getSqlSession().getMapper(UserMapper.class);
}
}
Mybatis的核心組態檔mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心組態檔-->
<configuration>
<!--設定標準日志-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
sping-dao.xml組態檔;
撰寫資料源配置;sqlSessionFactory配置;SqlSessionTemplate配置;配置事務;
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--使用Spring的資料源替換mybatis-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- sqlSessionFactory配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--系結Mybatis 組態檔-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/xiaozhi/dao/UserMapper.xml"/>
<property name="typeAliases" value="com.xiaozhi.pojo.User"/>
</bean>
<!-- SqlSessionTemplate 即使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!--配置宣告事務-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--事務置入-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--為方法配置事務-->
<!--配置事務的特性;默認為 propagation="REQUIRED"-->
<tx:attributes>
<tx:method name="findUser" propagation="REQUIRED"/>
<tx:method name="addUser" propagation="REQUIRED"/>
<tx:method name="deleteUser" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事務切入-->
<aop:config>
<aop:pointcut id="point" expression="execution(* com.xiaozhi.dao.*.*(..))"/>
<aop:advisor pointcut-ref="point" advice-ref="txAdvice"/>
</aop:config>
</beans>
還可以用一個spring容器的xml檔案來合并其他的組態檔
applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--將pring-dao.xml 的配置合并過來-->
<import resource="spring-dao.xml" />
<!--將持久層的實作類的bean注冊進來-->
<bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
測驗執行
public class Test10 {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲取bean
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> user = userMapper.findUser();
for (User user1 : user) {
System.out.println(user1);
}
}
}
一旦某個執行出現錯誤;不會將事務提交.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/301743.html
標籤:java
