Spring是分層的、JavaSE/EE一站式(full-stack)、輕量級開源框架。java
JavaEE分層:JavaEE規範的三層結構體系web
1.表現層(頁面數據顯示、頁面跳轉調度),例如jsp/servletspring
2.業務層(業務處理和功能邏輯、事務控制),例如service數據庫
3.持久層(數據存取和封裝、和數據庫打交道),例如dao編程
如圖:設計模式
一站式:Spring提供了JavaEE各層的解決方案:數組
表現層:struts1、struts2、Spring MVC緩存
業務層:Ioc、AOP、事務控制服務器
持久層:JdbcTemplate、HibernateTemplate、ORM框架(對象關係映射)整合架構
輕量級:Spring的出現取代了EJB的臃腫、低效、繁瑣複雜、脫離現實的狀況. 並且使用spring編程是非侵入式的。
Spring框架是一個分層架構,它包含一系列的功能要素並被分爲大約20個模塊。這些模塊分爲Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation和測試部分
核心容器(Core Container) 包括Core、Beans、Context、EL模塊。 1:Core和Beans模塊提供了Spring最基礎的功能,提供IoC和依賴注入特性。這裏的基礎概念是BeanFactory,它提供對Factory模式的經典實現來消除對程序性單例模式的須要,並真正地容許你從程序邏輯中分離出依賴關係和配置。 2:Context模塊基於Core和Beans來構建,它提供了用一種框架風格的方式來訪問對象,有些像JNDI註冊表。Context封裝包繼承了beans包的功能,還增長了國際化(I18N),事件傳播,資源裝載,以及透明建立上下文,例如經過servlet容器,以及對大量JavaEE特性的支持,如EJB、JMX。核心接口是ApplicationContext。 3:Expression Language,表達式語言模塊,提供了在運行期間查詢和操做對象圖的強大能力。支持訪問和修改屬性值,方法調用,支持訪問及修改數組、容器和索引器,命名變量,支持算數和邏輯運算,支持從Spring 容器獲取Bean,它也支持列表投影、選擇和通常的列表聚合等。 數據訪問/集成部分(Data Access/Integration) 1:JDBC模塊,提供對JDBC的抽象,它可消除冗長的JDBC編碼和解析數據庫廠商特有的錯誤代碼。 2:ORM模塊,提供了經常使用的"對象/關係"映射APIs的集成層。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封裝包,能夠混合使用全部Spring提供的特性進行"對象/關係"映射,如簡單聲明性 事務管理 。 3:OXM模塊,提供一個支持Object和XML進行映射的抽象層,其中包括JAXB、Castor、XMLBeans、JiBX和XStream。 4:JMS模塊,提供一套"消息生產者、消費者"模板用於更加簡單的使用JMS,JMS用於用於在兩個應用程序之間,或分佈式系統中發送消息,進行異步通訊。 5:Transaction模塊,支持程序經過簡單聲明性 事務管理,只要是Spring管理對象都能獲得Spring管理事務的好處,即便是POJO,也能夠爲他們提供事務。 Web 1:Web模塊,提供了基礎的web功能。例如多文件上傳、集成IoC容器、遠程過程訪問、以及Web Service支持,並提供一個RestTemplate類來提供方便的Restful services訪問 2:Web-Servlet模塊,提供了Web應用的Model-View-Controller(MVC)實現。Spring MVC框架提供了基於註解的請求資源注入、更簡單的數據綁定、數據驗證等及一套很是易用的JSP標籤,徹底無縫與Spring其餘技術協做。 3:Web-Struts模塊, 提供了對Struts集成的支持,這個功能在Spring3.0裏面已經不推薦了,建議你遷移應用到使用Struts2.0或Spring的MVC。 4:Web-Portlet模塊,提供了在Portlet環境下的MVC實現 AOP 1:AOP模塊,提供了符合AOP 聯盟規範的面向方面的編程實現,讓你能夠定義如方法攔截器和切入點,從邏輯上講,能夠減弱代碼的功能耦合,清晰的被分離開。並且,利用源碼級的元數據功能,還能夠將各類行爲信息合併到你的代碼中 。 2:Aspects模塊,提供了對AspectJ的集成。 3:Instrumentation模塊, 提供一些類級的工具支持和ClassLoader級的實現,能夠在一些特定的應用服務器中使用。 Test 1:Test模塊,提供對使用JUnit和TestNG來測試Spring組件的支持,它提供一致的ApplicationContexts並緩存這些上下文,它還能提供一些mock對象,使得你能夠獨立的測試代碼。
IoC(Inverse of Control 控制反轉):將對象建立權利交給Spring工廠進行管理。好比說:Book book = new Book(); Book book2 = Spring工廠.getBook();
AOP(Aspect Oriented Programming 面向切面編程),基於動態代理的功能加強方式。
Spring 出現爲了解決JavaEE 實際問題 (1)方便解耦,簡化開發 Spring就是一個大工廠,它能夠將全部對象建立和依賴關係維護,交給Spring管理 (2)AOP編程的支持 Spring提供面向切面編程,能夠方便的實現對程序進行權限攔截、運行監控等功能 (3)聲明式事務的支持 只須要經過配置就能夠完成對事務的管理,而無需手動編程 (3)方便程序的測試 Spring對Junit4支持,能夠經過註解方便的測試Spring程序 (5)方便集成各類優秀框架 Spring不排斥各類優秀的開源框架,其內部提供了對各類優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持 (6)下降JavaEE API的使用難度 Spring 對JavaEE開發中很是難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大下降
關於框架的特性,咱們也會俗稱Spring爲開發架構的粘合劑。
採用IoC(Inverse of Control,控制反轉)的思想解決代碼耦合問題。
簡單的說就是引入工廠(第三者),將原來在程序中手動建立管理的依賴的UserDaoImpl對象,交給工廠來建立管理。
IoC底層實現:工廠(設計模式)+反射(機制) + 配置文件(xml)。
DI:Dependency Injection 依賴注入,在Spring框架負責建立Bean對象時,動態的將依賴對象注入到Bean組件(簡單的說,能夠將另一個bean對象動態的注入到另一個bean中。)
回顧以前的代碼:
步驟一:將service對象也交給spring容器管理
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: spring工廠建立的一個對象(反射機制) id/name:對象的名字,能夠用來引用或者獲取對象, 通常爲類名或接口名稱的首字母小寫 class:要建立的對象類型的類字符串,類名全路徑 --> <bean id="userDAO" class="cn.spring.a_quickstart.UserDAOImpl" /> <bean id ="userService" class="cn.spring.a_quickstart.UserServiceImpl"> <!-- 注入對象 --> <!-- property 根據類中的setter方法進行屬性注入 --> <!-- name:類中setter方法的後綴小寫,好比setXxx 對應的name爲xxx --> <!-- ref:引用哪個bean(對象),值爲bean的id/name --> <property name="userDAO" ref="userDAO" /> </bean> </beans>
步驟二:在程序中定義屬性提供setter方法:
UserServiceImpl.java
public class UserServiceImpl implements IUserService{ //定義屬性 private IUserDAO userDAO; public void setUserDAO(IUserDAO userDAO) { this.userDAO = userDAO; } public void login() { System.out.println("UserServiceImpl-service層方法調用了"); //ioc:依賴注入 userDAO.findUserByUsernameAndPassword(); }
步驟三:Dao層
//dao的實現類 public class UserDaoImpl implements IUserDao { @Override public void findByUsernameAndPassword() { System.out.println("UserDaoImpl-dao層被調用了"); } }
步驟四:測試運行,此時獲取對象必須從spring工廠獲取(在spring容器配置中才有依賴注入,本身建立的對象沒有注入依賴關係)
public class SpringTest { //測試 @Test public void test(){ //建立service的示例 //IUserService userService = new UserServiceImpl(); //userService.login(); //建立spring工廠,獲取spring管理的對象 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); IUserService userService = (IUserService) ac.getBean("userService"); userService.login(); } }
小結:
IOC:控制反轉,將對象建立管理的權利交給spring容器,獲取對象經過spring工廠建立
DI:在spring容器中建立管理多個對象,經過 property標籤將對象注入到須要依賴的對象中
【擴展】
Bean獲取的兩種方式:
@Test public void getBean(){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //獲取bean的兩種方式 //1.經過spring容器中bean的id/name獲取 //IUserService userService = (IUserService) ac.getBean("userService"); //2.根據bean的類型或者bean接口的類型獲取,通常使用接口類型 IUserService userService = (IUserService) ac.getBean(IUserService.class); userService.login(); }
經常使用根據名稱獲取(id/name),即第一種方式,使用spring容器中的標識獲取對象
方式二的弊端:若是根據類型獲取,配置了多個類型的話,則拋出異常:
applicationContext.xml:
<bean id ="userService1" class="cn..spring.a_quickstart.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean id ="userService2" class="cn.spring.a_quickstart.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean>
第一種方式 無參數構造器 (最經常使用)
第一步:建立Bean1.java
//1。默認構造器(spring在建立bean的時候自動調用無參構造器來實例化,至關於new Bean1()) public class Bean1 { }
第二步:在spring容器applicationContext.xml中配置
<!-- 實例化 bean的四種方式 -->
<!-- 1.默認構造器實例化對象 -->
<bean id ="bean1" class="cn.spring.b_xmlnewbean.Bean1" />
第三步:建立測試類獲取bean對象
SpringTest.java:
public class SpringTest { @Test public void test(){ //建立spring工廠 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //1.默認構造器獲取bean對象 Bean1 bean1 = (Bean1) ac.getBean("bean1"); System.out.println(bean1); } }
【錯誤演示】:
public class Bean1 { //錯誤演示 private String name; public Bean1(String name) { this.name = name; } }
靜態工廠方法、 實例工廠方法、FactoryBean方式這三種方式在這裏就不演示了,第一種是最經常使用的
由spring建立的bean對象在什麼狀況下有效。
項目開發中一般會使用:singleton 單例、 prototype多例
Singleton: 在一個spring容器中,對象只有一個實例。(默認值)
Prototype: 在一個spring容器中,存在多個實例,每次getBean 返回一個新的實例
第一步:建立類SingletonBean.java和PrototypeBean.java
建立類SingletonBean.java類
//單例bean public class SingletonBean { public SingletonBean() { System.out.println("SingletonBean:初始化了單例"); } }
建立類PrototypeBean.java類
//多例bean public class PrototypeBean { public PrototypeBean() { System.out.println("--PrototypeBean初始化了多例的"); } }
第二步:applicationContext配置文件:
<!-- bean的做用範圍 scope:配置做用範圍的,默認值就是singleton單例 --> <!-- 單例 --> <bean id="singletonBean" class="cn.spring.c_xmlscope.SingletonBean" scope="singleton"/> <bean id="singletonBean" class="cn.spring.c_xmlscope.SingletonBean"/> <!-- 多例 --> <bean id="prototypeBean" class="cn.spring.c_xmlscope.PrototypeBean" scope="prototype"/>
第三步:測試代碼,建立SpringTest.java:
//newbean的方式 public class SpringTest { @Test public void test(){ //先構建實例化獲取spring的容器(工廠、上下文) ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //目標1:看看屢次獲取bean的時候,是否是同一個 //目標2:看看bean何時初始化的 //獲取單例的bean:應該是同一個 //單例:每次從spring容器中獲取的對象,是同一個對象 //單例初始化:是在spring容器初始化的時候,就初始化了 //即這一步new ClassPathXmlApplicationContext("applicationContext.xml")就初始化單例了 SingletonBean singletonBean1=(SingletonBean)applicationContext.getBean("singletonBean"); SingletonBean singletonBean2=(SingletonBean)applicationContext.getBean("singletonBean"); System.out.println(singletonBean1); System.out.println(singletonBean2); //獲取多例的bean: //多例:每次從spring容器中獲取的對象,不是同一個對象 //多例初始化:是在getBean的時候初始化,至關於每次getbean就是在new Bean() PrototypeBean prototypeBean1=(PrototypeBean)applicationContext.getBean("prototypeBean"); PrototypeBean prototypeBean2=(PrototypeBean)applicationContext.getBean("prototypeBean"); System.out.println(prototypeBean1); System.out.println(prototypeBean2); } }
【注意】
單例是默認值,若是須要單例對象,則不須要配置scope。
第二步: 編寫Service和DAO 的註冊
xml作法 : <bean id=」customerService」 class=」…」 />,用<bean>的方式建立對象
註解作法 : spring2.5引入 @Component 註解 若是放置到類的上面,至關於在spring容器中定義<bean id=」」 class=」」>
建立類:CustomerService.java類
/** * @Component註解放置到類上 * 至關於spring容器中定義:<bean id="customerService" class="cn.spring.a_ioc.CustomerService"> * @Component(value="customerService") //能夠自定義bean的id名字 若是不寫value值,默認value值爲類名的首字母小寫,即customerService * 至關於spring容器中定義:<bean id="customer" class="cn.spring.a_ioc.CustomerService"> */ //注意:只有value一個屬性時,能夠寫做@Component("customerService"),也能夠寫做@Component @Component(value="customerService") public class CustomerService { //保存業務方法 public void save(){ System.out.println("CustomerService業務層被調用了。。。"); } }
第三步: 配置註解開啓和註解Bean的掃描。配置的示例以下:配置applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns: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"> <!-- 開啓spring的註解功能 :讓註解有效了,識別註解--> <context:annotation-config/> <!-- 配置註解bean掃描 context:component-scan:專門掃描含有@Component註解的類,自動將其做爲bean base-package:要掃描包的路徑,cn.itcast.spring全部子包下的全部類定義註解都有效 注意:配置註解ean掃描時,會自動開啓註解功能,全部若是配置註解掃描能夠不配置開啓註解功能 --> <context:component-scan base-package="cn.itcast.spring"/> </beans>
擴展優化:
1.註解掃描配置
配置註解掃描時,會自動開啓註解功能,全部若是配置註解掃描能夠不配置開啓註解功能
2.衍生註解的問題
實際開發中,使用的是@Component三個衍生註解(「子註解」)
子註解的做用:有分層的意義(分層註解)。
Spring3.0爲咱們引入了組件自動掃描機制,它能夠在類路徑底下尋找標註了@Component、@Service、@Controller、@Repository註解的類,
並把這些類歸入進spring容器中管理。
除了@Component外,Spring提供了3個功能基本和@Component等效的註解
功能介紹
@Service用於標註業務層組件(如Service層)
@Controller用於標註控制層組件(如struts中的action層)
@Repository用於標註數據訪問組件,(如DAO層組件)。
而@Component泛指組件,當組件很差歸類的時候,咱們可使用這個註解進行標註。(好比測試類)