前言
最近感觸頗深,原諒我在開頭寫心情日記。介意的跳過看正文。
市場
趨勢
近幾年,技術市場對新人越來越不友好,社招幾乎是三年經驗起步。所以很多人都說能走校招千萬別走社招,年初我企圖走社招,然后絕望了 = =。。
原因
原因也很簡單,前幾年行業火爆,吸引了大批人轉行,另外加上培訓班不負責的廣告,造成現在一些方向人滿為患。
選擇
現實很殘酷,選擇比努力重要,轉方向并非本意,但看趨勢,不轉方向我就得轉行了。
行情
今天看了一下 18屆的實習招,發現大部分要求還是挺高的(吐槽一下能力堪比熟練工,工資媲美清潔工),比如 java 后端,都是要有項目經驗,熟練使用各大框架,嚇得我簡歷都不敢投(沒有四五個項目經驗,估計投了也沒戲)。
經歷
現狀
想想當初跟大流,選錯方向還是挺悲哀的。假如安卓的現在未飽和,我參加實習招校招估計對很多人來說就是開掛了,從現在工作狀態來說,基本在公司沒學到什么東西,大部分需求都是 1 + 1,干的不比正式工少。(工資君:是不是考慮一下清潔工崗位)
要是質疑我的編碼能力,不妨看看我的 github(id=ittianyu) 的 star、blog的質量。
現實
然而事實是,即便是我這樣的熟練工種,在安卓實習招上也是被公司各種挑,要么嫌我是 18 屆的,要么覺得我學校不行,甚至還有985光環 + 神級大牛 跟我搶飯碗。。
感觸
記得以前在 csdn 上寫博客,一些人誤以為我是工作多年的老司機,那個時候還暗自高興覺得找工作對我來說就和收割羊毛一樣簡單,然而我現在很絕望,總感覺學生被貼上了 “不行” 的標簽,技術面還好說,有些 HR 給我的感覺是,我技術還不如他,給我 2k 都太多了。(原諒我不是個強勢的人,害怕起爭執)
絕望&希望
絕望并沒有用,還是抓緊每一秒,多學習多練習,希望趕得上秋招。
目錄
- 環境搭建
- 入門
- 配置詳解
- AOP
- JDBCTemplate
- 事務
- 整合 Web 和 Junit
- SSH 整合
正文
1. 環境搭建
這里介紹的是 Spring Framework。
導包
根據需要選擇手動導入 jar 包,或者用依賴管理工具。
- 下載
官網目前好像沒提供直接下載,可以去 maven 倉庫下載 - Gradle
列舉了一些常用的,更多詳情參考 官網dependencies { // 核心包 compile 'org.springframework:spring-context:4.3.8.RELEASE' // 可選包 compile 'org.springframework:spring-tx:4.3.8.RELEASE' compile 'org.springframework:spring-web:4.3.8.RELEASE' compile 'org.springframework:spring-orm:4.3.8.RELEASE' compile 'org.springframework:spring-aspects:4.3.8.RELEASE' compile 'org.springframework:spring-test:4.3.8.RELEASE' }
2. 入門
IOC
定義
控制反轉(Inverse of Control):對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象的引用傳遞給它。
這里是指將對象創建的任務交給 Spring 來做。
Demo
com/ittianyu/spring/a_ioc/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.xsd">
<bean id="UserDao" class="com.ittianyu.spring.a_base.z_common.dao.impl.UserDaoImpl"/>
</beans>
com.ittianyu.spring.a_base.a_ioc.TestClass
public class TestClass {
@Test
public void helloIOC() {
String xmlPath = "com/ittianyu/spring/a_ioc/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 通過 spring 創建 dao
UserDao userDao = (UserDao) applicationContext.getBean("UserDao");
userDao.save(new User("hello spring !"));
}
}
DI
定義
依賴注入(Dependency Injection,簡稱DI):在程序運行過程中,客戶類不直接實例化具體服務類實例,而是客戶類的運行上下文環境或專門組件負責實例化服務類,然后將其注入到客戶類中,保證客戶類的正常運行。
在這里指的是 要創建的對象中的成員變量由 Spring 進行 set。
Demo
com/ittianyu/spring/b_di/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.xsd">
<bean id="UserService" class="com.ittianyu.spring.a_base.z_common.service.impl.UserServiceImpl">
<!-- 依賴注入 DI:在創建 service 時,需要設置 service 所依賴的 dao 實現 -->
<property name="userDao" ref="UserDao"/>
</bean>
<bean id="UserDao" class="com.ittianyu.spring.a_base.z_common.dao.impl.UserDaoImpl"/>
</beans>
com.ittianyu.spring.a_base.b_di.TestClass
public class TestClass {
@Test
public void helloDI() {
String xmlPath = "com/ittianyu/spring/b_di/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 通過 spring 創建 service
UserService userService = (UserService) applicationContext.getBean("UserService");
userService.addUser(new User("hello spring !"));
}
}
3. 配置詳解
實例化方式
默認構造、靜態工廠、實例工廠
默認構造
通過默認構造方法實例化對象
<bean id="" class="">
靜態工廠
通過工廠的靜態方法實例化對象
<bean id="" class="工廠全類名" factory-method="靜態方法">
工廠
通過工廠的普通方法實例化對象
<!-- 1. 創建工廠實例 -->
<bean id="myBeanFactory" class="com.xxx.MyBeanFactory"></bean>
<!-- 2. 通過工廠實例創建對象 userservice
* factory-bean 指定工廠實例
* factory-method 指定創建方法
-->
<bean id="userService" factory-bean="myBeanFactory"
factory-method="createService"></bean>
Bean 種類
- 普通 bean:通過默認構造直接創建的 bean
- FactoryBean:具有工廠生產對象能力的 bean,只能生成特定的對象。
bean 必須使用 FactoryBean接口,此接口提供方法getObject()
用于獲得特定 bean。
<bean id="" class="FB">
先創建FB實例,使用調用 getObject() 方法,并返回方法的返回值FB fb = new FB(); return fb.getObject();
- BeanFactory 和 FactoryBean 對比?
- BeanFactory:工廠,用于生成任意bean。
- FactoryBean:特殊bean,用于生成另一個特定的bean。 例如:ProxyFactoryBean ,此工廠bean用于生產代理。<bean id="" class="....ProxyFactoryBean"> 獲得代理對象實例。AOP使用
作用域
類別 | 說明 |
---|---|
singleton | Spring IOC 容器中僅存在一份 bean 實例 |
prototype | 每次都創建新的實例 |
request | 一次 http 請求創建一個新的 bean,僅適用于 WebApplicationContext |
session | 一個 session 對應一個 bean 實例,僅適用于 WebApplicationContext |
globalSession | 一般用于 Portlet 應用環境,作用域僅適用于 WebApplicationContext 環境 |
scope 為作用域
<bean id="" class="" scope="">
生命周期
初始化和銷毀
目標方法執行前后執行的方法
<bean id="" class="" init-method="初始化方法" destroy-method="銷毀方法">
例子:
com.ittianyu.spring.a_base.e_lifecycle.UserServiceImpl
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
System.out.println("addUser");
}
// 在 xml 中配置聲明周期方法
public void onInit() {
System.out.println("onInit");
}
// 銷毀方法只有滿足 1.容器 close 2. 必須是單例
public void onDestroy() {
System.out.println("onDestroy");
}
}
配置:
com/ittianyu/spring/a_base/e_lifecycle/applicationContext.xml
...
<!-- 注冊 初始化和銷毀方法 -->
<bean id="UserService" class="com.ittianyu.spring.a_base.e_lifecycle.UserServiceImpl"
init-method="onInit" destroy-method="onDestroy" />
...
測試:
com.ittianyu.spring.a_base.e_lifecycle.TestClass
public class TestClass {
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/e_lifecycle/applicationContext.xml";
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 通過 spring 生成工廠 調用 工廠方法 生成對象
UserService userService = applicationContext.getBean("UserService", UserService.class);
userService.addUser();
// 關閉容器才會調用 銷毀的方法
applicationContext.close();
}
}
BeanPostProcessor
只要實現此接口BeanPostProcessor,并配置此 bean,則在所有初始化方法前執行 before()
,在初始化方法之后執行 after()
。
例子:
com.ittianyu.spring.a_base.e_lifecycle.MyBeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {
// 不在 before 使用代理因為 jdk 的代理是面向接口,而 init 和 destroy 方法是 實現類的
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("after");
// 在 after 中生成 代理對象,在執行方法前后開啟和關閉事務
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("開始事務");
Object result = method.invoke(bean, args);
System.out.println("關閉事務");
return result;
}
});
return proxy;
}
}
com/ittianyu/spring/a_base/e_lifecycle/applicationContext.xml
...
<!--注冊 初始化 前后回調-->
<bean class="com.ittianyu.spring.a_base.e_lifecycle.MyBeanPostProcessor" />
...
屬性注入
注入方式
- 手動裝配:一般進行配置信息都采用手動
- 基于xml裝配:構造方法、setter方法
- 基于注解裝配
- 自動裝配:struts 和 spring 整合可以自動裝配
- byType:按類型裝配
- byName:按名稱裝配
- constructor:構造裝配
- auto: 不確定裝配
構造注入
實體類
public class User {
private Integer id;
private String username;
private Integer age;
public User(Integer id, String username) {
this.id = id;
this.username = username;
}
// 省略 get set...
}
配置
...
<!--
基于 name 配置構造參數,不常用
-->
<!-- <bean id="user" class="com.ittianyu.spring.a_base.f_xml.a_constructor.User">
<constructor-arg name="username" value="name"/>
<constructor-arg name="age" value="1"/>
</bean>-->
<!--
基于 index 和 type 方式
如果不指定 type,可能匹配到多個符合條件的構造方法,默認使用位置在前面的那個
-->
<bean id="User" class="com.ittianyu.spring.a_base.f_xml.a_constructor.User">
<constructor-arg index="0" type="java.lang.Integer" value="1"/>
<constructor-arg index="1" type="java.lang.String" value="hello"/>
</bean>
...
set 注入
實體類省略
...
<!--
利用 setter 方法進行參數注入
property 的值可以利用 內嵌標簽來完成,但一般很少用
-->
<bean id="Person" class="com.ittianyu.spring.a_base.f_xml.b_setter.Person">
<property name="name" value="Jone" />
<property name="age">
<value>18</value>
</property>
<property name="oldCar" ref="OldCar"/>
<property name="newCar">
<ref bean="NewCar"/>
</property>
</bean>
<bean id="OldCar" class="com.ittianyu.spring.a_base.f_xml.b_setter.Car">
<property name="name" value="拖拉機"/>
<property name="price" value="5000.0"/>
</bean>
<bean id="NewCar" class="com.ittianyu.spring.a_base.f_xml.b_setter.Car">
<property name="name" value="賓利"/>
<property name="price" value="5000000.0"/>
</bean>
...
P
對 "set 注入" 簡化,使用:
<bean p:屬性名="普通值" p:屬性名-ref="引用值">
替換
<property name="" value=""/>
必須添加 p 命名空間
<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.xsd">
例子:
...
<!--
利用 setter 方法進行參數注入
在上面要加入 xmlns:p="http://www.springframework.org/schema/p" (從 beans 行復制修改而來)
使用 p 簡化 setter 方法
-->
<bean id="Person" class="com.ittianyu.spring.a_base.f_xml.b_setter.Person"
p:name="Jone" p:age="18"
p:oldCar-ref="OldCar" p:newCar-ref="NewCar">
</bean>
<bean id="OldCar" class="com.ittianyu.spring.a_base.f_xml.b_setter.Car"
p:name="拖拉機" p:price="5000.0">
</bean>
<bean id="NewCar" class="com.ittianyu.spring.a_base.f_xml.b_setter.Car"
p:name="賓利" p:price="5000000.0">
</bean>
...
SpEL
對 <property>
進行統一編程,所有的內容都使用 value
<property name="" value="#{表達式}">
#{123}、#{'jack'}: 數字、字符串
#{beanId}:另一個bean引用
#{beanId.propName}:操作數據
#{beanId.toString()}:執行方法
#{T(類).字段|方法}:靜態方法或字段
例子:
<!--
利用 setter 方法進行參數注入
使用 SPEL 表達式 #{} 為固定格式
字符串用 ''
數字直接寫
名稱表示引用
靜態方法調用 T(Class).method()
-->
<bean id="Person" class="com.ittianyu.spring.a_base.f_xml.b_setter.Person">
<property name="name" value="#{'Jone'}" />
<property name="age" value="#{18}" />
<property name="oldCar" value="#{OldCar}"/>
<property name="newCar" value="#{NewCar}"/>
</bean>
<bean id="OldCar" class="com.ittianyu.spring.a_base.f_xml.b_setter.Car">
<property name="name" value="#{'拖拉機'}"/>
<property name="price" value="#{T(java.lang.Math).random() * 1000 + 5000}"/>
</bean>
<bean id="NewCar" class="com.ittianyu.spring.a_base.f_xml.b_setter.Car">
<property name="name" value="#{'賓利'}"/>
<property name="price" value="#{OldCar.price * 1000}"/>
</bean>
集合注入
<!--
各種集合類型的注入配置
數組:<array>
List:<list>
Set:<set>
Map:<map>, map 存放鍵值對,使用 <entry> 描述
Properties:<props> <prop key=""></prop>
-->
<bean id="Collection" class="com.ittianyu.spring.a_base.f_xml.e_collection.Collection">
<property name="array">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
<property name="list">
<list>
<value>l1</value>
<value>l2</value>
<value>l3</value>
</list>
</property>
<property name="map">
<map>
<entry key="1" value="m1"/>
<entry key="2" value="m2"/>
<entry key="3" value="m3"/>
</map>
</property>
<property name="set">
<set>
<value>s1</value>
<value>s2</value>
<value>s3</value>
</set>
</property>
<property name="properties">
<props>
<prop key="1">p1</prop>
<prop key="2">p2</prop>
<prop key="3">p3</prop>
</props>
</property>
</bean>
注解
類型
-
@Component
取代<bean class="">
@Component("id")
取代<bean id="" class="">
- web開發,提供3個
@Component
衍生注解(功能一樣)取代<bean class="">
- @Repository:dao 層
- @Service:service 層
- @Controller:web 層
- 依賴注入,給私有字段設置,也可以給 setter 方法設置
普通值:@Value("")
引用值:- 方式1:按照【類型】注入
@Autowired
- 方式2:按照【名稱】注入1
@Autowired
@Qualifier("名稱")
- 方式3:按照【名稱】注入2
@Resource("名稱")
- 方式1:按照【類型】注入
- 生命周期
- 初始化:
@PostConstruct
- 銷毀:
@PreDestroy
- 初始化:
- 作用域
@Scope("prototype")
配置
需要配置自動掃描才能使注解生效
<?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:component-scan base-package="com.ittianyu.spring.a_base.g_annotation.a_ioc" />
</beans>
4. AOP
簡介
定義
面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。
優點
利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
原理
aop底層將采用代理機制進行實現。
- 接口 + 實現類:spring 默認采用 jdk 的動態代理 Proxy。
- 實現類:spring 默認采用 cglib 字節碼增強。
術語
- target:目標類,需要被代理的類。例如:UserService
- Joinpoint:連接點,是指那些可能被攔截到的方法。例如:所有的方法
- PointCut:切入點,已經被增強的連接點。例如:addUser()
- advice: 通知/增強,增強代碼。例如:after、before
- Weaving:織入,是指把 advice 應用到 target 來創建代理對象的過程。
- proxy: 代理類
- Aspect: 切面,是切入點 pointcut 和通知 advice 的結合
一個線是一個特殊的面。
一個切入點和一個通知,組成成一個特殊的面。
APO 聯盟通知類型
AOP聯盟為通知 Advice 定義了 org.aopalliance.aop.Advice
Spring按照通知 Advice 在目標類方法的連接點位置,可以分為5類
- 前置通知
org.springframework.aop.MethodBeforeAdvice
- 在目標方法執行前實施增強
- 后置通知
org.springframework.aop.AfterReturningAdvice
- 在目標方法執行后實施增強
- 環繞通知
org.aopalliance.intercept.MethodInterceptor
- 在目標方法執行前后實施增強
- 異常拋出通知
org.springframework.aop.ThrowsAdvice
- 在方法拋出異常后實施增強
- 引介通知
org.springframework.aop.IntroductionInterceptor
在目標類中添加一些新的方法和屬性
Spring APO 編程
切面類
采用環繞通知
public class SpringTimeSpaceAspect implements Aspect, MethodInterceptor {
private long beforeTime;
@Override
public void before() {
beforeTime = System.currentTimeMillis();
System.out.println("before:" + beforeTime);
}
@Override
public void after() {
long afterTime = System.currentTimeMillis();
System.out.println("after:" + afterTime);
System.out.println("space:" + (afterTime - beforeTime));
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
before();
Object result = invocation.proceed();
after();
return result;
}
}
配置
- 導入命名空間 aop
- 使用
<aop:config>
進行配置proxy-target-class="true" true 表示底層使用 cglib 代理 <aop:pointcut> 切入點, 從目標對象獲得具體方法 <aop:advisor> 特殊的切面,只有一個通知 和 一個切入點 advice-ref 通知引用 pointcut-ref 切入點引用
- 切入點表達式
execution(* com.ittianyu.c_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: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 id="UserService" class="com.ittianyu.spring.b_aop.service.UserServiceImpl"/>
<bean id="SpringTimeSpaceAspect" class="com.ittianyu.spring.b_aop.c_spring_proxy.SpringTimeSpaceAspect"/>
<aop:config>
<aop:pointcut id="myPointCut" expression="execution(* com.ittianyu.spring.b_aop.service.*.*(..))"/>
<aop:advisor advice-ref="SpringTimeSpaceAspect" pointcut-ref="myPointCut"/>
</aop:config>
</beans>
AspectJ
介紹
- AspectJ 是一個基于 Java 語言的 AOP 框架
- Spring2.0 以后新增了對 AspectJ 切點表達式支持
-
@AspectJ
是 AspectJ1.5 新增功能,通過 JDK5 注解技術,允許直接在 Bean 類中定義切面
新版本 Spring 框架,建議使用 AspectJ 方式來開發 AOP - 主要用途:自定義開發
切入點表達式
-
execution()
用于描述方法 【掌握】
語法:execution(修飾符 返回值 包.類.方法名(參數) throws異常)
-
修飾符,一般省略
public 公共方法 * 任意
返回值,不能省略
void 返回沒有值
String 返回值字符串
* 任意包,[省略]
com.ittianyu.crm 固定包
com.ittianyu.crm..service crm包下面子包任意 (例如:com.ittianyu.crm.staff.service)
com.ittianyu.crm.. crm包下面的所有子包(含自己)
com.ittianyu.crm..service.. crm包下面任意子包,固定目錄service,service目錄任意包類,[省略]
UserServiceImpl 指定類
Impl 以Impl結尾
User 以User開頭
* 任意方法名,不能省略
addUser 固定方法
add* 以add開頭
*Do 以Do結尾
* 任意(參數)
() 無參
(int) 一個整型
(int ,int) 兩個
(..) 參數任意throws ,可省略,一般不寫。
綜合1
execution(* com.ittianyu.crm..service...*(..))綜合2
<aop:pointcut expression="execution(* com.ittianyu.WithCommit.(..)) ||
execution(* com.ittianyu.Service.(..))" id="myPointCut"/>
-
- within:匹配包或子包中的方法(了解)
within(com.ittianyu.aop..*) - this:匹配實現接口的代理對象中的方法(了解)
this(com.ittianyu.aop.user.UserDAO) - target:匹配實現接口的目標對象中的方法(了解)
target(com.ittianyu.aop.user.UserDAO) - args:匹配參數格式符合標準的方法(了解)
args(int,int) - bean(id) 對指定的bean所有的方法(了解)
bean('userServiceId')
通知類型
- before: 前置通知(應用:各種校驗)
在方法執行前執行,如果通知拋出異常,阻止方法運行 - afterReturning: 后置通知(應用:常規數據處理)
方法正常返回后執行,如果方法中拋出異常,通知無法執行
必須在方法執行后才執行,所以可以獲得方法的返回值。 - around: 環繞通知(應用:十分強大,可以做任何事情)
方法執行前后分別執行,可以阻止方法的執行
必須手動執行目標方法 - afterThrowing: 拋出異常通知(應用:包裝異常信息)
方法拋出異常后執行,如果方法沒有拋出異常,無法執行 - after: 最終通知(應用:清理現場)
方法執行完畢后執行,無論方法中是否出現異常
基于 xml Demo
實體類
public class MyAspect {
public void before(JoinPoint joinPoint) {
System.out.println("before:" + joinPoint.getSignature().getName());
}
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("after-returning:" + joinPoint.getSignature().getName() + ", result:" + result);
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around-before:" + joinPoint.getSignature().getName());
Object result = joinPoint.proceed();
System.out.println("around-after:" + joinPoint.getSignature().getName());
return result;
}
public void afterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("after-throwing:" + joinPoint.getSignature().getName() + ", exception:" + e.getMessage());
}
public void after(JoinPoint joinPoint) {
System.out.println("after:" + joinPoint.getSignature().getName());
}
}
配置
<?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 id="UserService" class="com.ittianyu.spring.b_aop.service.UserServiceImpl"/>
<bean id="MyAspect" class="com.ittianyu.spring.b_aop.d_aspect.a_xml.MyAspect"/>
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut id="myPointCut" expression="execution(* com.ittianyu.spring.b_aop.service.UserServiceImpl.*(..))" />
<!--前置通知 before
可選參數 org.aspectj.lang.JoinPoint ,主要用于獲取當前執行的方法名
-->
<aop:before method="before" pointcut-ref="myPointCut" />
<!--后置通知 after
可選參數: org.aspectj.lang.JoinPoint ,主要用于獲取當前執行的方法名
Object 切入點返回值,參數名需要用屬性 returning 指定,比如這里是 result
-->
<aop:after-returning method="afterReturning" pointcut-ref="myPointCut" returning="result" />
<!--環繞通知 around
方法簽名必須如下,要拋出異常
public Object around(ProceedingJoinPoint joinPoint) throws Throwable
中間要執行
Object result = joinPoint.proceed();
最后 return result
-->
<aop:around method="around" pointcut-ref="myPointCut" />
<!--異常通知 after-throwing
可選參數: org.aspectj.lang.JoinPoint ,主要用于獲取當前執行的方法名
Throwable 切入點返回值,參數名需要用屬性 throwing 指定,比如這里是 e
-->
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="e"/>
<!--后置通知 after
可選參數: org.aspectj.lang.JoinPoint ,主要用于獲取當前執行的方法名
-->
<aop:after method="after" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
</beans>
測試
public class TestClass {
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/b_aop/d_aspect/a_xml/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("UserService");
userService.add();
userService.delete();
userService.update();
}
}
基于注解 Demo
實體類
@Component
@Aspect
public class MyAspect {
/**
* <aop:pointcut id="myPointCut" expression="execution(* com.ittianyu.spring.b_aop.service.UserServiceImpl.*(..))" />
*/
@Pointcut(value = "execution(* com.ittianyu.spring.b_aop.d_aspect.b_annotation.UserServiceImpl.*(..))")
public void myPointcut() {
}
@Before(value = "myPointcut()")
public void before(JoinPoint joinPoint) {
System.out.println("before:" + joinPoint.getSignature().getName());
}
@AfterReturning(value = "myPointcut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("after-returning:" + joinPoint.getSignature().getName() + ", result:" + result);
}
@Around(value = "myPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around-before:" + joinPoint.getSignature().getName());
Object result = joinPoint.proceed();
System.out.println("around-after:" + joinPoint.getSignature().getName());
return result;
}
@AfterThrowing(value = "myPointcut()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("after-throwing:" + joinPoint.getSignature().getName() + ", exception:" + e.getMessage());
}
@After(value = "myPointcut()")
public void after(JoinPoint joinPoint) {
System.out.println("after:" + joinPoint.getSignature().getName());
}
}
切面類
@Service("UserService")
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("add");
}
@Override
public String delete() {
System.out.println("delete");
// int a = 1 / 0;
return "result-delete";
}
@Override
public void update() {
System.out.println("update");
}
}
配置
<?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: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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--自動掃描包下的注解-->
<context:component-scan base-package="com.ittianyu.spring.b_aop.d_aspect.b_annotation" />
<!--對 aop 注解進行處理-->
<aop:aspectj-autoproxy/>
</beans>
測試
public class TestClass {
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/b_aop/d_aspect/b_annotation/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("UserService");
userService.add();
userService.delete();
userService.update();
}
}
5. JDBCTemplate
Spring 提供用于操作JDBC工具類,類似:DBUtils。
依賴 連接池DataSource (數據源)
基本 API
可以通過代碼來設置數據源,但一般都是通過配置文件來注入
//1 創建數據源(連接池) dbcp
BasicDataSource dataSource = new BasicDataSource();
// * 基本4項
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day02");
dataSource.setUsername("root");
dataSource.setPassword("1234");
//2 創建模板
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
//3 通過api操作
jdbcTemplate.update("insert into t_user(username,password) values(?,?);", "tom","1");
配置 DBCP
<!--配置數據源-->
<bean id="DataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///myusers"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置模版-->
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="DataSource" />
</bean>
<!--配置 dao-->
<bean id="UserDao" class="com.ittianyu.spring.c_jdbc_template.dao.UserDao">
<property name="jdbcTemplate" ref="JdbcTemplate"/>
</bean>
配置 C3P0
<!--配置數據源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///myusers"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置模版-->
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="DataSource" />
</bean>
<!--配置 dao-->
<bean id="UserDao" class="com.ittianyu.spring.c_jdbc_template.dao.UserDao">
<property name="jdbcTemplate" ref="JdbcTemplate"/>
</bean>
配置 properties
properties 配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///myusers
jdbc.user=root
jdbc.password=123456
Spring 配置
<!--導入 properties-->
<context:property-placeholder location="classpath:com/ittianyu/spring/c_jdbc_template/d_properties_config/c3p0.properties" />
<!--配置數據源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
JdbcDaoSupport
Dao 繼承 JdbcDaoSupport 后,繼承了設置數據源的方法。
public final void setDataSource(DataSource dataSource)
然后自動創建 JdbcTemplate。
public class UserDao extends JdbcDaoSupport{
public void add(User user) {
String sql = "insert into user (username, password, nick) VALUES (?, ?, ?);";
Object[] args = new Object[]{user.getUsername(), user.getPassword(), user.getNick()};
getJdbcTemplate().update(sql, args);
}
}
所以,現在 Spring 配置只需要給 dao 注入數據源即可。
<!--導入 properties-->
<context:property-placeholder location="classpath:com/ittianyu/spring/c_jdbc_template/d_properties_config/c3p0.properties" />
<!--配置數據源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置 dao
繼承了 JdbcDaoSupport,直接注入數據源
-->
<bean id="UserDao" class="com.ittianyu.spring.c_jdbc_template.c_jdbc_dao_support.UserDao">
<property name="dataSource" ref="DataSource"/>
</bean>
6. 事務
Spring 中的事務有三個重要的接口。
- PlatformTransactionManager 平臺事務管理器,spring要管理事務,必須使用事務管理器,進行事務配置時,必須配置事務管理器。
- TransactionDefinition:事務詳情(事務定義、事務屬性),spring用于確定事務具體詳情,例如:
隔離級別、是否只讀、超時時間 等。
進行事務配置時,必須配置詳情。spring將配置項封裝到該對象實例。 - TransactionStatus:事務狀態,spring用于記錄當前事務運行狀態。例如:
是否有保存點,事務是否完成。
spring底層根據狀態進行相應操作。
PlatformTransactionManager
常見的事務管理器
- DataSourceTransactionManager ,jdbc開發時事務管理器,采用JdbcTemplate
- HibernateTransactionManager,hibernate開發時事務管理器,整合hibernate
Api
- TransactionStatus getTransaction(TransactionDefinition definition) ,事務管理器 通過“事務詳情”,獲得“事務狀態”,從而管理事務。
- void commit(TransactionStatus status) 根據狀態提交
- void rollback(TransactionStatus status) 根據狀態回滾
TransactionStatus
事務狀態
public interface TransactionStatus extends SavepointManager, Flushable {
/**
* 是否是新事務
*/
boolean isNewTransaction();
/**
* 是否有保存點
*/
boolean hasSavepoint();
/**
* 設置回滾
*/
void setRollbackOnly();
/**
* 是否回滾
*/
boolean isRollbackOnly();
/**
* 刷新
*/
@Override
void flush();
/**
* 是否已完成
*/
boolean isCompleted();
}
TransactionDefinition
事務詳情
public interface TransactionDefinition {
/**
* 傳播行為
*/
int getPropagationBehavior();
/**
* 隔離級別
*/
int getIsolationLevel();
/**
* 超時時間
*/
int getTimeout();
/**
* 是否只讀
*/
boolean isReadOnly();
/**
* 配置事務詳情名稱。一般方法名稱。例如:save、add 等
*/
String getName();
}
傳播行為
在兩個業務之間如何共享事務。有以下取值:
- PROPAGATION_REQUIRED , required , 必須 【默認值】
支持當前事務,A如果有事務,B將使用該事務。
如果A沒有事務,B將創建一個新的事務。 - PROPAGATION_SUPPORTS ,supports ,支持
支持當前事務,A如果有事務,B將使用該事務。
如果A沒有事務,B將以非事務執行。 - PROPAGATION_MANDATORY,mandatory ,強制
支持當前事務,A如果有事務,B將使用該事務。
如果A沒有事務,B將拋異常。 - PROPAGATION_REQUIRES_NEW , requires_new ,必須新的
如果A有事務,將A的事務掛起,B創建一個新的事務
如果A沒有事務,B創建一個新的事務 - PROPAGATION_NOT_SUPPORTED ,not_supported ,不支持
如果A有事務,將A的事務掛起,B將以非事務執行
如果A沒有事務,B將以非事務執行 - PROPAGATION_NEVER ,never,從不
如果A有事務,B將拋異常
如果A沒有事務,B將以非事務執行 - PROPAGATION_NESTED ,nested ,嵌套
A和B底層采用保存點機制,形成嵌套事務。
常用的是:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
轉賬 Demo
表
create table account(
id int primary key auto_increment,
username varchar(50),
money int
);
insert into account(username,money) values('jack','10000');
insert into account(username,money) values('rose','10000');
Dao
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void out(String outer, Integer money) {
String sql = "UPDATE account SET money = money - ? WHERE username = ?";
Object[] args = new Object[]{money, outer};
getJdbcTemplate().update(sql, args);
}
@Override
public void in(String inner, Integer money) {
String sql = "UPDATE account SET money = money + ? WHERE username = ?";
Object[] args = new Object[]{money, inner};
getJdbcTemplate().update(sql, args);
}
}
Service
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
// int i = 1 / 0;
accountDao.in(inner, money);
}
}
xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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
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">
<!--配置數據源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///db_transaction"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置 dao
繼承了 JdbcDaoSupport,直接注入數據源
-->
<bean id="AccountDao" class="com.ittianyu.spring.d_tx.c_auto.dao.AccountDaoImpl">
<property name="dataSource" ref="DataSource"/>
</bean>
<!--service -->
<bean id="AccountService" class="com.ittianyu.spring.d_tx.c_auto.service.AccountServiceImpl">
<property name="accountDao" ref="AccountDao"/>
</bean>
<!--tx manager-->
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="DataSource"/>
</bean>
<!--配置通知-->
<tx:advice id="Advice" transaction-manager="TransactionManager">
<tx:attributes>
<!--配置 要使用事務的 方法名,傳播途徑,隔離級別 -->
<tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--應用通知-->
<aop:advisor advice-ref="Advice" pointcut="execution(* com.ittianyu.spring.d_tx.c_auto.service..*.*(..))" />
</aop:config>
</beans>
注解配置
Service 注解
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
// int i = 1 / 0;
accountDao.in(inner, money);
}
}
xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置數據源-->
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///db_transaction"/>
<property name="user" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置 dao
繼承了 JdbcDaoSupport,直接注入數據源
-->
<bean id="AccountDao" class="com.ittianyu.spring.d_tx.d_annotation.dao.AccountDaoImpl">
<property name="dataSource" ref="DataSource"/>
</bean>
<!--service -->
<bean id="AccountService" class="com.ittianyu.spring.d_tx.d_annotation.service.AccountServiceImpl">
<property name="accountDao" ref="AccountDao"/>
</bean>
<!--tx manager-->
<bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="DataSource"/>
</bean>
<!--
自動掃描事務注解
-->
<tx:annotation-driven transaction-manager="TransactionManager" />
</beans>
測試
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/d_tx/d_annotation/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = applicationContext.getBean("AccountService", AccountService.class);
accountService.transfer("zs", "ls", 100);
}
7. 整合 Web 和 Junit
Junit
導包
需要導入 spring-test 包,環境搭建列表里面已經包含了。
目的
- 讓 Junit 通知 Spring 加載配置文件
- 讓 Spring 容器自動進行注入
配置
@ContextConfiguration 用于指定配置的位置
@Autowired 指定需要注入的對象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:com/ittianyu/spring/e_junit/applicationContext.xml")
public class TestClass {
@Autowired
private AccountService accountService;
@Test
public void test() {
accountService.transfer("zs", "ls", 100);
}
}
Web
導包
需要導入 spring-web 包,環境搭建列表里面已經包含了。
配置
在 web.xml 中配置 spring listener
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 修改默認的配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:com/ittianyu/spring/f_web/applicationContext.xml</param-value>
</context-param>
<!--配置 spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
手動獲取 Spring 容器
// 方式一,直接 map 中獲取
ApplicationContext applicationContext1 = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
// 方式二,通過工具類獲取
ApplicationContext applicationContext2 = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
AccountService accountService = applicationContext2.getBean("AccountService", AccountService.class);
accountService.transfer("zs", "ls", 100);
8. SSH 整合
導包
Struts2
特別注意 struts2-spring-plugin
,這個包是整合 spring 用的,導入后,Spring 可以自動根據名稱把 service 注入到 action。
compile "org.apache.struts:struts2-core:2.5.10.1"
compile "org.apache.struts:struts2-convention-plugin:2.5.10"
compile "org.apache.struts:struts2-spring-plugin:2.5.10"
Spring
compile "org.springframework:spring-context:4.3.7.RELEASE"
compile "org.springframework:spring-tx:4.3.7.RELEASE"
compile 'org.springframework:spring-web:4.3.7.RELEASE'
compile 'org.springframework:spring-orm:4.3.7.RELEASE'
compile 'org.springframework:spring-aspects:4.3.7.RELEASE'
compile 'org.springframework:spring-test:4.3.7.RELEASE'
Hibernate
compile "org.hibernate:hibernate-core:5.2.9.Final"
其他
// servlet
providedCompile "javax.servlet:javax.servlet-api:3.0.1"
// mysql
compile 'mysql:mysql-connector-java:5.1.40'
// c3p0
compile 'com.mchange:c3p0:0.9.5.2'
Spring 整合 Hibernate
不再使用 hibernate.cfg.xml,使用 Spring datasource 取代。
jdbc.roperties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ee19_crm
jdbc.user=root
jdbc.password=123456
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="classpath:spring/applicationContext-staff.xml"/>
<import resource="classpath:spring/applicationContext-department.xml"/>
<import resource="classpath:spring/applicationContext-post.xml"/>
<import resource="classpath:spring/applicationContext-courseType.xml"/>
<import resource="classpath:spring/applicationContext-classes.xml"/>
<!--import jdbc info-->
<context:property-placeholder location="classpath:jdbc.properties" />
<!--data source-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--session factory-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/ee19_crm</prop>
<prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
</props>
</property>
<property name="mappingLocations">
<list>
<value>classpath:com/ittianyu/crm/classes/bean/CrmClass.hbm.xml</value>
<value>classpath:com/ittianyu/crm/coursetype/bean/CrmCourseType.hbm.xml</value>
<value>classpath:com/ittianyu/crm/department/bean/CrmDepartment.hbm.xml</value>
<value>classpath:com/ittianyu/crm/post/bean/CrmPost.hbm.xml</value>
<value>classpath:com/ittianyu/crm/staff/bean/CrmStaff.hbm.xml</value>
</list>
</property>
</bean>
<!--tx-->
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*"/>
<tx:method name="update*"/>
<tx:method name="delete*"/>
<tx:method name="login"/>
<tx:method name="query*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.ittianyu.crm..service..*(..))"/>
</aop:config>
</beans>
Dao
Dao 繼承 HibernateDaoSupport
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
@Override
public void save(User user) {
this.getHibernateTemplate().save(user);
}
}
Struts2 整合 Spring
strut2 還是原來寫法。
Spring 中配置 Service 時,bean 的 id 必須和 Action 類中 service 的 set名字一致。
比如:
配置
<bean id="staffService" class="com.ittianyu.crm.staff.service.impl.StaffServiceImpl">
<property name="staffDao" ref="staffDao"/>
</bean>
StaffAction
public void setStaffService(StaffService staffService) {
this.staffService = staffService;
}