一申钩、Spring簡介
1只泼、簡介
2002年遇汞,首次推出Spring框架的雛形:interface21框架
Spring框架是以interface21框架為基礎昼丑,經過重新設計呻逆、不斷豐富內涵,于2004年3月24日發(fā)布了1.0正式版
Spring理念:使現有技術更加容易使用菩帝,整合了現有的技術框架
SSH:Struct2 + Spring + Hibernate
SSM:SpringMVC + Spring + Mybatis
Maven依賴
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
2咖城、優(yōu)點
- Spring是一個開源的免費的框架(容器)
- Spring是一個輕量級茬腿、非入侵式的框架
- 控制反轉(IOC),面向切面編程(AOP)
- 支持事務的處理宜雀,對框架整合的支持
總結:==Spring是一個輕量級的控制反轉(IOC)和面向切面編程(AOP)的框架==
3切平、組成
4、拓展
-
Spring Boot
- 一個快速開發(fā)的腳手架
- 基于SpringBoot可以快速開發(fā)單個微服務
- 約定大于配置
-
Spring Cloud
- SpringCloud是基于SpringBoot實現
Spring弊端:配置繁瑣
二辐董、IOC理論
1悴品、 IOC原型
- 以往的實現步驟
- XXX Dao
- XXX DaoImpl
- XXX Service
- XXX ServiceImpl
- XXX Servlet
存在問題
(1)當Service層調用Dao層時,Dao層會有許多不同的實現類简烘,是根據不同業(yè)務而實現的苔严,那么Service層會在調用時出現:選擇實現類的問題。
(2)假如Service的實現類孤澎,來選擇某一個Dao層實現類届氢,由ServiceImpl來創(chuàng)建對應的DaoImpl實例對象,那么ServiceImpl就只能有一個具體的Dao層實現類覆旭。
(3)可是當需要使用其他Dao層實現類悼沈,我們需要去改變ServiceImpl中的DaoImpl對象
(4)這樣程序的耦合性高
控制反轉(思想)
假如我們Service層不再實例化一個具體的DaoImpl對象,即程序員不用根據不同的需求而跑到Service層選擇不同的DaoImpl類而創(chuàng)建對象
將對象的創(chuàng)建交給更上一層姐扮,調用Service層的 Servlet層去確定要使用哪一個DaoImpl類絮供,直接創(chuàng)建并且傳入給Service層即可
程序對象創(chuàng)建的主動權,交給了用戶茶敏。至此壤靶,程序員不用管理對象的創(chuàng)建,系統(tǒng)的耦合性降低
-
左邊為:業(yè)務層決定調用的對象惊搏;右邊為:用戶層決定讓業(yè)務層去調用某個對象
- 控制反轉(思想)代碼演示:
- 通過Set注入一個UserDao對象贮乳,程序不再具有主動性,而是變成被動的接收對象
public class UserServiceImpl implements UserService {
//引入Dao層
private UserDao userDao = null;
//由創(chuàng)建該對象的實例對象決定使用那一個UserDao
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
//通過Set注入一個UserDao對象恬惯,程序不再具有主動性向拆,而是變成被動的接收對象
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
2、IOC本質
控制反轉IoC(Inversion of Control)酪耳,是一種設計思想浓恳,DI(依賴注入)是實現IoC的一種方法。
- 沒有IoC的程序中碗暗,我們使用面向對象編程颈将,對象的創(chuàng)建與對象間的依賴關系完全硬編碼在程序中,對象的創(chuàng)建由程序自己控制
- 控制反轉后言疗,將對象的創(chuàng)建轉移給第三方:獲得依賴對象的方式反轉了
采用XML方式配置Bean的時候晴圾,Bean的定義信息是和實現分離的,而采用注解的方式可以把兩者合為一體噪奄,Bean的定義信息直接以注解的形式定義在實現類中死姚,從而達到了零配置的目的人乓。
控制反轉是一種通過描述(XML或注解)并通過第三方去生產或獲取特定對象的方式。在Spring中實現控制反轉的是IoC容器都毒,其實現方法是依賴注入(Dependency Injection色罚,DI)
3、HelloSpring
- Hello.java
- 注意:要有無參的構造方法以及參數的set方法
public class Hello {
String str = null;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
- 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.xsd">
<!--
類型 變量名 = new 類型();
Hello hello = new Hello();
id = 變量名
class = 全類名
property 相當于給對象中的屬性設置一個值
-->
<!--使用Spring來創(chuàng)建對象温鸽,在Spring這些都稱為Bean-->
<bean id="hello" class="com.vigil.pojo.Hello">
<property name="str" value="Spring"></property>
</bean>
</beans>
- Test.java
import com.vigil.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//獲取Spring的上下文對象,解析beans.xml文件手负,生成管理相應的Bean對象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//對象都由Spring管理涤垫,使用的時候直接取出來使用
//getBean:參數即為spring配置文件中的bean的id
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
}
這一系列的過程就叫控制反轉
-
控制:控制對象的創(chuàng)建
- 傳統(tǒng)應用程序的對象是由程序本身控制創(chuàng)建
- 使用Spring后,對象是由Spring來創(chuàng)建
反轉:程序本身不創(chuàng)建對象竟终,而變?yōu)楸粍拥慕邮諏ο?/p>
依賴注入:利用set方法來進行注入
IOC是一種編程思想蝠猬,是由主動的編程編程被動的接收
利用Spring,不用在程序中去改動统捶,要實現不同的操作榆芦,只需要在xml配置文件中進行修改,所謂IoC:對象由Spring創(chuàng)建喘鸟、管理匆绣、裝配
4、對User實現的修改
- UserServiceImpl
public class UserServiceImpl implements UserService {
//引入Dao層
private UserDao userDao = null;
// public UserServiceImpl(UserDao userDao) {
// this.userDao = userDao;
// }
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
- beans.xml(ApplicationContext)
<?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.xsd">
<bean id="Mysql" class="com.vigil.dao.UserDaoMysqlImpl"></bean>
<bean id="SqlServer" class="com.vigil.dao.UserDaoSqlServerImpl"></bean>
<!--
ref:引用Spring容器中創(chuàng)建好的對象
value:具體的值什黑,是基本數據類型
-->
<bean id="UserService" class="com.vigil.service.UserServiceImpl">
<property name="userDao" ref="Mysql"></property>
</bean>
</beans>
- Test.java
public class Test {
public static void main(String[] args) {
// UserService userService = new UserServiceImpl(new UserDaoSqlServerImpl());
// userService.getUser();
//獲取ApplicationContext:拿到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//利用容器獲得對象
UserService userService = (UserService) context.getBean("UserService");
userService.getUser();
}
}
三崎淳、IOC創(chuàng)建對象的方式
- 使用無參構造創(chuàng)建對象,這是默認的愕把!
- 使用有參構造創(chuàng)建對象
1拣凹、第一種方式:下標賦值
2、通過類型創(chuàng)建恨豁,但不建議使用嚣镜,影響多態(tài)的實現
3、第三種方式:直接通過參數名來設置
- 注意:bean的id不可重復
<?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.xsd">
<!--默認的無參構造-->
<bean id="User" class="com.vigil.pojo.User">
<property name="name" value="你好測試"></property>
</bean>
<!--有參構造
第一種方式:下標賦值-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg index="0" value="測試一"></constructor-arg>
</bean>
<!--第二種方式:通過類型創(chuàng)建橘蜜,但不建議使用菊匿,影響多態(tài)的實現-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg type="java.lang.String" value="測試二"></constructor-arg>
</bean>
<!--第三種方式:直接通過參數名來設置-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg name="name" value="測試三"></constructor-arg>
</bean>
</beans>
- 總結:
在配置文件加載的時候,容器中管理的對象就已經初始化了
四计福、Spring配置
1捧请、別名
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg name="name" value="測試三"></constructor-arg>
</bean>
<!--別名,如果添加了別名棒搜,我們也可以使用別名獲取到這個對象-->
<!--這里的name指向id是這個值的bean-->
<alias name="User" alias="userName"></alias>
2疹蛉、Bean配置
- 在 bean 定義本身中,可以使用id屬性指定的最多一個名稱和name屬性中任意數量的其他名稱的組合來為 bean 提供多個名稱力麸。
<!--
id:bean 的唯一標識符可款,也就是相當于對象名
class:bean 對象所對應的全限定名:包名加類名
name:別名育韩,而且name可以同時取多個別名
-->
<bean id="User" class="com.vigil.pojo.User" name="user,u1,userUser">
<constructor-arg name="name" value="測試三"></constructor-arg>
</bean>
3、import
- 將多個配置文件導入合并為一個
<?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.xsd">
<import resource="beans.xml"></import>
<import resource="beans2.xml"></import>
</beans>
五闺鲸、依賴注入
1筋讨、構造器注入
(1) 使用無參構造創(chuàng)建對象,這是默認的摸恍!
<!--默認的無參構造-->
<bean id="User" class="com.vigil.pojo.User">
<property name="name" value="你好測試"></property>
</bean>
(2) 使用有參構造創(chuàng)建對象
- 1)第一種方式:下標賦值
<!--有參構造
第一種方式:下標賦值-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg index="0" value="測試一"></constructor-arg>
</bean>
- 2)通過類型創(chuàng)建悉罕,但不建議使用,影響多態(tài)的實現
<!--第二種方式:通過類型創(chuàng)建立镶,但不建議使用壁袄,影響多態(tài)的實現-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg type="java.lang.String" value="測試二"></constructor-arg>
</bean>
- 3)第三種方式:直接通過參數名來設置
<!--第三種方式:直接通過參數名來設置-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg name="name" value="測試三"></constructor-arg>
</bean>
2、Set方式注入
- 依賴注入:Set注入
- 依賴:bean對象的創(chuàng)建依賴于容器
- 注入:bean對象中所有的屬性媚媒,都由容器來注入
【環(huán)境搭建】
- 復雜類型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
- 真實對象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String,String> care;
private Set<String> games;
private String wife;
private Properties info;
}
- 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.xsd">
<!--第一種嗜逻,普通類型值的注入,value-->
<bean id="student" class="com.vigil.pojo.Student" name="Student">
<property name="name" value="測試"></property>
</bean>
</beans>
- 測試類
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student);
}
}
- 完善
<?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.xsd">
<bean id="address" class="com.vigil.pojo.Address">
<property name="address" value="東百坡"></property>
</bean>
<bean id="student" class="com.vigil.pojo.Student" name="Student">
<!--第一種缭召,普通類型值的注入栈顷,value-->
<property name="name" value="測試"></property>
<!--第二種,Bean注入嵌巷,ref-->
<property name="address" ref="address"></property>
<!--數組-->
<property name="books">
<array>
<value>三國演義</value>
<value>紅樓夢</value>
<value>西游記</value>
<value>紅樓夢</value>
</array>
</property>
<!--List-->
<property name="hobbies">
<list>
<value>聽歌</value>
<value>看電影</value>
<value>敲代碼</value>
<value>玩游戲</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份證" value="12345678"></entry>
<entry key="銀行卡" value="3232121"></entry>
</map>
</property>
<!--Set-->
<property name="games">
<set>
<value>API</value>
<value>LOL</value>
<value>COC</value>
</set>
</property>
<!--null-->
<property name="wife">
<null></null>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="學號">19120501</prop>
<prop key="性別">男</prop>
<prop key="姓名">楚名</prop>
</props>
</property>
</bean>
</beans>
3萄凤、拓展注入
(1) p-namespace :
使用bean元素的屬性(而不是嵌套的<property/>元素)來描述協作 Bean 的屬性值,或同時使用這兩者搪哪,相當于set注入
(2) c-namespace
c:
命名空間執(zhí)行與基于構造函數的依賴注入相同的操作蛙卤,相當于構造器注入
- 代碼實現
<?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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空間注入,可以直接注入屬性的值:property-->
<bean id="user" class="com.vigil.pojo.User" p:name="你好User" p:age="12"></bean>
<!--c命名空間注入噩死,通過構造器注入:construct-args-->
<bean id="userConstructor" class="com.vigil.pojo.User" c:name="HelloUsesr" c:age="23"></bean>
</beans>
- 測試代碼
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = (User) context.getBean("userConstructor");
System.out.println(user.toString());
- 注意:
要加入的一段代碼:xml約束
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
4颤难、Bean的作用域
Scope | Description |
---|---|
singleton | (默認)將每個 Spring IoC 容器的單個 bean 定義范圍限定為單個對象實例。 |
prototype | 將單個 bean 定義的作用域限定為任意數量的對象實例已维。 |
request | 將單個 bean 定義的范圍限定為單個 HTTP 請求的生命周期行嗤。也就是說,每個 HTTP 請求都有一個在單個 bean 定義后面創(chuàng)建的 bean 實例垛耳。僅在web的 Spring ApplicationContext 中有效栅屏。 |
session | 將單個 bean 定義的范圍限定為 HTTP Session 的生命周期。僅在web的 Spring ApplicationContext 上下文中有效堂鲜。 |
application | 將單個 bean 定義的范圍限定為ServletContext 的生命周期栈雳。僅在web的 Spring ApplicationContext 上下文中有效。 |
websocket | 將單個 bean 定義的范圍限定為WebSocket 的生命周期缔莲。僅在web的 Spring ApplicationContext 上下文中有效哥纫。 |
- 單例模式(Spring默認機制)
<bean id="user" class="com.vigil.pojo.User" p:name="你好User" p:age="12" scope="singleton"></bean>
- 原型模式:每次都從容器中get的時候,都會產生一個新的對象
<bean id="userConstructor" class="com.vigil.pojo.User" c:name="HelloUsesr" c:age="23" scope="prototype"></bean>
- 其余的 request痴奏、session蛀骇、application厌秒、websocket,這些只能在web開發(fā)中使用到
六擅憔、Bean的自動裝配
自動裝配模式
Mode | Explanation |
---|---|
no | (默認)無自動裝配鸵闪。 Bean 引用必須由ref元素定義。對于大型部署暑诸,建議不要更改默認設置蚌讼,因為明確指定協作者可以提供更好的控制和清晰度。在某種程度上个榕,它記錄了系統(tǒng)的結構篡石。 |
byName | 按屬性名稱自動布線。 Spring 尋找與需要自動裝配的屬性同名的 bean笛洛。例如夏志,如果一個 bean 定義被設置為按名稱自動裝配乃坤,并且包含一個master屬性(即苛让,它具有setMaster(..)方法),那么 Spring 將查找一個名為master的 bean 定義并使用它來設置屬性湿诊。 |
byType | 如果容器中恰好存在一個該屬性類型的 bean狱杰,則使該屬性自動裝配。如果存在多個錯誤厅须,則會引發(fā)致命異常仿畸,這表明您可能不對該 bean 使用byType自動裝配。如果沒有匹配的 bean朗和,則什么也不會發(fā)生(未設置該屬性)错沽。 |
constructor | 類似于byType,但適用于構造函數參數眶拉。如果容器中不存在構造函數參數類型的一個 bean千埃,則將引發(fā)致命錯誤。 |
- 自動裝配:Spring滿足bean依賴的一種方式
- Spring會在上下文中自動尋找忆植,并自動給bean裝配屬性
在Spring中有三種裝配的方式
- 在xml中顯式的配置
- 在Java中顯式配置
- 隱式 的自動裝配bean【重要】
1放可、測試
(1) 環(huán)境搭配: 一個人有兩個寵物
- Cat.java
public class Cat {
public void show() {
System.out.println("mao~");
}
}
- Dog.java
public class Dog {
public void show() {
System.out.println("hu~");
}
}
- Person.java
public class Person {
private Cat cat;
private Dog dog;
private String name;
}
- 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.xsd">
<bean id="dog" class="com.vigil.pojo.Dog"></bean>
<bean id="cat" class="com.vigil.pojo.Cat"></bean>
<bean id="person" class="com.vigil.pojo.Person">
<property name="name" value="魚佬"></property>
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
</bean>
</beans>
- Test.java
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person.getName());
person.getDog().show();
person.getCat().show();
}
}
2、ByName自動裝配
<bean id="dog" class="com.vigil.pojo.Dog"></bean>
<bean id="cat" class="com.vigil.pojo.Cat"></bean>
<!--byName:會自動在容器上下文中查找朝刊,和該對象set方法后面的值所對應的 beanid
經檢驗耀里,確實是SET后面的字符串,和形參拾氓、類型都沒關系-->
<bean id="person" class="com.vigil.pojo.Person" autowire="byName">
<property name="name" value="魚佬"></property>
</bean>
3冯挎、ByType自動裝配
<bean class="com.vigil.pojo.Dog"></bean>
<bean class="com.vigil.pojo.Cat"></bean>
<!--byType:會自動在容器上下文中查找,和該對象屬性類型相同的bean
所以上下文中要保證該類型全局唯一-->
<bean id="person" class="com.vigil.pojo.Person" autowire="byType">
<property name="name" value="魚佬"></property>
</bean>
- 小結
- 使用byName:需要保證所有的bean的id唯一咙鞍,并且這個bean需要和自動注入的屬性的set方法的值一致
- 使用byType:需要保證所有的bean的class唯一织堂,并且這個bean需要和自動注入的屬性的類型一致
4叠艳、使用注解實現自動裝配
- 導入約束:context
- 配置注解的 支持: <context:annotation-config/>
<?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
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:annotation-config/>
</beans>
1)@Autowired
public @interface Autowired {
boolean required() default true;
}
直接在屬性上使用即可,也可以在set方式上使用
使用 Autowired 易阳,則可以不用編寫set方法附较,前提是:這個自動裝配的屬性在 IOC(Spring)容器中存在,且符合名字byname
2)@Qualifier
public @interface Qualifier {
String value() default "";
}
如果@Autowired自動裝配的環(huán)境比較復雜潦俺,自動裝配無法通過一個注解【@Autowired】完成的時候拒课,可以使用@Qualifier (value = "xxx") 去配合@Autowired的使用,指定唯一的bean對象注入(value是beanid)
3)@Resource
@Resource和@Autowired的區(qū)別
- 都是用來自動裝配的事示,都可以放到屬性字段上
- @Autowired 通過byType的方式實現早像,而且必須要求這個對象存在,常用
- @Resource 默認通過byName的方式實現肖爵,如果找不到名字卢鹦,則通過byType實現。如果兩種方式都無法找到劝堪,會報錯
- 執(zhí)行順序不同:@Autowired 通過byType的方式實現冀自;@Resource 通過byName方式實現
- Test
- beans.xml
<bean id="cat" class="com.vigil.pojo.Cat"></bean>
<bean id="cat2" class="com.vigil.pojo.Cat"></bean>
<bean id="dog" class="com.vigil.pojo.Dog"></bean>
<bean id="dog23" class="com.vigil.pojo.Dog"></bean>
<bean id="person" class="com.vigil.pojo.Person"></bean>
- Person.java
public class Person {
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Resource(name = "dog")
private Dog dog;
private String name;
}
七、使用注解開發(fā)
在Spring4后秒啦,要使用注解開發(fā)熬粗,必須要保證 aop包的導入
使用注解還需要導入context約束,增加注解的支持
<?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
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:annotation-config/>
</beans>
bean
屬性如何注入
//等價于: <bean id="user" class="com.vigil.pojo.User"></bean>
//@Component組件:放在類上余境,說明這個類被Spring管理了驻呐,bean
@Component
public class User {
private String name = "默認測試";
public String getName() {
return name;
}
//相當于<property name="name" value="魚佬"></property>
@Value("魚佬")
public void setName(String name) {
this.name = name;
}
}
- 衍生的注解
@Component有幾個衍生作用域,按照mvc分層
- dao【@Repository】
- service【@Service】
- controller【@Controller】
這四個注解功能一致芳来,都是代表將某個類注冊到Spring中含末,裝配bean
-
自動裝配
1)@Autowired
直接在屬性上使用即可,也可以在set方式上使用
使用 Autowired 即舌,則可以不用編寫set方法佣盒,前提是:這個自動裝配的屬性在 IOC(Spring)容器中存在聋涨,且符合名字byname2)@Qualifier
如果@Autowired自動裝配的環(huán)境比較復雜后频,自動裝配無法通過一個注解【@Autowired】完成的時候,可以使用@Qualifier (value = "xxx") 去配合@Autowired的使用喇聊,指定唯一的bean對象注入(value是beanid)3)@Resource
@Resource 默認通過byName的方式實現芜飘,如果找不到名字务豺,則通過byType實現。如果兩種方式都無法找到嗦明,會報錯 作用域
@Component
//@Scope("singleton")
@Scope("prototype")
public class User {
}
- 小結
- xml和注解:
- xml更加萬能笼沥,適用于任何場合,維護簡單方便
- 注解 維護相對復雜
- xml 與注解的最佳分配
- xml用來管理bean
- 注解只負責屬性的注入
- 必須讓注解生效,就需要開啟注解的支持
<!--指定要掃描的包奔浅,這個包下的注解就會生效-->
<context:component-scan base-package="com.vigil"></context:component-scan>
<context:annotation-config/>
八馆纳、使用JavaConfig實現配置
純Java可以完成Spring的配置
JavaConfig 是Spring的子項目,在Spring 4 之后汹桦,他成為了核心功能
使用@Configuration 聲明配置類時有兩種方法來生成bean
方法一:在配置類中定義一個方法鲁驶,并使用 @Bean 注解聲明
方法二:在類上使用 @Component注解,并在配置類上聲明 @ComponentScan("類的路徑")舞骆,這樣會自動掃描 @Component并生成bean
配置文件(配置類)
// 這個也會由Spring容器托管钥弯,注冊到容器中,因為他本來就是一個@Component
// @Configuration 代表這是一個配置類督禽,相當于applicationContext.xml
@Configuration
@Component("com.vigil.pojo")
//將其他配置文件融合到當前的類中
@Import(com.vigil.config.VigilConfig.class)
public class VigilConfig {
//注冊一個bean脆霎,就相當于 bean標簽
//方法名,相當于bean標簽中的id屬性
//方法返回值狈惫,相當于bean標簽的class屬性
@Bean
public User getUser() {
return new User();//返回要注入的bean對象
}
}
- 實體類
public class User {
private String name;
public String getName() {
return name;
}
@Value("魚佬")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- Test
public class Test {
public static void main(String[] args) {
//如果完全使用了配置類方式去做睛蛛,就只能通過 AnnotationConfig 上下文來獲取容器,通過配置類的class對象加載
ApplicationContext context = new AnnotationConfigApplicationContext(VigilConfig.class);
User user = (User) context.getBean("getUser");
System.out.println(user.getName());
}
}
九胧谈、代理模式
代理模式是:SpringAOP的底層(面向切面編程)
- 代理分類 (核心:多態(tài))
- 靜態(tài)代理
- 動態(tài)代理
1忆肾、靜態(tài)代理
1)角色分析
- 抽象角色:一般會使用接口或者抽象類來解決
- 真實角色:被代理的角色
- 代理角色:代理真實角色,代理真實角色后第岖,一般會有附屬的操作
- 客戶:訪問代理對象的人
2)演示住房中介
代碼步驟:
- 接口(出租者)
public interface Leaser {
public abstract void lease();
}
- 真實角色(房東)
public class Landlord implements Leaser {
public void lease() {
System.out.println("I have a room to lease");
}
}
- 代理角色(出租房屋中介)
public class RentalAgent implements Leaser {
private Leaser landlord;//中介聚合多個房東:Leaser[]
public RentalAgent() {
}
public RentalAgent(Leaser landlord) {
this.landlord = landlord;
}
public void setLandlord(Leaser landlord) {
this.landlord = landlord;
}
public void lease() {
//調用用戶需要的房子难菌,的房東
landlord.lease();
//幫助房東完成租房合同的簽寫
contract();
//幫助房東收取租金
rent();
}
// 簽寫租憑合同
public void contract() {
System.out.println("to sign a contract");
}
// 收取租金
public void rent() {
System.out.println("delivery of the rent");
}
}
- 客戶(租房者):訪問代理角色
public class Lessee {
public static void main(String[] args) {
//租房找中介
RentalAgent agent = new RentalAgent();
//看中了某個房子
//讓中介去聯系這個房東试溯,是否能租房蔑滓,不需要客戶去聯系,客戶看房間就行
agent.setLandlord(new Landlord());
agent.lease();
}
}
靜態(tài)代理模式的好處
- 可以使真實角色的操作更加純粹遇绞,不用關心公共業(yè)務
- 公共業(yè)務就交給代理角色键袱,實現業(yè)務分工
- 公共業(yè)務發(fā)生拓展時,方便集中管理
缺點
- 一個真實角色就會產生一個代理角色摹闽,代碼量翻倍蹄咖、開發(fā)效率變低
2、動態(tài)代理
- 動態(tài)代理和靜態(tài)代理角色一樣
- 動態(tài)代理的代理類是動態(tài)生成的
- 動態(tài)代理分為兩大類:基于接口的動態(tài)代理付鹿、基于類的動態(tài)代理
- 基于接口 --- JDK動態(tài)代理
- 基于類:cgilb
- Java字節(jié)碼實現:javasist
JDK動態(tài)代理 兩個重要的兩個類
- Proxy:代理
- InvocationHandler:調用處理程序
測試例子
1)角色分析
- 抽象角色:一般會使用接口或者抽象類來解決
- 真實角色:被代理的角色
- 代理角色:代理真實角色澜汤,代理真實角色后,一般會有附屬的操作
- 客戶:訪問代理對象的人
2)演示住房中介
動態(tài)代理的代碼步驟:
- 出租者接口
public interface Leaser {
public abstract void lease();
}
- 出租者實例:房東
public class Landlord implements Leaser {
public void lease() {
System.out.println("I have a room to lease");
}
}
- 出租者代理:出租中介(與靜態(tài)代理最不同的地方)
注意:實現了InvocationHandler 接口
要有要被代理的接口的注入
要有得到代理類的方法舵匾,也就是調用了Proxy.newProxyInstance() 得到一個代理類
因為繼承了Invocation俊抵,所以invoke() 方法是要實現的
在invoke() 方法里,要調用傳入的method對象的invoke() 方法
//自動生成代理類坐梯,要實現接口Invocation
public class ProxyInvocationHandler implements InvocationHandler {
// 1.被代理的接口
private Object target;
// 2.注入要代理的接口實現類實例對象
public void setTarget(Object target) {
this.target = target;
}
// 3.生成代理類:指定由指定的類裝入器定義的代理類的指定調用處理程序的代理實例徽诲,并實現指定的接口
public Object getProxy() {
//Proxy創(chuàng)建動態(tài)代理類的實例提供了靜態(tài)方法,也是所有動態(tài)代理類的父類的方法創(chuàng)建
// this.getClass().getClassLoader():loader的類裝載器來定義代理類
// target.getClass().getInterfaces():interfaces -為代理類實現的接口列表
// this:InvocationHandler -調用處理程序調度方法調用
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
// 4.處理代理類實例,返回結果
// 在代理實例上處理方法調用谎替,并返回結果偷溺。
// 當在與它關聯的代理實例上調用方法時,該方法將在調用處理程序上調用此方法钱贯。
// 參數:
//proxy -代理實例挫掏,調用的方法
//對接口方法的調用相應的 method代理實例的 方法實例。聲明類的 方法對象將接口的方法聲明秩命,這可能是一個超接口代理接口砍濒,代理類繼承的方法。
//args -包含在方法上通過代理實例調用的實參的值對象的數組硫麻,或 null如果接口方法不需要參數爸邢。原始類型的實參是包裹在適當的原始包裝類的實例,如 java.lang.Integer或 java.lang.Boolean拿愧。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//動態(tài)代理的本質杠河,使用反射機制
Object result = method.invoke(target, args);
contract();
rent();
return null;
}
// 簽寫租憑合同
public void contract() {
System.out.println("to sign a contract");
}
// 收取租金
public void rent() {
System.out.println("delivery of the rent");
}
}
- 用戶
注意:要有一個被代理的對象,然后注入給代理角色處理類浇辜,再得到一個被代理的代理實例券敌,最后才能調用代理實例的方法
public class Lessee {
public static void main(String[] args) {
//真實角色
Leaser landlord = new Landlord();
//代理角色處理類
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通過調用程序處理角色,來處理將要被調用的接口(被代理的接口)
pih.setTarget(landlord);//設置要代理的對象
Object obj;
if((obj = pih.getProxy()) instanceof Leaser) {
((Leaser)(obj)).lease();
}
}
}
動態(tài)代理模式的好處
- 可以使真實角色的操作更加純粹柳洋,不用關心公共業(yè)務
- 公共業(yè)務就交給代理角色待诅,實現業(yè)務分工
- 公共業(yè)務發(fā)生拓展時,方便集中管理
- 一個動態(tài)代理類代理的是一個接口熊镣,一般就是對應的一類業(yè)務
十卑雁、AOP
1、什么是AOP
1)AOP (Aspect Oriented Programming):面向切面編程绪囱,通過預編譯方式和運行期動態(tài)代理實現程序功能的統(tǒng)一維護的一種技術
2)AOP 是 OOP 的延續(xù)测蹲,是Spring框架中的一個重要內容,是函數式編程的一種衍生范型鬼吵。
3)利用AOP 可以對業(yè)務邏輯的各個部分進行隔離扣甲,從而使得業(yè)務邏輯各部分之間的耦合度降低,提高程序的可重用性齿椅,同時提高開發(fā)的效率
2琉挖、AOP 在Spring中的作用
提供聲明式事務;允許用戶自定義切面
- 橫切關注點:跨越應用程序多個模塊的方法或功能涣脚。即是:與我們業(yè)務邏輯無關的示辈,但是我們需要關注的部分,就是橫切關注點涩澡。如:日志顽耳,安全坠敷,緩存,事務等
- 切面(ASPECT):橫切關注點 被模塊化 的特殊對象射富。是一個類
- 通知(Advice):切面必須要完成的工作膝迎。是類中的方法
- 目標(Target):被統(tǒng)治的對象
- 代理(Proxy):向目標對象應用通知之后創(chuàng)建的對象
- 切入點(PointCut):切面通知 執(zhí)行的”地點“的定義
- 連接點(JointPoint):與切入點匹配的執(zhí)行點
SpringAOP中,通過Advice定義橫切邏輯胰耗,Spring中支持5中類型的Advice:
通知類型 | 連接點 | 實現接口 |
---|---|---|
前置通知 | 方法前 | org.springframework.aop.MethodBeforeAdvice |
后置通知 | 方法后 | org.springframework.aop.AfterReturningAdvice |
環(huán)繞通知 | 方法前后 | org.aopalliance.intercept.MethodInterceptor |
異常拋出通知 | 方法拋出異常 | org.springframework.aop.ThrowsAdvice |
引介通知 | 類中增加新的方法屬性 | org.springframework.aop.IntroductionInterceptor |
即 AOP 在不改變原有代碼的情況下限次,去增加新的功能
3、使用Spring實現AOP
【重點】使用AOP織入柴灯,需要導入一個依賴包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
(1) 使用Spring的API接口【主要SpringAPI接口實現】
- UserService
public interface UserService {
public void add();
public void update();
public void delete();
public void query();
}
- UserServiceImpl
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一個用戶");
}
public void update() {
System.out.println("修改了一個用戶");
}
public void delete() {
System.out.println("刪除了一個用戶");
}
public void query() {
System.out.println("查詢了一個用戶");
}
}
- Log 實現 MethodBeforeAdvice 接口
public class Log implements MethodBeforeAdvice {
//method: 要執(zhí)行的目標對象的方法
//args: 參數
//target: 目標對象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass() + "的" + method.getName() + "方法被執(zhí)行了");
}
}
- AfterLog 實現 AfterReturningAdvice 接口
public class AfterLog implements AfterReturningAdvice {
//returnValue:返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("執(zhí)行了" + 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="userService" class="com.vigil.service.UserServiceImpl"></bean>
<bean id="log" class="com.vigil.log.Log"></bean>
<bean id="afterLog" class="com.vigil.log.AfterLog"></bean>
<!--方式一:使用原生的Spring API接口-->
<!--配置aop:導入aop的約束-->
<aop:config>
<!--切入點:expression:表達式,execution(要執(zhí)行的位置赠群! * * * * *)修飾詞 返回值 列名 方法名 參數-->
<aop:pointcut id="pointcut" expression="execution(* com.vigil.service.UserServiceImpl.*(..))"/>
<!--執(zhí)行環(huán)繞增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
- Test
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//十分注意的地方:動態(tài)代理----->代理接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
(2) 自定義類來實現AOP【主要切面定義】
- UserService
- UserServiceImpl
- MyLog
public class MyLog {
public void before() {
System.out.println("======方法執(zhí)行前======");
}
public void after() {
System.out.println("======方法執(zhí)行后======");
}
}
- applicationContext.xml
<!--方式二:自定義類-->
<bean id="myLog" class="com.vigil.diy.MyLog"></bean>
<aop:config>
<!--自定義切面羊始,ref 要引用的類-->
<aop:aspect ref="myLog">
<!--切入點-->
<aop:pointcut id="point" expression="execution(* com.vigil.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
- Test
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//動態(tài)代理:代理接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
- 兩種方式小結
方式一:使用原生Spring API接口 配置文件里只說明用哪幾個通知,根據類的定義(實現)去分配具體的功能(before/after)
方式二:自定義類 配置文件里說明切面類的某個方法是做什么的查描,這樣就不用限制類本身性質了
十分注意的地方:動態(tài)代理----->代理接口突委,那么我們傳入的是接口,得到是接口實現的實例化對象
(3) 使用注解實現AOP
- UserService
- UserServiceImpl
- AnnotationPointCut.java
@Aspect //標注這個類是一個切面
public class AnnotationPointCut {
@Before("execution(* com.vigil.service.UserServiceImpl.*(..))")
public void before() {
System.out.println("方法執(zhí)行前");
}
@After("execution(* com.vigil.service.UserServiceImpl.*(..))")
public void after() {
System.out.println("方法執(zhí)行后");
}
//在環(huán)繞增強中冬三,可以給定一個參數匀油,代表要獲取處理切入的點
@Around("execution(* com.vigil.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("==環(huán)繞前==");
Signature signature = joinPoint.getSignature();//獲得簽名
System.out.println("signature" + signature);
//執(zhí)行方法
Object proceed = joinPoint.proceed();
System.out.println("==環(huán)繞后==");
System.out.println(proceed);
}
}
- applicationContext.xml
<!--方式三:使用注解-->
<bean id="annotationPointCut" class="com.vigil.diy.AnnotationPointCut"></bean>
<!--開啟注解支持-->
<!--JDK(默認 proxy-target-class="false")-->
<!--cglib(proxy-target-class="true")-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
- Test.java
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//動態(tài)代理:代理接口
UserService userService = (UserService) context.getBean("userService");
userService.update();
}
十一、Spring整合Mybatis
步驟:
- 導入相關的包
- junit
- mybatis
- mysql數據庫
- spring相關
- aop織入
- mybatis-spring【new】
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--spring-jdbc:Spring操作數據庫-->
<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.8.13</version>
</dependency>
<!---->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
- 編寫配置文件
- 測試
1勾笆、回憶mybatis
- 編寫實體類
- 編寫核心配置文件
- 編寫接口
- 編寫接口對應的Mapper.xml
- 在核心配置文件中注冊Mapper.xml
- 測試
2敌蚜、整合Mybatis方式一
- 編寫數據源配置
<!--DataSource:使用Spring的數據源替換MyBatis的配置 c3p0 dbcp druid
使用Spring提供的JDBC:org.springframework.jdbc.datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="20201123"/>
</bean>
- sqlSessionFactory
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--綁定MyBatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/vigil/mapper/*.xml"></property>
</bean>
- sqlSessionTemplate
<!--SqlSessionTemplate:SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用構造器注入sqlSessionFactory,因為該類沒有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
前三個配置在一個spring.xml 文件中(作為一個工具配置)窝爪,實現獲得數據源弛车、sqlSessionFactory、sqlSession這三類資源的配置文件
- 需要給接口加實現類【】
public class UserMapperImpl implements UserMapper {
// 在原來所有的操作:都使用sqlSession來執(zhí)行
// 而現在都使用SqlSessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> getUserList() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUserList();
}
}
- 將實現類注入Spring中
在Spring總配置文件applicationContext.xml 中 import 上面配置資源的xml酸舍,注入該實現類
<import resource="spring-dao.xml"></import>
<!---->
<bean id="userMapper" class="com.vigil.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"></property>
</bean>
- 測試(獲得Spring容器帅韧,獲取bean里初,調用方法)
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper",UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
3啃勉、整合Mybatis方式二
- 實現類
繼承SqlSessionDaoSupport,直接獲取SqlSession的對象
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
public List<User> getUserList() {
return getSqlSession().getMapper(UserMapper.class).getUserList();
}
}
- 注入spring
<bean id="userMapper2" class="com.vigil.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
- 測試
4双妨、總結工具配置
<?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.xsd">
<!--DataSource:使用Spring的數據源替換MyBatis的配置 c3p0 dbcp druid
使用Spring提供的JDBC:org.springframework.jdbc.datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="20201123"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--綁定MyBatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/vigil/mapper/*.xml"></property>
</bean>
<!--SqlSessionTemplate:SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用構造器注入sqlSessionFactory淮阐,因為該類沒有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
</beans>
十二、聲明式事務
1刁品、事務
- 要么都成功要么都失敗
- ACID原則:
- 原子性
- 一致性
- 隔離性
- 持久性
2泣特、Spring中的事務管理
- 編程式事務:需要在代碼中,進行事務的管理
- 聲明式式事務:AOP
- 需要導入的包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--spring-jdbc:Spring操作數據庫-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!---->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
- 配置文件
<?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:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--DataSource:使用Spring的數據源替換MyBatis的配置 c3p0 dbcp druid
使用Spring提供的JDBC:org.springframework.jdbc.datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="20201123"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--綁定MyBatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/vigil/mapper/*.xml"></property>
</bean>
<!--SqlSessionTemplate:SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用構造器注入sqlSessionFactory挑随,因為該類沒有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
<!--配置聲明式事務-->
<bean id="transactionManage" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--結合AOP實現事務的織入-->
<tx:advice id="tsAdvice" transaction-manager="transactionManage">
<!--給那些方法配置事務-->
<!--配置事務的傳播特性:propagation-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事務切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.vigil.mapper.*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="tsAdvice" pointcut-ref="txPointCut"></aop:advisor>
</aop:config>
</beans>