前面已經學習了Struts2和Hibernate框架了。接下來學習的是Spring框架...本博文主要是引入Spring框架...html
Spring誕生:java
Spring是一種非侵入式的框架...web
侵入式spring
非侵入式express
前面咱們在寫程序的時候,都是面向接口編程,經過DaoFactroy等方法來實現鬆耦合編程
private CategoryDao categoryDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.CategoryDAOImpl", CategoryDao.class); private BookDao bookDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.BookDaoImpl", BookDao.class); private UserDao userDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.UserDaoImpl", UserDao.class); private OrderDao orderDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.OrderDaoImpl", OrderDao.class);
DAO層和Service層經過DaoFactory來實現鬆耦合微信
而Spring給咱們更加合適的方法來實現鬆耦合,而且更加靈活、功能更增強大!---->IOC控制反轉session
切面編程也就是AOP編程,其實咱們在以前也接觸過...動態代理就是一種切面編程了...mvc
當時咱們使用動態代理+註解的方式給Service層的方法添加權限.app
@Override @permission("添加分類") /*添加分類*/ public void addCategory(Category category) { categoryDao.addCategory(category); } /*查找分類*/ @Override public void findCategory(String id) { categoryDao.findCategory(id); } @Override @permission("查找分類") /*查看分類*/ public List<Category> getAllCategory() { return categoryDao.getAllCategory(); } /*添加圖書*/ @Override public void addBook(Book book) { bookDao.addBook(book); }
AOP編程能夠簡單理解成:在執行某些代碼前,執行另外的代碼
Spring也爲咱們提供更好地方式來實現面向切面編程!
咱們試着回顧一下沒學Spring的時候,是怎麼開發Web項目的
用戶訪問:
咱們來思考幾個問題:
action 多個 【維護成員變量】
service 一個 【不須要維護公共變量】
dao 一個 【不須要維護公共變量】
action 訪問時候建立
service 啓動時候建立
dao 啓動時候建立
對於第一個問題和第三個問題,咱們能夠經過DaoFactory解決掉(雖然不是比較好的解決方法)
對於第二個問題,咱們要控制對象的數量和建立事件就有點麻煩了....
而Spring框架經過IOC就很好地能夠解決上面的問題....
Spring的核心思想之一:Inversion of Control , 控制反轉 IOC
那麼控制反轉是什麼意思呢???對象的建立交給外部容器完成,這個就作控制反轉。
那麼對象的對象之間的依賴關係Spring是怎麼作的呢??依賴注入,dependency injection.
上面已經說了,控制反轉是經過外部容器完成的,而Spring又爲咱們提供了這麼一個容器,咱們通常將這個容器叫作:IOC容器.
不管是建立對象、處理對象之間的依賴關係、對象建立的時間仍是對象的數量,咱們都是在Spring爲咱們提供的IOC容器上配置對象的信息就行了。
那麼使用IOC控制反轉這一思想有什麼做用呢???咱們來看看一些優秀的回答...
來自知乎:https://www.zhihu.com/question/23277575/answer/24259844
我摘取一下核心的部分:
ioc的思想最核心的地方在於,資源不禁使用資源的雙方管理,而由不使用資源的第三方管理,這能夠帶來不少好處。第一,資源集中管理,實現資源的可配置和易管理。第二,下降了使用資源雙方的依賴程度,也就是咱們說的耦合度。
也就是說,甲方要達成某種目的不須要直接依賴乙方,它只須要達到的目的告訴第三方機構就能夠了,好比甲方須要一雙襪子,而乙方它賣一雙襪子,它要把襪子賣出去,並不須要本身去直接找到一個賣家來完成襪子的賣出。它也只須要找第三方,告訴別人我要賣一雙襪子。這下好了,甲乙雙方進行交易活動,都不須要本身直接去找賣家,至關於程序內部開放接口,賣家由第三方做爲參數傳入。甲乙互相不依賴,並且只有在進行交易活動的時候,甲才和乙產生聯繫。反之亦然。這樣作什麼好處麼呢,甲乙能夠在對方不真實存在的狀況下獨立存在,並且保證不交易時候無聯繫,想交易的時候能夠很容易的產生聯繫。甲乙交易活動不須要雙方見面,避免了雙方的互不信任形成交易失敗的問題。由於交易由第三方來負責聯繫,並且甲乙都認爲第三方可靠。那麼交易就能很可靠很靈活的產生和進行了。這就是ioc的核心思想。生活中這種例子比比皆是,支付寶在整個淘寶體系裏就是龐大的ioc容器,交易雙方以外的第三方,提供可靠性可依賴可靈活變動交易方的資源管理中心。另外人事代理也是,僱傭機構和我的以外的第三方。 ==========================update===========================
在以上的描述中,誕生了兩個專業詞彙,依賴注入和控制反轉所謂的依賴注入,則是,甲方開放接口,在它須要的時候,可以講乙方傳遞進來(注入)所謂的控制反轉,甲乙雙方不相互依賴,交易活動的進行不依賴於甲乙任何一方,整個活動的進行由第三方負責管理。
參考優秀的博文①:https://www.tianmaying.com/tutorial/spring-ioc
參考優秀的博文②:這裏寫連接內容
知乎@Intopass
的回答:
Spring能夠分爲6大模塊:
能夠與struts整合,讓struts的action建立交給spring
spring mvc模式
上面文主要引出了爲啥咱們須要使用Spring框架,以及大體瞭解了Spring是分爲六大模塊的....下面主要講解Spring的core模塊!
引入jar包:
本博文主要是core模塊的內容,涉及到Spring core的開發jar包有五個:
我主要使用的是Spring3.2版本...
編寫配置文件:
Spring核心的配置文件applicationContext.xml
或者叫bean.xml
那這個配置文件怎麼寫呢??通常地,咱們都知道框架的配置文件都是有約束的...咱們能夠在spring-framework-3.2.5.RELEASE\docs\spring-framework-reference\htmlsingle\index.html
找到XML配置文件的約束
<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: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"> </beans>
我是使用Intellij Idea集成開發工具的,能夠選擇自帶的Spring配置文件,它長的是這樣:
<?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"> </beans>
前面在介紹Spring模塊的時候已經說了,Core模塊是:IOC容器,解決對象建立和之間的依賴關係。
所以Core模塊主要是學習如何獲得IOC容器,經過IOC容器來建立對象、解決對象之間的依賴關係、IOC細節。
Spring容器不僅僅只有一個,能夠歸爲兩種類型
//加載Spring的資源文件 Resource resource = new ClassPathResource("applicationContext.xml"); //建立IOC容器對象【IOC容器=工廠類+applicationContext.xml】 BeanFactory beanFactory = new XmlBeanFactory(resource);
// 獲得IOC容器對象 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println(ac);
在Spring中整體來看能夠經過三種方式來配置對象:
在上面咱們已經能夠獲得IOC容器對象了。接下來就是在applicationContext.xml文件中配置信息【讓IOC容器根據applicationContext.xml文件來建立對象】
/** * Created by ozc on 2017/5/10. */ public class User { private String id; private String username; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
User user = new User();
<!-- 使用bean節點來建立對象 id屬性標識着對象 name屬性表明着要建立對象的類全名 --> <bean id="user" class="User"/>
經過IOC容器對象獲取對象:
// 獲得IOC容器對象 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = (User) ac.getBean("user"); System.out.println(user);
上面咱們使用的是IOC經過無參構造函數來建立對象,咱們來回顧一下通常有幾種建立對象的方式:
使用無參的構造函數建立對象咱們已經會了,接下來咱們看看使用剩下的IOC容器是怎麼建立對象的。
首先,JavaBean就要提供帶參數的構造函數:
public User(String id, String username) { this.id = id; this.username = username; }
接下來,關鍵是怎麼配置applicationContext.xml文件了。
<bean id="user" class="User"> <!--經過constructor這個節點來指定構造函數的參數類型、名稱、第幾個--> <constructor-arg index="0" name="id" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" name="username" type="java.lang.String" value="zhongfucheng"></constructor-arg> </bean>
在constructor上若是構造函數的值是一個對象,而不是一個普通類型的值,咱們就須要用到ref屬性了,而不是value屬性
好比說:我在User對象上維護了Person對象的值,想要在構造函數中初始化它。所以,就須要用到ref屬性了
<bean id="person" class="Person"></bean> <bean id="user" class="User" > <!--經過constructor這個節點來指定構造函數的參數類型、名稱、第幾個--> <constructor-arg index="0" name="id" type="java.lang.String" value="1"></constructor-arg> <constructor-arg index="1" name="username" type="java.lang.String" ref="person"></constructor-arg> </bean>
首先,使用一個工廠的靜態方法返回一個對象
public class Factory { public static User getBean() { return new User(); } }
配置文件中使用工廠的靜態方法返回對象
<!--工廠靜態方法建立對象,直接使用class指向靜態類,指定靜態方法就好了--> <bean id="user" class="Factory" factory-method="getBean" > </bean>
首先,也是經過工廠的非非靜態方法來獲得一個對象
public class Factory { public User getBean() { return new User(); } }
配置文件中使用工廠的非靜態方法返回對象
<!--首先建立工廠對象--> <bean id="factory" class="Factory"/> <!--指定工廠對象和工廠方法--> <bean id="user" class="User" factory-bean="factory" factory-method="getBean"/>
咱們在使用XML配置建立Bean的時候,若是該Bean有構造器,那麼咱們使用<constructor-arg>
這個節點來對構造器的參數進行賦值...
<constructor-arg>
未免有點太長了,爲了簡化配置,Spring來提供了c名稱空間...
要想c名稱空間是須要導入xmlns:c="http://www.springframework.org/schema/c"
的
<bean id="userService" class="bb.UserService" c:userDao-ref=""> </bean>
c名稱空間有個**缺點:不能裝配集合,**當咱們要裝配集合的時候仍是須要<constructor-arg>
這個節點
若是對象上的屬性或者構造函數擁有集合的時候,而咱們又須要爲集合賦值,那麼怎麼辦?
<bean id="userService" class="bb.UserService" > <constructor-arg > <list> //普通類型 <value></value> </list> </constructor-arg> </bean>
<property name="userDao"> <list> <ref></ref> </list> </property>
自從jdk5有了註解這個新特性,咱們能夠看到Struts2框架、Hibernate框架都支持使用註解來配置信息...
經過註解來配置信息就是爲了簡化IOC容器的配置,註解能夠把對象添加到IOC容器中、處理對象依賴關係,咱們來看看怎麼用吧:
使用註解步驟:
xmlns:context="http://www.springframework.org/schema/context"
`<context:component-scan base-package=""></context:component-scan>`
@CompoentScan
修飾來掃描IOC容器的bean對象。。以下代碼://代表該類是配置類 @Configuration //啓動掃描器,掃描bb包下的 //也能夠指定多個基礎包 //也能夠指定類型 @ComponentScan("bb") public class AnnotationScan { }
在使用@ComponentScan()
這個註解的時候,在測試類上須要@ContextConfiguration這個註解來加載配置類...
@ContextConfiguration
這個註解又在Spring的test包下..建立對象以及處理對象依賴關係,相關的註解:
@ComponentScan
掃描器@Configuration
代表該類是配置類@Component
指定把一個對象加入IOC容器--->@Name
也能夠實現相同的效果【通常少用】@Repository 做用同@Component
; 在持久層使用@Service 做用同@Component
; 在業務邏輯層使用@Controller 做用同@Component
; 在控制層使用@Resource
依賴關係
@Resource
不指定值,那麼就根據類型來找,相同的類型在IOC容器中不能有兩個@Resource
指定了值,那麼就根據名字來找測試代碼:
package aa; import org.springframework.stereotype.Repository; /** * Created by ozc on 2017/5/10. */ //把對象添加到容器中,首字母會小寫 @Repository public class UserDao { public void save() { System.out.println("DB:保存用戶"); } }
package aa; import org.springframework.stereotype.Service; import javax.annotation.Resource; //把UserService對象添加到IOC容器中,首字母會小寫 @Service public class UserService { //若是@Resource不指定值,那麼就根據類型來找--->UserDao....固然了,IOC容器不能有兩個UserDao類型的對象 //@Resource //若是指定了值,那麼Spring就在IOC容器找有沒有id爲userDao的對象。 @Resource(name = "userDao") private UserDao userDao; public void save() { userDao.save(); } }
package aa; import org.springframework.stereotype.Controller; import javax.annotation.Resource; /** * Created by ozc on 2017/5/10. */ //把對象添加到IOC容器中,首字母會小寫 @Controller public class UserAction { @Resource(name = "userService") private UserService userService; public String execute() { userService.save(); return null; } }
package aa; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by ozc on 2017/5/10. */ public class App { public static void main(String[] args) { // 建立容器對象 ApplicationContext ac = new ClassPathXmlApplicationContext("aa/applicationContext.xml"); UserAction userAction = (UserAction) ac.getBean("userAction"); userAction.execute(); } }
因爲Spring的自動裝配並不能將第三方庫組件裝配到應用中,因而須要顯式裝配配置。顯示裝配有兩種方式
Spring In Action做者首推使用自動裝配的功能,然後是經過java代碼配置bean,最後才用XML文件配置的方式..
那麼怎麼經過java代碼來配置Bean呢??
@Configuration
修飾該類@Configuration
修飾的類就是配置類編寫配置類:
@org.springframework.context.annotation.Configuration public class Configuration { }
使用配置類建立bean:
@Bean
來修飾方法,該方法返回一個對象。@org.springframework.context.annotation.Configuration public class Configuration { @Bean public UserDao userDao() { UserDao userDao = new UserDao(); System.out.println("我是在configuration中的"+userDao); return userDao; } }
package bb; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.test.context.ContextConfiguration; /** * Created by ozc on 2017/5/11. */ //加載配置類的信息 @ContextConfiguration(classes = Configuration.class) public class Test2 { @Test public void test33() { ApplicationContext ac = new ClassPathXmlApplicationContext("bb/bean.xml"); UserDao userDao = (UserDao) ac.getBean("userDao"); System.out.println(userDao); } }
註解和XML配置是能夠混合使用的,JavaConfig和XML也是能夠混合使用的...
若是JavaConfig的配置類是分散的,咱們通常再建立一個更高級的配置類(root),而後使用**@Import
來將配置類進行組合** 若是XML的配置文件是分散的,咱們也是建立一個更高級的配置文件(root),而後使用<import>來將配置文件組合
在JavaConfig引用XML
@ImportResource()
在XML引用JavaConfig
<bean>
節點就好了在Spring第一篇中,咱們爲何要引入Spring提出了這麼一些問題:
既然咱們如今已經初步瞭解IOC容器了,那麼這些問題咱們都是能夠解決的。而且是十分簡單【對象寫死問題已經解決了,IOC容器就是控制反轉建立對象】
指定scope屬性,IOC容器就知道建立對象的時候是單例仍是多例的了。
屬性的值就只有兩個:單例/多例
scope屬性除了控制對象是單例仍是多例的,還控制着對象建立的時間!
public User() { System.out.println("我是User,我被建立了"); }
lazy-init屬性只對singleton【單例】的對象有效.....lazy-init默認爲false....
有的時候,可能咱們想要對象在使用的時候才建立,那麼將lazy-init設置爲ture就好了
若是咱們想要對象在建立後,執行某個方法,咱們指定爲init-method屬性就好了。。
若是咱們想要IOC容器銷燬後,執行某個方法,咱們指定destroy-method屬性就好了。
<bean id="user" class="User" scope="singleton" lazy-init="true" init-method="" destroy-method=""/>
/** * 1) 對象建立: 單例/多例 * scope="singleton", 默認值, 即 默認是單例 【service/dao/工具類】 * scope="prototype", 多例; 【Action對象】 * * 2) 何時建立? * scope="prototype" 在用到對象的時候,才建立對象。 * scope="singleton" 在啓動(容器初始化以前), 就已經建立了bean,且整個應用只有一個。 * 3)是否延遲建立 * lazy-init="false" 默認爲false, 不延遲建立,即在啓動時候就建立對象 * lazy-init="true" 延遲初始化, 在用到對象的時候才建立對象 * (只對單例有效) * 4) 建立對象以後,初始化/銷燬 * init-method="init_user" 【對應對象的init_user方法,在對象建立以後執行 】 * destroy-method="destroy_user" 【在調用容器對象的destroy方法時候執行,(容器用實現類)】 */
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y