1. 程式人生 > >第一天:Spring Core IoC 的學習(工廠的Bean裝配管理)

第一天:Spring Core IoC 的學習(工廠的Bean裝配管理)

Spring Core IoC 的學習(工廠的Bean裝配管理)3.2 版本

目錄

一、 Spring技術概述

1、什麼是Spring : Spring是分層的JavaSE/EE full-stack(一站式) 輕量級開源框架

2、 Spring的核心 : IoC 控制反轉 和 Aop 面向切面程式設計

3、 Spring的由來 : 作者 Rod Johnson

4、 Spring 框架優點

5、Spring 包括哪些東西?

二、 Spring 控制反轉案例快速入門

1、下載Spring最新開發包

2、複製Spring開發 jar包到工程

3、理解IoC控制反轉和DI依賴注入

4、編寫Spring核心配置檔案

5、在程式中讀取Spring配置檔案,通過Spring框架獲得Bean,完成相應操作

三、 Spring 工廠介面

四、 在MyEclipse 配置Spring的xml檔案提示

    1、 聯網後,自動快取路徑檔案到本地,提供提示功能    

    2、 無法聯網 ,需要配置 xsd schema檔案位置

五、 IoC容器裝配Bean(xml配置方式)

       1、 Spring 提供配置Bean 三種例項化方式

    1)使用類構造器例項化(預設無引數)

    2)使用靜態工廠方法例項化(簡單工廠模式)

    3)使用例項工廠方法例項化(工廠方法模式)

2、 Bean的其它屬性配置

3、 Bean的生命週期

4、Spring的Bean屬性的依賴注入

第一種 構造器注入 ,通過 元素完成注入

第二種 setter方法注入, 通過 元素完成注入

5、 集合屬性的注入

1) 注入List (或者陣列)

2)  注入Set

3) 注入Map

4)  注入Properties

6、 在Spring框架中引入多個XML配置檔案

    第一種 並列引入多個XML

    第二種 引入總xml檔案,在總xml檔案引入 子xml檔案

六、Ioc容器裝配Bean(註解方式)

1、 搭建環境

2、 使用註解方式進行Bean註冊

3、 屬性依賴注入

    1) 簡單屬性的注入 通過 @Value註解完成

    2) 複雜屬性注入,通過@Autowired註解 完成Bean自動裝配

    3) 使用@Resource註解 完成複雜物件Bean裝配

4、Bean其它屬性設定

5、 Spring3.0 提供 註冊Bean的註解

6、 xml和註解混合使用

七、在web專案中整合Spring

1、 直接在Servlet 載入Spring 配置檔案

2、匯入spring-web.jar

3、配置web.xml

4、 修改Servlet程式碼

八、Spring 整合 junit4 測試

1、 匯入spring-test.jar

2、 編寫測試用例


一、 Spring技術概述

1、什麼是Spring : Spring是分層的JavaSE/EE full-stack(一站式) 輕量級開源框架

    * JavaEE 程式在伺服器端被分為三層 (Web層【表現層】、業務邏輯層、資料訪問層【整合層、持久層】)
    * struts2 是表現層MVC的框架
    * hibernate 是資料訪問層(持久層)的完全ORM框架

Spring框架中包括JavaEE 三層的 每一層的解決方案 (一站式)
    * web層  SpringMVC
    * 業務層 Spring Bean管理、AOP、事務管理
    * 持久層 Spring JDBCTemplate、 ORM模組(整合其他持久層框架)

2、 Spring的核心 : IoC 控制反轉 和 Aop 面向切面程式設計

3、 Spring的由來 : 作者 Rod Johnson

    2002年 Expert One-to-One J2EE Design and Development  (分析J2EE開發 使用技術 EJB)
    2004年 Expert One-to-One J2EE Development without EJB (客觀分析J2EE開發需要什麼,推出一個新的框架, 後來Spring)

sun 公司在最早J2EE規範中,提供業務層解決方案 EJB

Spring出現就是為了解決JavaEE開發實際問題,輕量級, 相比EJB比較繁重、複雜的解決方案

4、 Spring 框架優點

* 方便解耦,簡化開發
Spring就是一個大工廠,可以將所有物件建立和依賴關係維護,交給Spring管理
* AOP程式設計的支援
Spring提供面向切面程式設計,可以方便的實現對程式進行許可權攔截、執行監控等功能
* 宣告式事務的支援
只需要通過配置就可以完成對事務的管理,而無需手動程式設計
* 方便程式的測試
Spring對Junit4支援,可以通過註解方便的測試Spring程式
* 方便整合各種優秀框架
Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支援
* 降低JavaEE API的使用難度
Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠端呼叫等),都提供了封裝,使這些API應用難度大大降低

5、Spring 包括哪些東西?

   * 核心技術 IoC 和 AOP
   * 資料訪問 (持久層解決方案)
   * Web層解決方案  SpringMVC
   * 整合 (整合其他開源框架)

 

二、 Spring 控制反轉案例快速入門

1、下載Spring最新開發包

http://www.springsource.org/download/community 下載spring3.2 的開發包
目錄結構
    * docs 存放API和 規範文件
    * libs 開發jar包
    * schemas 開發過程中需要匯入xml的schema 約束

2、複製Spring開發 jar包到工程

    複製核心容器包含jar包 (beans、core、context、expression language)
    spring 的 jar包 需要依賴 commons-logging的 jar (commons-logging 類似 slf4j 是通用日誌元件,需要整合 log4j )

* 提示:spring3.0.X 版本 asm jar包 已經被合併到 spring core包中

3、理解IoC控制反轉和DI依賴注入

IoC: Inverse of Control 反轉控制的概念,就是將原本在程式中手動建立HelloService物件的控制權,交由Spring框架管理,簡單說,就是建立HelloService物件控制權被反轉到了Spring框架

DI:Dependency Injection 依賴注入,在Spring框架負責建立Bean物件時,動態的將依賴物件注入到Bean元件

面試題: IoC 和 DI的區別?
IoC 控制反轉,指將物件的建立權,反轉到Spring容器 , DI 依賴注入,指Spring建立物件的過程中,將物件依賴屬性通過配置進行注入(設定)

4、編寫Spring核心配置檔案

在src目錄建立 applicationContext.xml
在 docs\spring-framework-reference\html 找到 xsd-config.html

5、在程式中讀取Spring配置檔案,通過Spring框架獲得Bean,完成相應操作

載入classpath (src):
     new ClassPathXmlApplicationContext("applicationContext.xml");
載入磁碟路徑:
     new FileSystemXmlApplicationContext("applicationContext.xml");
建立Spring 核心工廠物件

通過工廠的getBean 獲得配置例項物件 (IHelloService) applicationContext.getBean("helloService");

 

三、 Spring 工廠介面

    BeanFactory 介面 和 ApplicationContext 介面區別 ?
    * ApplicationContext 介面是 繼承 BeanFactory 介面 ,Spring 核心工廠是BeanFactory ,BeanFactory 採取延遲載入,第一次getBean時才會初始化Bean , ApplicationContext 是會在載入配置檔案時 初始化Bean
    * ApplicationContext是對BeanFactory擴充套件
        國際化處理
        事件傳遞
        Bean自動裝配
        各種不同應用層的Context實現

開發中基本都在使用ApplicationContext, web專案使用WebApplicationContext ,很少用到BeanFactory
    BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    IHelloService helloService = (IHelloService) beanFactory.getBean("helloService");
    helloService.sayHello();

 

四、 在MyEclipse 配置Spring的xml檔案提示

    xml需要匯入schema約束,約束指向網路路徑

    1、 聯網後,自動快取路徑檔案到本地,提供提示功能
    2、 無法聯網 ,需要配置 xsd schema檔案位置

        到解壓spring/schemas/beans/spring-beans-3.2.xsd
        選擇schema location 方式
        複製網路路徑 http://www.springframework.org/schema/beans/spring-beans.xsd

 

五、 IoC容器裝配Bean(xml配置方式)
1、 Spring 提供配置Bean 三種例項化方式

    1)使用類構造器例項化(預設無引數)

        <bean id="bean1" class="cn.itcast.spring.b_instance.Bean1"></bean>

    2)使用靜態工廠方法例項化(簡單工廠模式)

        <bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2"></bean>

    3)使用例項工廠方法例項化(工廠方法模式)

        <bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory"></bean>
        <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>

2、 Bean的其它屬性配置

    <bean>元素的id屬性 和 name屬性的區別
早期Spring開發中 Bean的 id屬性 ,遵守xml語法 id約束
    * id 的命名要滿足XML對ID屬性命名規範 必須以字母開始,可以使用字母、數字、連字元、下劃線、句話、冒號
使用name屬性,就可以使用很多特殊字元  , 早期在struts1 和 spring整合
    <bean name="/login" class="....LoginAction" />  name中含有/ ,使用id會報錯

****** 如果元素沒有id只有name ,name 屬性值可以作為id 使用

    <bean>元素scope屬性
        * scope="singleton" 單例 ,在Spring IoC容器中僅存在一個Bean例項 (預設的scope)
        * scope="prototype" 多例 ,每次從容器中呼叫Bean時,都返回一個新的例項,即每次呼叫getBean()時 ,相當於執行new XxxBean()
        * scope="request" 用於web開發,將Bean放入request範圍 ,request.setAttribute("xxx") , 在同一個request 獲得同一個Bean
        * scope="session" 用於web開發,將Bean 放入Session範圍,在同一個Session 獲得同一個Bean
        * scope="globalSession" 一般用於Porlet應用環境 , 分散式系統存在全域性session概念 ,如果不是porlet環境,globalSession 等同於Session
    在開發中主要使用 scope="singleton"、 scope="prototype"

3、 Bean的生命週期

    在配置 <bean> 元素,通過 init-method 指定Bean的初始化方法,通過 destroy-method 指定Bean銷燬方法
    *  destroy-method 只對 scope="singleton" 有效
    *  銷燬方法,必須關閉ApplicationContext物件,才會被呼叫
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        applicationContext.close();

Bean的完整生命週期 (十一步驟)(瞭解)
1、instantiate bean物件例項化(構造器)
2、populate properties 封裝屬性
3、如果Bean實現BeanNameAware 執行 setBeanName(瞭解)
4、如果Bean實現BeanFactoryAware 或者 ApplicationContextAware 設定工廠 setBeanFactory 或者上下文物件 setApplicationContext(瞭解)
5、如果存在類實現 BeanPostProcessor(後處理Bean) ,執行postProcessBeforeInitialization
6、如果Bean實現InitializingBean 執行 afterPropertiesSet
7、呼叫<bean init-method="init"> 指定初始化方法 init
8、如果存在類實現 BeanPostProcessor(處理Bean) ,執行postProcessAfterInitialization
9、執行業務處理
10、如果Bean實現 DisposableBean 執行 destroy
11、呼叫<bean destroy-method="customerDestroy"> 指定銷燬方法 customerDestroy

第三步和第四步,使Bean 瞭解Spring容器
第五步和第八步,使用BeanPostProcessor 就是鉤子函式,作用用來對Bean物件進行擴充套件

問題: 在userDAO物件所有方法上 新增執行時間監控
    解決: 使用 BeanPostProcessor 完成

4、Spring的Bean屬性的依賴注入

  支援 構造器注入 和 setter 方法注入

第一種 構造器注入 ,通過 <constructor-arg> 元素完成注入

    <bean id="car" class="cn.itcast.spring.e_di.Car">
        <!-- 通過構造器引數,完成屬性注入 -->
        <constructor-arg index="0" type="java.lang.String" value="保時捷"></constructor-arg> <!-- 第一個引數 String型別引數 -->
        <constructor-arg index="1" type="double" value="1000000"></constructor-arg>
    </bean>

第二種 setter方法注入, 通過<property> 元素完成注入

    <bean id="car2" class="cn.itcast.spring.e_di.Car2">
        <!-- 通過 property 元素完成屬性注入 -->
        <property name="name" value="寶馬"></property>
        <property name="price" value="500000"></property>
    </bean>

* 使用 <property> 元素 ref屬性(當前bean的屬性引用另外的bean),引入另一個Bean物件,完成Bean之間注入
    <bean id="employee" class="cn.itcast.spring.e_di.Employee">
        <property name="name" value="張三"></property>
        <property name="car2" ref="car2"></property> <!-- ref引用其他Bean的id或者name -->
    </bean>

* 名稱空間 p的使用  (Spring2.5 新特性)
    spring2.5版本 引入名稱空間p, 簡化屬性注入的配置
p:<屬性名>="xxx" 引入常量值
p:<屬性名>-ref="xxx" 引用其它Bean物件
    1) 引入p名稱空間
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:p="http://www.springframework.org/schema/p"
               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">
    2) 改寫<property>注入為 p名稱空間注入
        <bean id="car2" class="cn.itcast.spring.e_di.Car2">
            <!-- 通過 property 元素完成屬性注入 -->
            <property name="name" value="寶馬"></property>
            <property name="price" value="500000"></property>
        </bean>

        <bean id="employee" class="cn.itcast.spring.e_di.Employee">
            <property name="name" value="張三"></property>
            <property name="car2" ref="car2"></property> <!-- ref引用其他Bean的id或者name -->
        </bean>
    改寫
        <bean id="car2" class="cn.itcast.spring.e_di.Car2" p:name="寶馬" p:price="1000000"></bean>
        <bean id="employee" class="cn.itcast.spring.e_di.Employee" p:name="李四" p:car2-ref="car2"></bean>

* spring3.0之後引入 spEL 表示式
    1、 完成物件之間注入
        <property name="car2" ref="car2"></property>
        改寫為
        <property name="car2" value="#{car2}"></property>
    2、 使用另一個Bean屬性完成注入
        <bean id="carInfo" class="cn.itcast.spring.e_di.CarInfo"></bean>
        <bean id="car2_2" class="cn.itcast.spring.e_di.Car2">
            <property name="name" value="#{carInfo.name}"></property>
        </bean>
    3、 使用另一個Bean方法完成注入
        <bean id="carInfo" class="cn.itcast.spring.e_di.CarInfo"></bean>
        <bean id="car2_2" class="cn.itcast.spring.e_di.Car2">
            <property name="name" value="#{carInfo.name}"></property>
            <property name="price" value="#{carInfo.caculatePrice()}"></property>
        </bean>

5、 集合屬性的注入

    spring提供專門標籤完成 List、Set、Map、Properties 等集合元素屬性注入

1) 注入List (或者陣列)

    <property name="hobbies">
            <list>
                <!-- <value>注入簡單型別,<ref />注入複雜型別 -->
                <value>音樂</value>
                <value>體育</value>
            </list>
    </property>

2)  注入Set

    <property name="numbers">
            <set>
                <value>10</value>
                <value>6</value>
                <value>15</value>
            </set>
    </property>

3) 注入Map

    <property name="map">
            <map>
<!--             複雜型別    <entry key-ref="" value-ref=""></entry> -->
                <entry key="name" value="itcast"></entry>
                <entry key="address" value="北京"></entry>
            </map>
    </property>

4)  注入Properties

    * java.utils.Properties 類 繼承  java.utils.HashTable
    Properties key和value都是String型別
    例如:
        <property name="properties">
            <props>
                <prop key="company">傳智播客</prop>
                <prop key="pnum">100</prop>
            </props>
        </property>

6、 在Spring框架中引入多個XML配置檔案

    第一種 並列引入多個XML

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");

    第二種 引入總xml檔案,在總xml檔案引入 子xml檔案

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    * 在applicationContext.xml 中
        <import resource="classpath:bean1.xml"/>
        <import resource="classpath:bean2.xml"/>

在開發中主要使用 第二種 , 將配置檔案分離配置 便於維護管理

 

六、Ioc容器裝配Bean(註解方式)

1、 搭建環境

    匯入jar 和 xml方式開發 是相同的

2、 使用註解方式進行Bean註冊

    xml 方式: <bean id="" class="">
    spring2.5版本 提供一組註解,完成Bean註冊
    * @Component  描述Spring框架中Bean

第一步 編寫Class,在宣告上 新增 @Component
    @Component("helloService")(註解:元素中只有一個value屬性,value可以省略)
    // <bean id="helloService" class="...." />
    public class HelloService {
    }

第二步 編寫applicationContext.xml
    通知Spring 註解類所在包
    * 需要引入 context 名稱空間
<context:component-scan base-package="cn.itcast.spring.a_beandefinition"></context:component-scan>

spring2.5 引入@Component 等效三個衍生註解
    * @Repository 用於對DAO實現類進行標註 (持久層)
    * @Service 用於對Service實現類進行標註 (業務層)
    * @Controller 用於對Controller實現類進行標註 (表現層)

3、 屬性依賴注入

    1) 簡單屬性的注入 通過 @Value註解完成

    @Service("userService")
    public class UserService {
        // 注入name屬性
        @Value("itcast")
        private String name;
    }
 
    不需要setter方法

    2) 複雜屬性注入,通過@Autowired註解 完成Bean自動裝配

        @Autowired 預設按照型別進行注入

    @Service("userService")
    public class UserService {
        @Autowired
        // 複雜物件
        private UserDAO userDAO;
    }

    @Repository("userDAO")
    public class UserDAO {
    }

========================== @Value @Autowired註解都可以修飾 成員變數 或者 setter方法,如果修改成員變數,不需要提供setter方法
    @Autowired註解 結合 @Qualifer註解 按照名稱注入
        @Service("userService")
        public class UserService {
            @Autowired
            @Qualifier("uDAO")
            // 複雜物件
            private UserDAO userDAO;
        }

        @Repository("uDAO")
        public class UserDAO {

        }

    3) 使用@Resource註解 完成複雜物件Bean裝配

        @Resource和@Autowired註解功能相似

    @Autowired
    @Qualifer("userDAO")
    private UserDAO userDAO ;
    等價於
    @Resource(name="userDAO")
    private UserDAO userDAO ;

4、Bean其它屬性設定

    1) 指定Bean的初始化方法和銷燬方法(註解)  <bean init-method="" destroy-method="" />
        @PostConstruct  作用 init-method
        @PreDestroy  作用 destroy-method
    2) Bean的作用範圍  <bean scope="" />
        @Scope 註解 ,預設作用域 singleton 單例

5、 Spring3.0 提供 註冊Bean的註解

    @Configuration 指定POJO類為Spring提供Bean定義資訊
    @Bean 提供一個Bean定義資訊

    @Configuration
    public class BeanConfig {
        // 提供兩個方法 獲得Car和Product物件
        @Bean(name = "car")
        public Car initCar() {
            Car car = new Car();
            car.setName("大眾");
            car.setPrice(10000);
            return car;
        }

        @Bean(name = "product")
        public Product showProduct() {
            Product product = new Product();
            product.setPname("空調");
            product.setPnum(100);
            return product;
        }
    }

使用配置Bean 被Spring 掃描到 就可以了

6、 xml和註解混合使用

    很多企業開發者 還是採用 xml作為主流配置
* Bean 註冊 通過XML完成
* 注入使用 @Autowired 註解完成

<context:annotation-config/> 啟用四個註解 使@Resource、@ PostConstruct、@ PreDestroy、@Autowired註解生效

結論 :
   1、 xml配置 和 註解配置 效果完全相同
   2、 如果Bean 來自第三方, 必須使用xml(eg:c3p0 配置)
   3、 Spring3.0 Bean註冊方式, 使用比較少,主要用於Bean 構造邏輯及其複雜

 

七、在web專案中整合Spring

1、 直接在Servlet 載入Spring 配置檔案

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    HelloService helloService = (HelloService) applicationContext.getBean("helloService");
    helloService.sayHello();
問題: 每次請求都會載入Spring環境,初始化所有Bean ,效能問題 !!!
解決方案一 : 將程式碼放入Servlet init 中 , 無法保證所有Servlet都能使用 ApplicationContext
解決方案二 : ServletContext ----- tomcat啟動時, 載入Spring配置檔案,獲得物件 ,放入ServletContext
    * ServletCointextListener

2、匯入spring-web.jar

    儲存 ContextLoaderListener 完成在Servlet初始化階段,載入Spring配置檔案,將工廠物件放入 ServletContext

3、配置web.xml

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
* 預設讀取 WEB-INF/applicationContext.xml
    配置 全域性引數 contextConfigLocation 指定 配置檔案位置
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

4、 修改Servlet程式碼

    從ServletContext中獲得 Spring工廠
    第一種:
    WebApplicationContext applicationContext = (WebApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    第二種:
    WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

 

八、Spring 整合 junit4 測試

1、 匯入spring-test.jar
2、 編寫測試用例

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml") // 指定配置檔案位置
    public class HelloServiceTest {
        @Autowired
        private HelloService helloService; // 注入需要測試物件

        @Test
        // 測試
        public void demo2() {
            helloService.sayHello(); // 呼叫測試方法
        }
    }