<!doctype html>Spring5筆記css
Spring是一個輕量級的開源的javaee框架html
Spring目的:能夠解決企業應用開發的複雜性java
String組成部分:核心部分node
總結一句話:Spring就是一個輕量級的數據反轉(IOC)和麪向切面編程(AOP)的框架mysql
Spring bootweb
Spring cloudspring
由於使用的人多,大多數都在使用SpringBoot進行快速開發,學習SpringBoot的前提,須要徹底掌握Spring及SpringMVC!承上啓下的做用!sql
弊端:發展了過久以後,違背了原來的理念!配置十分繁瑣,人稱:「配置地獄!」數據庫
建立maven工程,普通Java工程編程
導入座標
只須要導入一個Spring Context,經過傳遞依賴就能夠把其餘的jar所有導入進來
<dependencies>
<!--經過maven窗體依賴,導入依賴的jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--junit單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--日誌-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
在resources目錄下導入log4j.properties
編寫包,編寫Service接口和實現類
在resouces目錄下編寫配置文件(推薦名爲:"applicationContext.xml")
xxxxxxxxxx
<!--文檔聲明-->
<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"
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/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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
編寫測試方法,調方法
小提示:ApplicationContext工廠類 按住快捷鍵Ctrl+H 能夠查看該類的結構
xxxxxxxxxx
//先建立Spring的IOC的工廠,加載src目錄下的配置文件,把配置文件中的類建立成對象,存儲到IOC容器中
ApplicationContext ac = new FileSystemXMlApplicationContext("加載某個磁盤上的文件");
//ApplicationContext ac = new ClassPathXmlApplicationContext("resources目錄下配置文件");
//從容器中獲取對象
UserService us = (UserService)ac.getBean("配置文件bean標籤的id屬性獲取該對象");//注意:強轉,使用接口接收
//調用對象的方法
us....
Bean標籤的屬性
id:--> 對象在IOC容器中惟一的名稱,要求編寫的時候是惟一的
class: --> 管理的類的全路徑(包名+類名),經過Java反射技術幫助建立實例對象,建立後存到IOC容器當中,經過id來拿對象
scope: --> 建立後對象的生命週期(做用範圍)
singLeton --> 默認的:單例的,IOC容器中只會存在一個實例的 (通常默認使用)
prototype --> 多例的:(每次獲取 都會建立新的實例對象)
xxxxxxxxxx
//驗證單例和多例的生命週期
//在service編寫構造方法輸出內容 配置文件修改單例和多例查詢結果 是否先輸出構造參數仍是先輸出從容器中獲取對象以前的內容
init-method ,當bean被載入到容器的時候調用init-method屬性指定的方法
destroy-method ,當bean從容器中刪除的時候調用destroy-method屬性指定的方法
通常會用來完成銷燬工做: destroy-method = "service實現類方法"
xxxxxxxxxx
<bean id="" class="" scope="" init-method="" destroy-method=""></bean>
框架提供建立bean對象的三種方式,基本上都使用默認方式
xxxxxxxxxx
<bean id="user" class="...."/>
xxxxxxxxxx
//建立StaticFactory實體類
//建立靜態create(自定義名User)方法 返回值Service這個類
public class StaticFactory{
//靜態工廠方式
public static UserService createUser(){
sout("經過靜態工廠的方式建立....")
return new UserServiceImpl();
}
}
//配置文件中 "經過StaticFactory類的creatrUser這個靜態類獲取的對象"
//優勢:編寫不少業務邏輯 權限校驗...
<bean id="user" class="包名+StaticFactory類" factory-method="createUser" />
//測試類
...
xxxxxxxxxx
//建立Dfactory實體類
//動態工廠方式
public class Dfactory{
//靜態工廠方式
public static UserService createUser(){
sout("實例化工廠的方式建立....")
return new UserServiceImpl();
}
}
<bean id="user" class="包名+Dfactory類" factory-method="createUser" factory-bean="dfactory" />;
//測試類
...
把全部配置都寫在一個配置文件中,太亂,spring支持多配置文件方式
xxxxxxxxxx
//加載多個配置文件
ApplicationContext ac = new ClassPathXmlApplication("applicationContext.xml","application...");//CTRL+P 參數能夠有多個 能夠加載多個配置文件
xxxxxxxxxx
<!-- 引入其餘的配置文件 -->
<import resource="applicationContext2.xml"/>
ApplicationContext工廠:建立對象都是由工廠來實現的,讀取配置文件,底層使用反射機制來建立對象
ApplicationContext這個接口底層有2個實現類,Ctrl+H查看
使用工廠,獲取IOC容器中的對象 工廠對象.getBean("bean標籤的id別名");
加載多個配置文件,獲取工廠時,參數能夠給多個
或在主配置文件中,增長引入其餘的配置文件
IOC和DI的概念
引用類型注入:
xxxxxxxxxx
//將dao和service都存放到容器中
//在Service裏面建立Dao成員屬性
//給成員屬性提供一個set方法
//最後修改bean標籤
<bean id="user" class="...">
<property name="這個類的屬性名" ref="引用(bean標籤的id屬性)"/>
</bean>
基本類型注入
xxxxxxxxxx
//將dao和service都存放到容器中
//在Service裏面建立Dao成員屬性
//給成員屬性提供一個set方法
//最後修改bean標籤
<bean id="user" class="...">
<property name="屬性名" value="成員屬性基本類型的值"/>
</bean>
xxxxxxxxxx
<!--基本數據類型注入方式-->
<bean id="service" class="cn.dong.service.impl.UserServiceImpl">
<property name="dao" ref="userDao" />
<property name="name" value="張三" />
</bean>
總結:
xxxxxxxxxx
//寫實體類 建立構造方法
//配置文件配置bean
<bean id="惟一的名" class="..">
<constructor-arg name="屬性的名稱" value="基本類型" ref="引用類型"/>
<constructor-arg name="屬性的名稱" value="基本類型" ref="引用類型"/>
<constructor-arg name="屬性的名稱" value="基本類型" ref="引用類型"/>
</>
xxxxxxxxxx
<!--屬性構造器方式注入值-->
<bean id="user" class="cn.dong.domain.User">
<constructor-arg name="name" value="張三"/>
<constructor-arg name="age" value="20"/>
</bean>
本身通常寫程序用的比較少,可是使用多個框架整合的時候,必定得會寫
xxxxxxxxxx
//寫實體類 建立set方法 tostring 數組,集合
//配置文件(給集合屬性注入值)
<bean id="" class="">
//數組
<property name="屬性名稱">
<array>//給數組傳值
<value>張三</value>//基本類型的數組
<value>李四</value>//基本類型的數組
//<ref></ref>引用類型的數組
<array/>
</property>
//list集合
<property name="屬性名稱">
<list>//給list集合傳值
<value>張三</value>//泛型爲基本類型
<value>李四</value>//泛型爲基本類型
//<ref></ref>泛型爲引用類型
<list/>
</property>
//map集合
<property name="屬性名稱">
<map>//給list集合傳值
<entry key-ref="" value/>//泛型爲引用類型
<entry key="" value=""/>//泛型爲基本類型
<entry key-ref="" value=""/>//泛型爲基本類型
<map/>
</property>
//屬性配置文件 實體類 private Properties properties;
<property>
<props>
<prop key="key...">值</prop>
</props>
</property>
<bean/>
@Value(value = "字符串或數值") //在屬性上增長
xxxxxxxxxx
//注意:使用配置文件方式依賴注入,須要提供set方法
//使用註解注入值能夠不須要set方法
"張三") (
private String name;
value="29") (
private int age;
xxxxxxxxxx
//也不用提供set方法 (經常使用)
//按類型(和id沒有任何關係,容器中有對象就自動裝配注入)自動裝配的註解
private User user;
//按id名稱的方式注入 @Qualifier不能單獨使用,須要Autowired一塊兒使用
value="id名稱") (
//這一個頂第二個兩個 (偶爾用)
name = "id名稱") //Java提供的註解,按名稱注入對象,屬性名稱是name (
xxxxxxxxxx
//建立普通的Java的maven工程
//引入座標,
<dependencies>
<!--經過maven窗體依賴,導入依賴的jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--junit單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--日誌實現-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--日誌-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--鏈接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!--MySql驅動包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
</dependencies>;
//建立數據庫 建立表結構 id主鍵 用戶名 money錢 添加3條數據
...;
//新建包,實體類對應數據庫,dao,service
//dao寫一個查詢全部數據的方法
...
//service...
//測試方法
...
xxxxxxxxxx
//新建編寫spring核心配置文件 log4j配置文件
//配置service和dao的bean標籤 依賴注入...
//dao 鏈接池對象注入到spring 配置鏈接池
<bean id="" class="...">
<property name="driverClassName" value"" />
<property name="url" value"" />
<property name="username" value"" />
<property name="password" value"" />
</bean>;
//在dao提供DateSource成員屬性 建立set方法 privete DataSource dataSource
<bean id="" class="...">
<property name="dataSource" ref="dataSource" />
</bean>
IOC註解的方式依賴沒有變化
編寫接口和實體類
在須要管理的類上增長@Compoent註解
xxxxxxxxxx
value = "user") //組件,做用:把當前類使用IOC容器進行管理,若是沒有指定名稱,默認使用類名,首字母是小寫,或者本身指定名稱 (
public class UserServiceImpl implents UserService{}
//spring核心配置文件 多配置文件也能夠
<!-- 開啓註解掃描 -->;
<context:component-scan base-package="cn.dong包名"/>
以上註解@Component... =
xxxxxxxxxx
value="annotation") (
public class AnnotationServiceImpl implements AnnotationService {
public void showInfo() {
System.out.println("顯示信息!!");
}
}
@Value(value = "字符串或數值") //在屬性上增長
xxxxxxxxxx
//注意:使用配置文件方式依賴注入,須要提供set方法
//使用註解注入值能夠不須要set方法
"張三") (
private String name;
value="29") (
private int age;
xxxxxxxxxx
//也不用提供set方法 (經常使用)
//按類型(和id沒有任何關係,容器中有對象就自動裝配注入)自動裝配的註解
private User user;
//按id名稱的方式注入 @Qualifier不能單獨使用,須要Autowired一塊兒使用
value="id名稱") (
//這一個頂第二個兩個 (偶爾用)
name = "id名稱") //Java提供的註解,按名稱注入對象,屬性名稱是name (
xxxxxxxxxx
value = "singleton") //默認值,單例的 (
value = "propotype") //多例的 (
xxxxxxxxxx
//@PostConstruct 至關於init-method
public void init(){ sout("初始化"); }
//@PreDestroy 至關於destroy-method
public void destroy(){ sout("銷燬"); }
使用以上註解須要在Spring的配置文件進行註解掃描,不然無法注入到IOC容器,報錯空指針異常
xxxxxxxxxx
<!--開啓註解掃描(組件掃描)-->
<context:component-scan base-package="cn.dong.service"/>
純註解的方式是微服務架構開發的主要方式,因此也是很是的重要。純註解的目的是換掉全部的配置文件。可是須要編寫配置類。
編寫配置類SpringConfig,包SpringConfig,替換掉applicationContext.xml配置文件
xxxxxxxxxx
//聲明當前類是一個配置類
value = {"cn.dong","..."})//配置掃描的包 (
public class ...{}
編寫測試方法
//編寫程序,加載配置類
//建立工廠,加載配置類
ApplicaitonCOntext ac = new AnnotationConfigApplicaitonContext(配置類.class);
ac.getBean(....
範例:
xxxxxxxxxx
value="showInfo")//加載類到IOC容器 (
public class UserServiceImpl implements UserService {//Service業務層
public void showInfo() {
System.out.println("業務層顯示信息.....");
}
}
//聲明當前類是一個配置類
value="cn.dong") //配置掃描的包 (
public class SpringConfig {
}
junit.Test .
public void show(){//測試類
//建立工廠,加載配置類
ApplicationContext ac = new AnnotationConfigApplicationContext(UserServiceImpl.class);
//使用工廠獲取對象
UserServiceImpl service=(UserServiceImpl) ac.getBean("showInfo");
service.showInfo();
}
@import註解 String的配置文件能夠分紅多個配置的,編寫多個配置類,用於導入其餘配置類
xxxxxxxxxx
@Impoer(value={xxx.class,xxx.class})
public class SrpingConfig{}
@Bean 只能寫在方法上,代表使用此方法建立一個對象,對象建立完成保存到IOC容器中,(用於解決鏈接池的對象管理等,不少類都不是本身寫的,只是拿來用不能隨意更改,不能加註解,就得使用bean註解)
xxxxxxxxxx
管理IOC,管理鏈接池對象
/**
* 建立鏈接池對象,返回對象,把該方法建立後的對象存入到鏈接池中,使用@Bean註解解決
*/;
name="dataSource")//name惟一的 (
public DataSource source(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("...");
dataSource.setUsername(".....");
return dataSource;
}
同等於 Spring配置文件中,配置鏈接池對象;
<bean id="..." ..>
<property name="" value="..."/>
</bean>
xxxxxxxxxx
持久層;
//Spring模板
name="template") (
public JdbcTemplate template(){
//實例化JdbcTemplate對象 Spring模板
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
return template;
}
測試類;
public void show(){
//加載配置類,建立工廠
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
//使用工廠對象獲取對象
JdbcTemplate template =(JdbcTemplate) ac.getBean("template");
//寫sql語句
String sql = "select count(*) from user";
//數據操做
Integer i=template.queryForObject(sql, Integer.class);
System.out.println(i);
}
經常使用註解(類加載到IOC容器)
這四個註解使用方法,和結果都是同樣的,可是仍是推薦哪一個領域寫哪一個註解!
依賴注入註解
基本類型依賴注入
引用類型依賴注入
對象生命週期註解
初始化和銷燬註解
IOC純註解方式
引入多個配置類
xxxxxxxxxx
@Configuration //聲明配置類
public class SpringConfig{}
@Configuration //聲明配置類
//掃描指定的包結構
@ComponentScan(value="cn.dong")
//引用新的配置類
Import(valueu = {SpringConfig2.class})
public class SpringConfig2{}
@Bean註解(重要)
只能寫在方法上,代表使用此方法建立一個對象,對象建立完成保存到IOC容器中,(用於解決鏈接池的對象管理等,不少類都不是本身寫的,只是拿來用不能隨意更改,不能加註解,就得使用bean註解)
快速入門
xxxxxxxxxx
<!-- 整合單元測試 -->
<bean id="user" class="cn.dong.User"></bean>
xxxxxxxxxx
//運行單元測試
value = SpringJunit4ClassRunner.class) (
//加載類路徑下的配置文件
value = "classpath:Spring配置文件路徑") (
public Class Test{
//測試哪個對象,就把該對象注入進來,在測試環境下,可使用註解方式注入測試的對象
private User user;//依賴注入的測試對象
public void show(){
//...
}
}
xxxxxxxxxx
//建立配置類
//聲明配置類
//掃描包結構
value = "cn.dong要掃描的路徑") (
public class SpringConfig(){
}
//建立測試類
SpringJunit4ClassRunner.class)//運行單元測試 (
classes = SpringConfig.class)//加載配置類 (
public class Test(){
//按類型依賴注入
private User user;
public void show(){
user...
}
}
xxxxxxxxxx
測試類
//運行單元測試
value = SpringJUnit4ClassRunner.class) (
//加載路徑下的配置文件
value="classpath:applicationContext.xml") (
public class Test3 {
//依賴注入的測試對象
private User user;
//Junit測試
public void show(){
user.setName("顫三");
System.out.println(user);
}
}
User實體類
public class User {
爲何要使用Spring整合的Junit單元測試?
測試類增長如下註解
在測試類中,增長"依賴注入的測試對象(接口)" 直接使用對象調方法便可 (千萬不要忘記: 依賴注入的測試對象 增長@Autowired 自動裝配對象到IOC容器管理)
建立maven的普通工程,引入開發座標,跟原來如出一轍
建立包,實體類,業務層,持久層...
導入配置文件
業務層建立2個帳戶,持久層建立1個帳戶
問題來了:業務層若是有一個帳戶建立失敗,就不能給數據庫添加數據,就應該事務回滾,須要事務管理
開啓事務 要用Connection接口,發現dao也須要用到Connection接口,並且還必須用到業務層的Connection接口
xxxxxxxxxx
//業務層
sout("業務層:保存兩個帳號");
//開啓事務 要用Connection接口,發現dao也須要用到Connection接口,並且還必須用到業務層的Connection接口
工具類.startTransaction();
//第一種方法:方法的參數傳遞,設計以前參數須要一個Connection接口,誰調用誰傳遞 (太麻煩)
//第二種方法:線程綁定 能夠從當前線程中拿到直接綁定的Connection (優先使用)
//執行操做
try{
dao.seve(user1);
//模擬異常
...
dao.seve(user2);
//提交事務/回滾事務
工具類.commit();
} catch(...) {
//回滾事務打印異常信息
工具類.rollback();
}finally{
//關閉資源(歸還鏈接)
工具類.close();
}
編寫持久層dao;
//獲取到鏈接
Connection conn = 工具類.getConnection();
//編寫sql
...;
//預編譯
PreparedStatement stmt = conn.prepareStatement(sql);
//設置值
stme.setString(1,user.getName());
stmt.setInt(2,user.getMoney());
//執行操做
stmt.executeUpdate();
//關閉資源 conn不能關閉
stmt.close();
xxxxxxxxxx
業務層
//DI依賴注入Dao
UserDaoImpl dao;
public void setDao(UserDaoImpl dao) {
this.dao=dao;
}
/**
* 保存2個帳戶
* @param user1
* @param user2
*/
public void save(User user1, User user2) {
//開啓事務:使用第二種方法「線程綁定」
try {
AffairUtils.startTransaction();
//執行操做
dao.save(user1);
dao.save(user2);
//提交事務
AffairUtils.commit();
} catch (Exception e) {
//打印錯誤信息
e.printStackTrace();
//提交回滾
AffairUtils.rollback();
} finally {
//歸還鏈接
AffairUtils.close();
}
}
持久層;
public void save(User user) throws SQLException {
//獲取鏈接
Connection conn=AffairUtils.getConnection();
//編寫sql
String sql="insert into `user`.`user` (`name`, `money`) values (?, ?)";
//預編譯
PreparedStatement stmt=conn.prepareStatement(sql);
//設置值
stmt.setString(1, user.getName());
stmt.setInt(2, user.getMoney());
//執行操做
stmt.executeUpdate();
//關閉資源
stmt.close();
}
測試類:
public void show(){
//加載配置文件,建立工廠
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//使用工廠對象獲取對象
UserService service =(UserService) ac.getBean("userService");
//建立用戶
User user1 = new User("熊大",1000);
User user2 = new User("熊二",2000);
//保存
service.save(user1,user2);
}
使用到的事務工具類: AffairUtils.java
業務層開啓事務 要用Connection接口,發現持久層也須要用到Connection接口,並且還必須用到業務層的Connection接口
以上代碼的業務層很是繁瑣,在真正開發中,業務層只須要關注業務邏輯,不須要關注其餘,因此就須要進行,業務層的方法加強
加強方法的手段
xxxxxxxxxx
//建立JdkProxy類
//傳入目標對象,生成該對象的代理對象,返回,對目標對象的方法進行加強
//獲取代理對象,返回,加強目標對象的方法
public static Object getProxy(UserService userService){
/**
* 使用Jdk的動態代理生成代理對象
*/
Object proxy = Proxy.newProxyInstance(類加載器,傳入對象的實現的接口要字節碼對象,回調函數匿名內部類);
//類加載器 JdkProxy.class.getClassLoader()
//傳入對象實現了哪些接口的字節碼對象userService.getClass().getInterfaces()
new InvocationHandler(){//invoke方法參數Object proxy , Method method , Object[] args
try{
//開啓事務
//對目標對象的方法進行加強
Object result = method.invoke(userService,args);
//提交事務
}回滾事務...歸還鏈接
return result;
}
return proxy;
}
xxxxxxxxxx
測試類:
public void show(){
//其餘代碼省略,請看上方
//使用工廠對象獲取對象
UserService service =(UserService) ac.getBean("userService");
//生成代理對象
Object proxyObj= JdkProxy.getProxy(userService);
//強轉
UserService proxy = (UserService) proxyObj;
//調用代理對象方法(進行保存到數據庫)
proxy.save(user1,user2);
}
範例:
xxxxxxxxxx
業務層;
//DI依賴注入Dao
UserDaoImpl dao;
public void setDao(UserDaoImpl dao) {
this.dao=dao;
}
/**
* 保存2個帳戶
* @param user1
* @param user2
*/
public void save(User user1, User user2) throws SQLException {
//開啓事務:使用第二種方法「線程綁定」+Jdk動態代理
dao.save(user1);
int i = 100/0;
dao.save(user2);
}
測試類;
public void show() throws SQLException {
//加載配置文件,建立工廠
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//使用工廠對象獲取對象
UserService service =(UserService) ac.getBean("userService");
//建立用戶
User user1 = new User("熊大",1000);
User user2 = new User("熊二",2000);
//生成代理對象
Object proxyObj=JdkProxy.getProxy(service);
//強轉成Service
UserService proxy = (UserService)proxyObj;
//使用代理對象進行保存數據
proxy.save(user1,user2);
}
jdk動態代理類事務管理: JdkProxy.java
寫完以上代碼,又發現一個問題,使用動態代理模式很是繁瑣,若是還要給其餘方法加強,好比:事務管理,日誌的統計,日誌的記錄
因此就可使用SpringAOP這個技術,他能幹什麼: "能夠直接對某個方法進行加強,不用你去繁瑣的寫方法加強"
還有一個問題:動態代理只能加強接口中的方法,沒有接口,還不能加強...
增長方法,就不用本身寫代理,能夠對某些方法某些個方法進行加強
什麼是AOP的技術?
在軟件業,AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程
AOP:面向切面編程.(思想--解決OOP遇到一些問題)
AOP採起橫向抽取機制,取代了傳統縱向繼承體系重複性代碼(性能監視、事務管理、安全檢查、緩存)
爲何要學習AOP,能夠在不修改源代碼的前提下,對程序進行加強! !
總結一句話:AOP能夠在不修改源代碼的狀況下,"對某些方法,某些程序進行加強"
優點:
AOP底層實現原理:
底層使用的就是代理技術:
爲何Spring框架底層會提供多個代理技術呢?
Spring框架會自動作一個選擇,當你的程序有沒有接口,默認有:就會用JDK方式加強,若是不是JDK就會使用CGL方式加強
Joinpoint(鏈接點)所謂鏈接點是指那些被攔截到的點。在spring中,這些點指的是方法,由於spring只支持方法類型的鏈接點
Pointcut(切入點) -所謂切入點是指咱們要對哪些oinpoint進行攔截的定義
Advice(通知/加強)--所謂通知是指攔截到Joinpoint以後所要作的事情就是通知.通知分爲前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
Target(目標對象)--代理的目標對象
Weaving(織入)--是指把加強應用到目標對象來建立新的代理對象的過程
Proxy (代理) - -個類被AOP織入加強後,就產生一個結果代理類
Aspect(切面)--是切入點和通知的結合,之後我們本身來編寫和配置的
作AOP開發,編寫的內容
需求: 業務層對save方法進行加強(不改變代碼對本來打印一條語句改成兩條)
步驟:
導入新的座標(jar包)
xxxxxxxxxx
<!-- AOP聯盟 -->
aopalliance 版本1.0
<!-- aspectj -->
aspectjweaver 版本1.8.3
<!-- spring整合 -->
spring-aspects 版本5.0.2.ReLEASE
引入AOP的XML的名稱空間
xxxxxxxxxx
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
編寫新的類(切面類MyXMLAspect)
xxxxxxxxxx
/**
* 自定義切面類 = 切入點(表達式) + 通知組成(加強代碼)
*/
public class MyXMlAspect{
//通知
public void log(){
//發送郵件/事務管理/記錄日誌
sout("加強方法執行了");
}
}
打開Spring核心配置文件applicationContext.xml
xxxxxxxxxx
<!--配置切面類,把該類交給IOC容器管理-->
<bean id="xmlAspect" class="...MyXmlAspect"></bean>
<!--配置AOP的加強-->
<aop:config>
<!--用上面的引用id配置切面 = 切入點 + 通知組成-->
<aop:aspect ref="xmlAspect">
<!--前置通知: UserServiceImpl的save方法執行前,會加強-->
<aop:before method="寫切面類通知的方法" pointcut="切入點的表達式execution(public void cn.dong.service.UserServiceImpl.save())"/>
</aop:aspect>
</aop:config>
在配置切入點的時候,須要定義表達式,具體以下:
切入點表達式的格式以下:
execution[修飾符] 返回值類型 包名.類名.方法名(參數)
修飾符能夠省略不寫,不是必需要出現的
返回值類型是不能省略不寫的,根據你的方法來編寫返回值。可使用 「 * 」 替代。
包名例如:cn.dong.dao.UserDaoImpl
類名也可使用 * 號代替,也有相似的寫法:*UserDaoImpl
方法也可使用 * 號代替
參數若是是一個可使用 * 號代替,若是想表明任意參數使用 ..
xxxxxxxxxx
<aop:before method="切面類方法" phintcut="切入點表達式"/>
<!--
切入點的表達式
execution(描述想對哪一個類的方法進行加強) 固定寫法
[public] 修飾符(能夠不寫)
void返回值 () * (推薦使用* = 支持返回任意值)
包名+類名 * (所有類或包下的類都加強) 或者類名首位* = (*UserDao)以他開頭
方法 * 也可使用*開頭或者結尾
參數(int,String)或..(推薦使用) 表示任意類型的和個數的參數 = Object..
通用表達式:execution(public * cn.dong.*.*UserDao.*(..))
注意:加強方法首先找類,找不到不加強方法"並不會報錯,包括返回值填錯和參數"
-->
環繞通知: 目標方法執行先後,均可以進行加強,目標對象的方法須要手動執行
<aop:around method="..." pointcut="..." />
直接使用的問題: 目標對象的方法沒有執行,須要手動執行目標對象的方法
在切面類的環繞通知方法增長參數,"ProceedingJoinPoint point"
point.procedd(); //讓目標對象的方法去執行 (優勢:這個方法寫在這個位置,以前以後,能夠去完成其餘操做,這個方法自動會拋出異常,也能夠利用異常均可以加強)
xxxxxxxxxx
總結: 前四個通知能夠一塊兒使用,環繞通知能夠單獨使用,就能夠完成事務管理
配置文件+註解方式
搭建IOC環境...
搭建AOP環境步驟:
編寫切面類,增長通知方法
@Compoent 把切面類交給IOC容器進行管理
@Aspect //聲明切面類 == <aop:aspect ref="myXmlAspect">
在log通知方法上增長註解:切入點的表達式
開啓AOP自動代理(在Spring核心配置文件配置)
開啓AOP的自動代理 換成 配置類
xxxxxxxxxx
//配置類
value = "掃描下包名") // 掃描包 (
//開啓自動代理 == (aop:aspectj-autoproxy) />
public class SpringConfig(){}
execution(public * cn.dong..UserDao.*(..))
建立一個配置類,增長如下註解
建立切面類增長如下註解:
若是不玩純註解配置文件增長如下代碼:
總結一句話:AOP能夠在不修改源代碼的狀況下,"對某些方法,某些程序進行加強"
需求:查詢數據庫的所有用戶信息,使用純註解方式
xxxxxxxxxx
測試類;
value=SpringJUnit4ClassRunner.class)//運行單元測試 (
classes=SpringConfig.class)//掃描配置類 (
public class Test {
//自動裝配到IOC容器管理
private UserService service;
junit.Test .
public void show(){
service.findAll();
}
}
xxxxxxxxxx
userServiceImpl實現類;
public class UserServiceImpl implements UserService {
/**
* 獲取Dao持久層
*/
UserDaoImpl dao;
/**
* 查詢所有用戶信息
* @return
*/
public List<User> findAll() {
System.out.println(dao.findAll());
return dao.findAll();
}
}
xxxxxxxxxx
spring配置類;
//聲明當前是一個配置類
value="cn.dong") //配置掃描的包 (
//開啓自動代理
/**
* Spring配置類
*/
public class SpringConfig {
}
xxxxxxxxxx
Dao實現類;
/**
* 持久層
*/
public class UserDaoImpl implements UserDao {
/**
* 獲取JdbcTemplate對象
*/
public JdbcTemplate template() {
//獲取JdbcTemplate對象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
return template;
}
/**
* 查詢全部用戶
* @return
*/
public List<User> findAll() {
//寫sql語句
String sql="select * from user ";
return template().query(sql, new BeanPropertyRowMapper<User>(User.class));
}
}
xxxxxxxxxx
切面類(加強方法);
/**
* 自定義切面類 並聲明切面類將切面類交給IOC容器管理
*/
public class MyXmlAspect {
/**
*後置通知
*/
"execution(public * cn.dong.service.UserService.findAll(..))") (
public void log(){
System.out.println("查詢了用戶,關閉了程序");
}
}
什麼模板技術: Spring框架中提供了不少持久層的模板類來簡化編程,使用模板類寫程序會變的簡單
提供了Jdbc模板,Spring框架提供的
xxxxxxxxxx
<dependencies>
<!--經過maven窗體依賴,導入依賴的jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--junit單元測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--日誌實現-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--日誌接口-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--鏈接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!--MySql驅動包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!--spring整合Junit測試jar包-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--AOP聯盟-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--aspectj-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!--spring整合-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--JDBC-->
<dependency>
<groupId>maven_repository.org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--事務-->
<dependency>
<groupId>maven_repository.org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
xxxxxxxxxx
使用new對象方式完成;
//建立鏈接池對象 Spring框架內置鏈接池對象
DriverManagerDataSource dataSource = new ...();
//設置四大參數 數據庫 帳號 密碼 包+類
...
//建立對象,提供模板
JdbcTempate template = new JdbcTemplate(鏈接池對象);
建立對象,提供模板
方法
xxxxxxxxxx
SpringIOC方式編寫程序;
Spring配置文件配置鏈接池和模板;
<!--配置鏈接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource .DriverManagerDataSource>
<property name="driverClassName" value= "..." />
<property name= "url" value= "..." />
<property name= "username" value="..." />
<property name=" password" value="..." />
</bean>
<!--配置jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean>
xxxxxxxxxx
測試方法;
SpringJunit4ClassRunner.class) (
value = "classpath:applicationContext.xml") (
private JdbcTemplate jdbcTemplate;
public void run1(){
....
}
配置開源的鏈接池,使用Druid開源的鏈接池,引入座標 druid (德洛依)
druid屬性配置文件: druid.properties
xxxxxxxxxx
第一種方式;
<!--引入外部屬性文件-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfiggurer">
<property name="location" value="classpath:druid.properties"/>
</bean>
第二種方式;
<context:property-placeholder location="classpath:druid.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource .DriverManagerDataSource>
<property name="driverClassName" value= "${配置文件的key}" />
<property name= "url" value= "${...}" />
<property name= "username" value="${...}" />
<property name=" password" value="${...}" />
</bean>
修改
xxxxxxxxxx
public void show2(){
int i=template.update("update user set name = ?,money = ? where id = ?", "光頭強", 10, 16);
System.out.println(i);
}
刪除
xxxxxxxxxx
public void show3(){
template.update("delete from user where id = ?",16);
}
查詢: 根據主鍵查詢數據
xxxxxxxxxx
//queryForObject("sql語句",RowMapper<T>實體類封裝查詢數據 , Obect..數據)
User user = jdbcTemplate.queryForObject("select * from user where id=?",new BeanMapper());
//新建實體類,用來進行數據封裝的 實現RowMapper<T要封裝的類型>{
class BeanMapper implements RowMapper<Account>{
//建立user對象
User user = new User();
//封裝數據
account.setId(resultSer.getInt("數據庫對應的值id"));
account.setName(resultSer.getInt("數據庫對應的值name"));
account.setMoney(resultSer.getInt("數據庫對應的值money"));
reretn user;
}
}
查詢:查詢所有()
//queryForObject("sql語句",RowMapper<T>實體類封裝查詢數據 , Obect..數據)
User user = jdbcTemplate.queryForObject("select * from user",new BeanMapper());
xxxxxxxxxx
/**
* 根據主鍵查詢用戶信息
*/
public void show3(){
User user=template.queryForObject("select * from user where id = ?", new BeanPropertyRowMapper<User>(User.class),1);
System.out.println(user);
}
/**
* 查詢所有用戶信息
*/
public void show4(){
List<User> list=template.query("select * from user", new BeanPropertyRowMapper<User>(User.class));
System.out.println(list);
}
業務層: 轉帳方法,三個參數: ont付款人 in收款人 money金額
持久層: 付款 收款 2個方法 各爲2個參數
xxxxxxxxxx
測試類;
private UserService service;
public void show(){
service.pay(2,1,500);
}
業務層;
public class UserServiceImpl implements UserService {
//獲取dao
private UserDao dao;
public void setDao(UserDao dao) {
this.dao=dao;
}
public void pay(int out, int in, int money) {
//收錢
dao.inMoney(in,money);
//給錢
dao.outMoney(out,money);
}
}
持久層;
/**
* 獲取IOC容器中的JdbcTemplate對象
*/
private JdbcTemplate template;
public void setTemplate(JdbcTemplate template) {
this.template=template;
}
/**
* 發款
* @param out
* @param money
*/
public void outMoney(int out, int money) {
template.update("update user set money = money - ? where id = ?",money,out);
}
/**
* 收款
* @param in
* @param money
*/
public void inMoney(int in, int money) {
template.update("update user set money = money + ? where id = ?",money,in);
}
發現了一個問題 , 持久層的JdbcTemplate的模板 成員屬性還有set方法,
每一次有個新的dao類,就得寫一次jdbc模板和set方法,太繁瑣,太麻煩 ,
這時候能夠定義一個父類,把模板寫到父類當中 ,
可是我們不用管,Spring框架已經幫忙寫好了直接繼承就好
xxxxxxxxxx
public void outMoney(int out, int money) {
this.getJdbcTemplate().update("update user set money = money - ? where id = ?",money,out);
}
xxxxxxxxxx
配置文件;
模板類能夠不用配置
在配置dao時,直接依賴注入鏈接池
<bean id="userDao" class="cn.dong.dao.UserDaoImpl">
<property name="別名" ref="鏈接池引入id(別名)"/>
</bean>
範例:
xxxxxxxxxx
/**
* 收款
* @param in
* @param money
*/
public void inMoney(int in, int money) {
this.getJdbcTemplate().update("update user set money = money + ? where id = ?",money,in);
}
<!--引入外部屬性文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--配置Druid鏈接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="root" />
<property name="password" value="${password}" />
</bean>
<!--配置實體類加載到IOC容器-->
<bean id="service" class="cn.dong.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<bean id="dao" class="cn.dong.dao.impl.UserDaoImpl" >
<!--依賴注入鏈接池-->
<property name="dataSource" ref="dataSource" />
</bean>;
xxxxxxxxxx
1. PlatformTransactionManager接口 -- 平臺事務管理器.(真正管理事務的類)。該接口有具體的實現類,根據不一樣的持久層框架,須要選擇不一樣的實現類!
2. TransactionDefinition接口 -- 事務定義信息.(事務的隔離級別,傳播行爲,超時,只讀)
3. TransactionStatus接口 -- 事務的狀態
4. 總結:上述對象之間的關係:平臺事務管理器真正管理事務對象.根據事務定義的信息TransactionDefinition 進行事務管理,在管理事務中產生一些狀態.將狀態記錄到TransactionStatus中
5. PlatformTransactionManager接口中實現類和經常使用的方法
1. 接口的實現類
* 若是使用的Spring的JDBC模板或者MyBatis框架,須要選擇DataSourceTransactionManager實現類
* 若是使用的是Hibernate的框架,須要選擇HibernateTransactionManager實現類
2. 該接口的經常使用方法
* void commit(TransactionStatus status)
* TransactionStatus getTransaction(TransactionDefinition definition)
* void rollback(TransactionStatus status)
6. TransactionDefinition
1. 事務隔離級別的常量
* static int ISOLATION_DEFAULT -- 採用數據庫的默認隔離級別
* static int ISOLATION_READ_UNCOMMITTED
* static int ISOLATION_READ_COMMITTED
* static int ISOLATION_REPEATABLE_READ
* static int ISOLATION_SERIALIZABLE
2. 事務的傳播行爲常量(不用設置,使用默認值)
* 先解釋什麼是事務的傳播行爲:解決的是業務層之間的方法調用!!
* PROPAGATION_REQUIRED(默認值) -- A中有事務,使用A中的事務.若是沒有,B就會開啓一個新的事務,將A包含進來.(保證A,B在同一個事務中),默認值!!
* PROPAGATION_SUPPORTS -- A中有事務,使用A中的事務.若是A中沒有事務.那麼B也不使用事務.
* PROPAGATION_MANDATORY -- A中有事務,使用A中的事務.若是A沒有事務.拋出異常.
* PROPAGATION_REQUIRES_NEW(記)-- A中有事務,將A中的事務掛起.B建立一個新的事務.(保證A,B沒有在一個事務中)
* PROPAGATION_NOT_SUPPORTED -- A中有事務,將A中的事務掛起.
* PROPAGATION_NEVER -- A中有事務,拋出異常.
* PROPAGATION_NESTED(記) -- 嵌套事務.當A執行以後,就會在這個位置設置一個保存點.若是B沒有問題.執行經過.若是B出現異常,運行客戶根據需求回滾(選擇回滾到保存點或者是最初始狀態)
TransactionDefinition接口事務的傳播行爲: 解決業務層方法相互調用,事務傳播問題 (使用默認值)
步驟一: 配置平臺事務管理器
xxxxxxxxxx
<!--配置平臺事務管理器-->
<bean id="transactionMavager" class="DataSourceTransactionMavager">
<!--依賴注入鏈接池-->
...
</bean>
步驟二: 配置平臺事務通知
xxxxxxxxxx
<!--引入tx名稱空間-->
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
<!--配置平臺事務通知(沒有本身編寫切面類,通知方法也是很多本身編寫的,Spring框架提供的)-->
<tx:advice id="txAdvisor" transaction-manager="transactionManager">
<!--對方法進行加強,設置隔離級別,傳播行爲,超時的時間-->
<tx:mehod name="方法名" isolation="DEFAULT默認" propagation="REQUIRED默認" read-only="是不是隻讀的事務(查詢的時候能夠設置爲只讀) timeout="事務超時時間(-1永久)"/><tx:mehod name="方法名"/><!--能夠配置多個--?
</tx:advice>
步驟三: 配置AOP的加強 (Spring框架提供的系統通知)
xxxxxxxxxx
<!--配置AOP的加強-->
<aop:config>
<!--Spring框架提供的系統通知,使用advisor標籤-->
<aop:advisor advice-ref="txAdvice事務通知id" pointcut="execution(public * 包名+類名+方法名(..))" />
</aop:config>
範例:
xxxxxxxxxx
<!--引入外部屬性文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--配置Druid鏈接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="root" />
<property name="password" value="${password}" />
</bean>
<!--配置實體類加載到IOC容器-->
<bean id="service" class="cn.dong.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<bean id="dao" class="cn.dong.dao.impl.UserDaoImpl" >
<!--依賴注入鏈接池-->
<property name="dataSource" ref="dataSource" />
</bean>
<!--配置平臺事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--依賴注入鏈接池-->
<property name="dataSource" ref="dataSource" />
</bean>
<!--配置平臺事務通知-->
<tx:advice id="txAdvisor" transaction-manager="transactionManager">
<!--對方法進行加強,設置隔離級別,傳播行爲,超時時間...-->
<tx:attributes>
<tx:method name="pay" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>
</tx:attributes>
</tx:advice>
<!--配置AOP的加強-->
<aop:config>
<!--Spring框架提供的系統通知,使用advisor標籤-->
<aop:advisor advice-ref="txAdvisor" pointcut="execution(public * cn.dong.service.impl.UserServiceImpl.pay(..))" />
</aop:config>
配置文件能夠更改的地方有: 配置事務的通知 , 和配置AOP的加強(這些均可以省略不寫使用註解代替)
步驟一: 開啓註解的掃描
xxxxxxxxxx
在Spring配置開啓註解的掃描
<context:component-scan base-package="xn.dong"/>
給持久層和業務層增長註解,把類交給IOC容器進行管理
在業務層 依賴注入dao 使用@Autowired註解
持久層依賴注入 jdbcTemplate (但在以前先在配置文件中將jdbcTemplate放到IOC容器管理)
開啓事務對註解的支持
<tx:annotation-driven transaction-mavager="transactionManager" />
在Service增長註解@Transactional = 對Service的全部方法進行事務管理 也能夠增長到方法中 對當前方法進行事務管理
@Transactional(isolation = Isolation.DEFAULT) //設置隔離級別 (能夠點進註解查看屬性)
範例:
xxxxxxxxxx
<!--引入外部屬性文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<!--配置Druid鏈接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="root" />
<property name="password" value="${password}" />
</bean>
<!--註解掃描-->
<context:component-scan base-package="cn.dong" />
<!--加載到IOC容器管理-->
<bean id="template" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" />
</bean>
<!--開啓事務對註解的支持-->
<tx:annotation-driven transaction-manager="transactionManager" />
<!--配置平臺事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--依賴注入鏈接池-->
<property name="dataSource" ref="dataSource" />
</bean>
dao; ("dao")
private JdbcTemplate template;
service; ("service")
private UserDao dao;
xxxxxxxxxx
建立配置類,
掃描包
鏈接池
使用@Bean 註解 //把鏈接池保存到IOC容器中
模板對象
使用@Bean //把JdbcTemplate保存到IOC容器中
@Resource //不只能夠做用在屬性上,也能夠做用在方法上
平臺事務管理器
使用@Bean //把JdbcTemplate保存到IOC容器中
@Resource //不只能夠做用在屬性上,也能夠做用在方法上
開啓事務註解
@EnableTransactionManagement //開啓事務註解
範例:
xxxxxxxxxx
配置類;
/**
* Spring配置類
*/
//聲明配置類
value="cn.dong") //掃描包 (
public class SpringConfig {
/**
* 建立鏈接池對象
*/
"dataSource") (
public DataSource dataSource(){
//建立鏈接池對象,Spring框架內置了鏈接池
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//設置四個參數
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai");
dataSource.setUsername("root");
dataSource.setPassword("accp");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
return dataSource;
}
/**
* 建立Spring模板的JdbcTemplate對象
* @return
*/
name="dataSource") (
public JdbcTemplate jdbcTemplate(){
//建立JdbcTemplate對象
JdbcTemplate template=new JdbcTemplate();
//存放鏈接到JdbcTemplate
template.setDataSource(dataSource());
return template;
}
/**
* 建立平臺事務管理對象
* @return
*/
name="dataSource") (
public PlatformTransactionManager createTransactionManager(){
DataSourceTransactionManager manager = new DataSourceTransactionManager(dataSource());
return manager;
}
}
"service") (
isolation=Isolation.DEFAULT) //對此類中全部方法都增長事務管理 (
public class UserServiceImpl implements UserService {
//獲取dao
private UserDao dao;
public void pay(int out, int in, int money) {
//收錢
dao.inMoney(in,money);
int i = 100/0;
//給錢
dao.outMoney(out,money);
}
}
測試類;
SpringJUnit4ClassRunner.class) (
classes=SpringConfig.class) (
public class Demo {
private UserService service;
public void show(){
service.pay(2,1,100);
}
}