一. Spring 框架是一個分層架構,由 7 個定義良好的模塊組成。Spring 模塊構建在覈心容器之上,核心容器定義了創建、配置和管理 bean 的方式,如下圖所示。
組成 Spring 框架的每個模塊(或組件)都可以單獨存在,或者與其他一個或多個模塊聯合實現。每個模塊的功能如下:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要組件是
BeanFactory
,它是工廠模式的實現。BeanFactory
使用控制反轉(IOC) 模式將應用程序的配置和依賴性規範與實際的應用程序代碼分開。Spring 上下文:Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。
Spring AOP:通過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何對象支持 AOP。Spring AOP 模塊爲基於 Spring 的應用程序中的對象提供了事務管理服務。通過使用 Spring AOP,不用依賴 EJB 組件,就可以將聲明性事務管理集成到應用程序中。
Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常代碼數量(例如打開和關閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。
Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關係工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。
Spring Web 模塊:Web 上下文模塊建立在應用程序上下文模塊之上,爲基於 Web 的應用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。
Spring MVC 框架:MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。通過策略接口,MVC 框架變成爲高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。
二. IOC
1. 控制反轉
控制反轉(inverse of control)也稱爲DI(Didependency injection)的基本概念是:不創建對象,但是描述創建它們的方式。在代碼中不直接與對象和服務連接,但在配置文件中描述哪一個組件需要哪一項服務,容器負責將這些聯繫在一起。初始化控制反轉到容器中了,不在控制在自己手中定義的了;原來控制的是具體的實現,現在依賴的是抽象,控制的是接口,也可稱爲控制反轉。
2. 注入方式:
(1)Set注入
這是最簡單的注入方式,假設有一個SpringAction,類中需要實例化一個SpringDao對象,那麼就可以定義一個private的SpringDao成員變量,然後創建SpringDao的set方法(這是ioc的注入入口):
public class SpringAction { //注入對象springDao private SpringDao springDao; //一定要寫被注入對象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = springDao; } public void method(){ springDao.method(); } }
spring將SpringDaoImpl對象實例化並且調用SpringAction的setSpringDao方法將SpringDao注入:
<!--配置bean,配置後該類由spring管理--> <bean name="springAction" class="com.spring.action.SpringAction"> <!--依賴注入,配置當前類中相應的屬性--> <property name="springDao" ref="springDao"></property> </bean> <!--配置SpringDaoImpl對象--> <bean name="springDao" class="com.spring.dao.impl.SpringDaoImpl"></bean>
(2)構造器注入
這種方式的注入是指帶有參數的構造函數注入,如下:創建了兩個成員變量SpringDao和User,但是並未設置對象的set方法,所以就不能支持第一種注入方式,這裏的注入方式是在SpringAction的構造函數中注入,也就是說在創建SpringAction對象時要將SpringDao和User兩個參數值傳進來:
public class SpringAction { //注入對象springDao private SpringDao springDao; private User user; public SpringAction(SpringDao springDao,User user){ this.springDao = springDao; this.user = user; System.out.println("構造方法調用springDao和user"); } public void save(){ user.setName("aa"); springDao.save(user); } }
在XML文件中使用<constructor-arg>標籤,
<!--配置bean,配置後該類由spring管理--> <bean name="springAction" class="com.spring.action.SpringAction"> <!--創建構造器注入,如果主類有帶參的構造方法則需添加此配置--> <constructor-arg ref="springDao"></constructor-arg> <constructor-arg ref="user"></constructor-arg> </bean> <bean name="springDao" class="com.spring.dao.impl.SpringDaoImpl"></bean> <bean name="user" class="com.spring.entity.User"></bean>
解決構造方法參數的不確定性,你可能會遇到構造方法傳入的兩參數都是同類型的,爲了分清哪個該賦對應值,則需要進行一些小處理:
下面是設置index,就是參數位置:
<bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <constructor-arg index="0" ref="springDao"></constructor-arg> <constructor-arg index="1" ref="user"></constructor-arg> </bean>
另一種是設置參數類型:
<constructor-arg type="java.lang.String" ref=""/>
(3) Annotation 注入
① 第一步修改xml文件;
<beans xmlns="http://www.springframework.org/schema/beans"//beans裏沒有前綴的都是由它指定 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" //beans裏xsi開頭的找這個文件 xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd //對應上面的beans http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config/> //隱式加載了四個bean,用於處理annotation的註解
②添加提示功能,.xsd文件;preference/XML/XML Catalog裏添加.xsd文件
Xsd文件定義的xml文件的語法,一個xml文件可由多個xsd確定
③使用
@Autowired
a) 默認按類型by type
b) 如果想用byName,使用@Qulifier
c) 寫在private field(第三種注入形式)(不建議,破壞封裝)
d) 如果寫在set上,@qualifier需要寫在參數上
@Autowired 默認按bytype自動尋找對應的類型
public void setUserDAO(@Qualifier("u") UserDAO userDAO){//尋找名字爲u
this.userDAO = userDAO;
}
@Resource(重要)
e) 加入:j2ee/common-annotations.jar
f) 默認按名稱,名稱找不到,按類型
g) 可以指定特定名稱
h) 推薦使用
i) 不足:如果沒有源碼,就無法運用annotation,只能使用xml
@Component @Service @Controller @Repository與component一樣
初始化spring配置文件的時候,會自動掃描com.spring下的所有包,若發現有@component,則將該類初始化爲一個對象,對象的key爲@component("name")中指明的name,若不指明,則默認爲類的名字首字母小寫;
如果發現@Resource(name=”u”);則查看容器是否有名字叫u的bean,若有則將u注入到方法參數中,而後參數就會傳人方法內,當然也就注入了成員變量裏:
j) 初始化的名字默認爲類名首字母小寫
k) 可以指定初始化bean的名字
Xml:里加<context:component-scanbase-package="com.spring"/>//加了該句spring會自動掃描該包的component註解,進行相應的處理
@Component("u")
public class UserDAOImpl implementsUserDAO {
@Resource(name="u")
public void setUserDAO( UserDAO userDAO) {
this.userDAO= userDAO;
}
@Component("userService")//在容器裏可以作爲bean存在
public class UserService {}
UserService service = (UserService)ctx.getBean("userService");
@Scope
@PostConstruct =init-method; @PreDestroy = destroy-method;
三. AOP
面向切面編程(也叫面向方面),可以通過預編譯方式和運行期動態代理實現在不修改源代碼的情況下給程序動態統一添加功能的一種技術。AOP實際是GoF設計模式的延續,設計模式孜孜不倦追求的是調用者和被調用者之間的解耦,AOP可以說也是這種目標的一種實現。
1. 面向切面編程Aspect-Oriented-Programming
a) 是對面向對象的思維方式的有力補充
b) 用途:權限,日誌,效率檢查,事務,異常管理,filter就是aop
2. 好處:可以動態的添加和刪除在切面上的邏輯而不影響原來的執行代碼
a) Filter
b) Struts2的interceptor
3. 概念:查文檔即可
a) JoinPoint 連接點:加入切面的那個點,比如在某個方法之前加入切面,該方法就是連接點
b) PointCut JoinPoint的集合,@Pointcut("execution(public* com.bjsxt.service..*.add(..))")
c) Aspect(切面) 下面的LogInterceptor就是個切面
d) Advice 切面的邏輯,@ Before就是個邏輯在..之前,區別jointpoint
e) Target 被代理對象,邏輯要織入的對象
f) Weave
4. 問題:想要在源daoimpl代碼基礎上加日誌或者一些功能,
(1) 繼承daoimpl,extends daoimpl重寫方法。
Daoimpl2 extends daoimpl{
@override
save(){ ….加代碼 super.save();}
}
(2) 組合
daoimpl3 implement dao{
private userdao=new userdaoimpl();
save(){ ….加代碼 dao.save();}
}
慎用繼承,組合較好
5. Spring aop使用:註解 自己寫時會用到註解
(1) xml中加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy/>//使用aspectj語法,spring採用了這個框架
(2) 代碼
@Aspect //指定是個切面類 @Component public class LogInterceptor { @Before ("execution(public * com.bjsxt.service..*.add(..))")//excut..代表方法的執行,在這個方法執行之前執行下面的方法,第一個*代表返回值,..代表層次, publicvoid before() { System.out.println("methodbefore"); } @Aspect @Component public class LogInterceptor { @Pointcut("execution(public* com.bjsxt.dao..*.*(..))")//Execution方法運行,第一個*代表返回值,..代表所有子包,任何類的任何方法, public void myMethod(){}; // myMethod爲pointcut的名字 @Before("myMethod()") //指上面定義的那個切入點集合 public void before() { System.out.println("methodbefore"); } @Around("myMethod()") public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("methodaround start"); pjp.proceed(); System.out.println("methodaround end"); } }
@afterreturning @afterthrowing @around
cglib包若不是接口需用該包
Spring aop使用:xml
<bean id="logInterceptor"class="com.bjsxt.aop.LogInterceptor"></bean> <aop:config> <aop:aspectid="logAspect" ref="logInterceptor"> <aop:beforemethod="before" pointcut="execution(public *com.bjsxt.service..*.add(..))" /> </aop:aspect> </aop:config>
若沒有切面類的邏輯,或使用第三方提供的邏輯類,就不能加註解了,所以xml必須會。
四. datasource
1. Spring 指定datasource
a) 參考文檔,找dbcp.BasicDataSource 主要用到的三種連接池,要用注入的方式
i. c3p0
ii. dbcp
iii. proxool
b) 在DAO或者Service中注入dataSource
c) 在Spring中可以使用PropertyPlaceHolderConfigure來讀取Properties文件的內容
(1)dbcp.BasicDataSource
datasource:提供了一個標準化的連接
<bean id="myDataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"> <!-- results in asetDriverClassName(String) call --> <property name="driverClassName"value="com.mysql.jdbc.Driver"/> <property name="url"value="jdbc:mysql://localhost:3306/mydb"/> <property name="username"value="root"/> <property name="password"value="masterkaoli"/> </bean>
dao注入這個數據源。
private DataSource Datasource; public DataSource get Datasource() { returnDatasource; } @Resource publicvoid set Datasource(DataSourceDatasource) { this.Datasource = Datasource; }
還需要拿connction等,較古老。
(2)c3p0
配置參數影響因素:性能的要求要親身測試(自動化測試工具,或寫個多線程測試);硬件cpu等;內存的大小;網頁執行時間影響;鏈接的長短;
(3)佔位符配置,jdbc.propertites配置:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <propertyname="locations"> //此種情況都可以用propertites配置 <value>classpath:jdbc.properties</value> </property> </bean> <beanid="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <propertyname="driverClassName" value="${jdbc.driverClassName}"/> <propertyname="url" value="${jdbc.url}" /> <propertyname="username" value="${jdbc.username}" /> <propertyname="password" value="${jdbc.password}" /> </bean>
Jdbc.propertites文件:
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring jdbc.username=root jdbc.password=root
五. Spring整合Hibernate Spring_1700_Spring_DataSource參考
Opensession和getcurrentsession的區別?open是打開新的,需要自己寫關閉,事務等
(1)知道即可
a) Spring中配置sessionfactory
<bean ..AnnotationSessionFactoryBean>
i. <property dataSource
ii. <annotatedClasses
b) 引入hibernate 系列jar包
c) User上加Annotation
d) UserDAO或者UserServie 注入SessionFactory
e) jar包問題一個一個解決
(2)聲明式的事務管理
f) 事務加在DAO層還是Service層?
g) annotation Spring_1800_Spring_Hibernate_Transaction_Annotation
i. 加入annotation.xsd 即加三行tx代碼
ii. 加入txManager bean
iii. <tx:annotation-driven
iv. 在需要事務的方法上加:@Transactional
v. 需要注意,使用SessionFactory.getCurrentSession 不要使用OpenSession
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <beanid="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <propertyname="sessionFactory" ref="sessionFactory" /> </bean> <tx:annotation-driventransaction-manager="txManager"/>
注意:
Spring對事務管理簡單很多了,dao不需要try catch了
h) @Transactional詳解
i. 什麼時候rollback
1. 運行期異常,非運行期異常不會觸發rollback
2. 必須uncheck (沒有catch)
3. 不管什麼異常,只要你catch了,spring就會放棄管理
4. 事務傳播特性:propagation_required
@Transactional(propagation=propagation.REQUIRED):如果有了transation,就用以前的,沒有就創建一個。
5. read_only
@Transactional(readOnly=true) 用途,可以提高效率
i) xml(推薦,可以同時配置好多方法)
i. <bean txmanager
ii. <aop:config
1. <aop:pointcut
2. <aop:advisor pointcut-refadvice-ref
iii. <tx:advice: idtransaction-manager =
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <propertyname="sessionFactory" ref="sessionFactory" /> </bean> <aop:config> <aop:pointcut id="bussinessService" expression="execution(public* com.bjsxt.service..*.*(..))" /> <aop:advisorpointcut-ref="bussinessService" advice-ref="txAdvice"/> </aop:config> <tx:adviceid="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:methodname="getUser" read-only="true" />//get都是隻讀的 <tx:methodname="add*" propagation="REQUIRED"/>//讀寫都行 </tx:attributes> </tx:advice>
(3)自動掃描實體類
<!-- <propertyname="annotatedClasses"> <list> <value>com.bjsxt.model.User</value> <value>com.bjsxt.model.Log</value> </list> </property> --> <propertyname="packagesToScan"> //自動掃描實體類,自己就不用加了 <list> <value>com.bjsxt.model</value> </list> </property>
HibernateTemplate、HibernateCallback、HibernateDaoSupport(不重要)介紹
iv. 設計模式:Template Method (按照模板,具體內容自己往裏填即可)
前面的打開session,關閉session,事務提交等都作爲模板
v. Callback:回調/鉤子函數
vi. 第一種:(建議)
1. 在spring中初始化HibernateTemplate,注入sessionFactory
2. DAO裏注入HibernateTemplate
3. save寫getHibernateTemplate.save();
<bean id="hibernateTemplate"class="org.springframework.orm.hibernate3.HibernateTemplate"> <propertyname="sessionFactory"ref="sessionFactory"></property> </bean> public class UserDAOImpl implementsUserDAO { privateHibernateTemplate hibernateTemplate; publicHibernateTemplate getHibernateTemplate() { returnhibernateTemplate; } @Resource publicvoid setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate= hibernateTemplate; } publicvoid save(User user) { hibernateTemplate.save(user); //thrownew RuntimeException("exeption!"); } }
vii. 第二種:
1. 從HibernateDaoSupport繼承(不需要)
2. 必須寫在xml文件中,無法使用Annotation,因爲set方法在父類中,而且是final的
也可以編寫superdao簡化代碼,SuperDAO.java但以後就不能繼承其他類了。
如Spring_2100_Spring_Hibernate_HibernateDaoSupport
或者Spring_2200_Spring_Hibernate_HibernateDaoSupport_2