Spring從入門到精通(一)


 

1.     說在前面

怎樣的架構的程序,我們認為是一個優秀的架構?

 

我們考慮的標准:可維護性好,可擴展性好,性能。

 

 

什么叫可擴展性好?

答:就是可以做到,不斷的增加代碼,但是可以不修改原來的代碼的程序。

 

 

如何讓程序的可維護性好,可擴展性好呢?

業界有一個公認的標准,高內聚,低耦合。

 

高內聚:就是盡量將代碼寫在與之功能描述一致的模塊中。如User表的操作寫在UserDAO里面就不用寫在非UserDAO的類里面。

 

低耦合:就是盡量減少類與類之間的直接關系。(重點)

 

Spring框架就是通過IoC(控制反轉)實現程序的解耦。從而提高程序的維護性和擴展性。

 

 

 

 

2.     Spring概述

 

2.1.  Spring是什么

Spring是一個JavaEE輕量級的一站式開發框架。

 

JavaEE: 就是用於開發B/S的程序。(企業級)

輕量級:使用最少代碼啟動框架,然后根據你的需求選擇,選擇你喜歡的模塊使用。

重量級:早期有的EJB,開發一個HelloWorld程序都需要引入EBJ的全部模塊

一站式:提供了,表示層(Struts2/SpringMVC),服務層,持久層的所有支持。

 

2.2.  Spring框架出現的背景

在世界第一套有Java官方Sun公司推出的企業級開發框架EJB出現后,瞬間風靡全球。被各大公司所應用。

 

Spring之父,Rod Jonhson是一個音樂博士,在Sun公司的大力推廣下,也成為EJB框架的使用者。

 

在深入研究完EJB框架(由Sun主導開發的一個JavaEE開發框架),無法接收這么一個框架被吹成世界第一,具體查看他吐槽EJB的書《Expert one on one J2EE design and development》

 

其中突出被他吐槽最厲害的一個點就EJB的重量級,就是只要使用EJB里面任何一個組件。都要將所有EJB的jar導進去。

 

於是他就提供了一個他的解決方案:輕量級的一站式企業開發框架。

 

那么什么是輕量級呢?

就是除內核模塊(4個jar),其他模塊由開發者自由選擇使用,同時支持整合其他框架。

 

也可以稱為就是可插拔式開發框架,像插頭和插座一樣,插上就用。這就是Spring框架核心理念。(Ioc)

 

 

那么什么是一站式呢?

就是Spring框架提供涵蓋了JavaEE開發的表示層,服務層,持久層的所有組件功能。也就是說,原則上,學完一套Spring框架,不用其他框架就可以完成網站一條流程的開發。

 

如圖:

 

 

2.3.  Spring框架的作用

根據以上章節的描述。Spring是一個JavaEE一站式的開發框架。它提供的功能涵蓋了JavaEE程序中的表示層,服務層,持久層功能組件。這意味着,使用了Spring框架,一個框架就可以滿足整個JavaEE程序的開發。

 

但Spring框架,更加強調的是它的輕量級(模塊的可插拔)!!也就是說,除了內核以外模塊,如果你不想使用可以不用,它能夠整合任何第三方的框架。

 

所以,在現實開發中,Spring主要用於整合其他框架

 

2.4.  總結

  1. Spring是一個一站式的企業級(JavaEE)開發框架,意味着,僅僅使用一個Spring框架就可以滿足JavaEE開發的表示層,服務層,持久層的開發。
  2. Spring強調的理念是,輕量級。意味着Spring提供的功能模塊,除了內核模塊以外,開發人員可以選擇性使用。
  3. 所以,Spring框架在現實開發中,主要的功能用於整合,各種開發來開發項目。

2.5.  Spring框架包

Spring官方網站

https://spring.io/

2.5.1.  框架包的下載

Spring官方提供的Maven方式的項目下載。

https://start.spring.io/

 

但是基於簡單入門的原則,我們要通過導入包的方式來學習。需要下載框架的zip包

路徑為:http://repo.springsource.org/libs-release-local/org/springframework/spring/

 

2.5.2.  目錄說明

--根目錄

 

--類庫規則

 

 

--包說明

包名

說明

spring-aop-4.3.2.RELEASE.jar

實現了AOP的支持

spring-aspects-4.3.2.RELEASE.jar

AOP框架aspects支持包

spring-beans-4.3.2.RELEASE.jar

內核支撐包,實現了處理基於xml對象存取

spring-context-4.3.2.RELEASE.jar

內核支撐包,實現了Spring對象容器

spring-context-support-4.3.2.RELEASE.jar

容器操作擴展包,擴展了一些常用的容器對象的設置功能

spring-core-4.3.2.RELEASE.jar

內核支撐包,Spring的內核

spring-expression-4.3.2.RELEASE.jar

內核支撐包,實現了xml對Spring表達式的支持

spring-instrument-4.3.2.RELEASE.jar

提供了一些類加載的的工具類

spring-instrument-tomcat-4.3.2.RELEASE.jar

提供了一些tomcat類加載的的工具類,實現對應Tomcat服務的調用

spring-jdbc-4.3.2.RELEASE.jar

SpringJDBC實現包,一個操作數據庫持久層的子框架

spring-jms-4.3.2.RELEASE.jar

集成jms的支持,jms:Java消息服務。

spring-messaging-4.3.2.RELEASE.jar

集成messaging api和消息協議提供支持

spring-orm-4.3.2.RELEASE.jar

ORM框架集成包,實現了Hibernate,IBatis,JDO的集成。

spring-oxm-4.3.2.RELEASE.jar

Spring OXM對主流O/X Mapping框架做了一個統一的抽象和封裝。就是對應XML讀寫框架的支持

spring-test-4.3.2.RELEASE.jar

Spring集成JUnit測試

spring-tx-4.3.2.RELEASE.jar

事務代理的支持

spring-web-4.3.2.RELEASE.jar

SpringWeb通用模塊

spring-webmvc-4.3.2.RELEASE.jar

SpringMVC子框架

spring-webmvc-portlet-4.3.2.RELEASE.jar

Spring對門戶技術(portlet)的支持

spring-websocket-4.3.2.RELEASE.jar

Spring對websocket的支持

3.     入門示例

Spring之所以可以實現模塊的可插拔是支持依賴注入,所謂的依賴注入/控制反轉就是不用new就可以創建對象。

 

 

需求:使用Spring框架不用new創建一個對象。

 

3.1.  配置流程圖

 

 

 

 

  1. 創建一個普通的類。
  2. 創建一個Spring配置文件,用於描述類與類之間的關系。
  3. 創建ApplicationContext容器對象根據Spring配置文件的描述,將對象創建並且放在Spring容器里面。
  4. 使用ApplicationContext容器對象的getBean方法,調用Spring容器里面的對象。

 

3.2.  配置步驟說明

  1. 導入包
  2. 創建一個普通的類
  3. 創建一個Spring配置文件(去官方文檔上拷貝約束)
  4. 編寫一個測試類,使用ApplicationContext的子類對象根據配置文件創建容器。並且在容器里面獲得創建的對象

 

3.3.  配置步驟

3.3.1.  第一步:搭建環境

1.創建一個Java項目

 

--選中創建

 

--創建目錄結構

 

2.導入包,String的基礎支撐包和依賴的日志包復制到lib文件下,並且加入項目中

---導入Spring基礎支撐包

 

--導入Spring依賴的日志包

 

3.3.2.  -第二步:創建配置文件

1. 在項目的src下面創建配置文件applicationContext.xml中並完成配置文件的約束,約束查找位置(spring框架/docs/spring-framework-reference/html/beans.html)

<?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>

3.3.3.  第三步:創建對象到容器里面

  1. 創建一個類

package com.zj.service;

 

public class HelloWorldService {

   

    public void say(){

       System.out.println("--你好世界!--");

    }

 

}

 

  1. 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-4.2.xsd ">

  

   <!--

     <bean>標簽:用於聲明一個類,在啟動Spring框架的時候根據該配置的類創建對象到容器里面

     name

    -->

   <bean name="helloWorldService" class="com.zj.service.HelloWorldService"></bean>

</beans>

  1. 測試使用getBean獲得容器中的對象。

package com.zj.test;

 

import org.junit.Test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import com.zj.service.HelloWorldService;

 

public class HelloWorldServiceTest {

   

    @Test

    public void say(){

        //創建一個ApplicationContext對象,根據xml配置創建一個對象

        //直接讀取Spring的src目錄下的配置文件的子類是ClassPathXmlApplicationContext

        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

        HelloWorldService helloWorldService = context.getBean("helloWorldService", HelloWorldService.class);

        //調用方法

        helloWorldService.say();

    }

}

 

通過代碼得到,Spring框架果然不用new就可以創建對象。

3.4.  Eclipse提示xml文件語法

1. 聯網

2.手動關聯約束window->preferences

3.5.  Spring容器的兩個實現

 

 

ClassPathXmlApplicationContext:通過classpath路徑直接獲得加載的xml文件(推薦使用)

FileSystemXmlApplicationContext:通過文件路徑來獲得加載的xml文件。

 

3.6.  ApplicationContext類圖結構圖(了解)

Spring框架容器對象的繼承體系

 

 

通過結構圖可以看到,Spring容器頂級接口是BeanFactory,ApplicationContext是它的子接口。

 

4.     Spring的IOC控制反轉和依賴注入-重點-spring核心之一

IoC:Inverse of Control(控制反轉):

讀作“反轉控制”,更好理解,不是什么技術,而是一種設計思想,好比於MVC。就是將原本在程序中手動創建對象的控制權,交由Spring框架來管理。

正控:若調用者需要使用某個對象,其自身就得負責該對象的創建。

反控:調用者只管負責從Spring容器中獲取需要使用的對象,不關心對象的創建過程,也就是把創建對象的控制權反轉給了Spring框架。

(Don’t call me ,I’ll call you)

DI:Dependency Injection(依賴注入)

從字面上分析:

IoC:指將對象的創建權,反轉給了Spring容器;

DI :指Spring創建對象的過程中,將對象依賴屬性(簡單值,集合,對象)通過配置設值給該對象。

IoC和DI其實是同一個概念的不同角度描述,DI相對IoC而言,明確描述了“被注入對象依賴IoC容器配置依賴對象”。

 

Container:容器,在生活中容器就是一種盛放東西的器皿,從程序設計角度看作是裝對象的對象,因為存在對對象的存入、取出等操作,所以容器還要管理對象的生命周期。

 

4.1.  IoC(控制反轉)的概述

Spring號稱是一個可以實現模塊可插拔的JavaEE開發框架。那么它是如何實現程序的可插拔的呢?

 

實現程序可以插拔的核心理念就是,控制反轉(Inversion of Control,英文縮寫為IoC)

 

 

所謂的控制反轉,就是將代碼的調用權從調用方轉移給被調用方(服務提供方)。

 

如圖所示:

  1. 強耦合調用方式

將A調用B的對象修改為C類的對象,修改的是調用方的代碼,所以我們認為代碼的調用權在調用方。

 

 

 

  1. 基於IoC(控制反轉)的調用方式

 

將上圖的需求,修改為使用Ioc的調用代碼方式。就是將代碼的控制權從調用方修改為被調用方,意味着,代碼的調用權轉移給被調用方(我們也稱為服務方),不用修改調用方的的代碼

只要修改配置文件就實現對象的切換。

 

如下圖:將A類調用B類的對象修改為C類的對象,修改的是被調用方的配置文件的代碼,所以代碼的調用權轉移到了被調用方。通過控制反轉,我們可以實現增加模塊或者移除模塊統一由配置文件關聯,增加或者移除模塊,配置XML配置文件即可。

 

我們將代碼的調用權(控制權)調用方轉移給被調用方(服務提供方)的設計模式稱為控制反轉(IoC)

 

 

 

根據上圖可以的得出,實現一個IoC的框架,必須要解決兩個問題:

1.被調用方(服務方),在程序啟動時就要創建好對象,放在一個容器里面。

2.調用方使用一個接口或類的引用(不用使用new),就可以創建獲得對象。

 

我們將這種不用new,而是根據接口或者類的引用就可以從被調用的容器里獲得創建的對象的方式稱為依賴注入。

 

所以,控制反轉(Ioc),就是依賴注入加上面向接口的編程思想的實現。

 

在這里,我們首先抓住一個重點:Spring之所以可以實現可插拔程序,是實現了不用new,使用類或接口就可以獲得獲得對象!

 

4.2.  項目目錄結構

 

4.3.  示例代碼

4.3.1.  CustomerService接口代碼

package cn.zj.spring.service;

 

public interface CustomerService {

   /**

    * 保存方法

    */

   public void save();

}

 

 

4.3.2.  CustomerServiceImpl子類

package cn.zj.spring.service.impl;

 

import cn.zj.spring.service.CustomerService;

 

public class CustomerServiceImpl implements CustomerService {

 

   @Override

   public void save() {

      System.out.println("-保存客戶-CustomerServiceImpl");

   }

 

}

 

 

4.3.3.  CustomerServiceImpl2子類

package cn.zj.spring.service.impl;

 

import cn.zj.spring.service.CustomerService;

 

public class CustomerServiceImpl2 implements CustomerService {

 

   @Override

   public void save() {

      System.out.println("-保存客戶-CustomerServiceImpl2");

   }

 

}

 

 

4.3.4.  CustomerClient類(調用方)

package cn.zj.spring.client;

 

import cn.zj.spring.service.CustomerService;

 

public class CustomerClient {

  

   //1.聲明一個父接口的引用

   private CustomerService customerService;

 

   //2.使用set方法注入對象,我們將通過方法注入的對象的方式稱為依賴注入

   public void setCustomerService(CustomerService customerService) {

      this.customerService = customerService;

   }

 

   public void save(){

      //調用服務端的方法

      customerService.save();;

   }

  

}

 

4.3.5.  配置文件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框架的時候根據該配置的類創建對象到容器里面 name -->

<!-- <bean name="customerServiceImpl" class="cn.zj.spring.service.impl.CustomerServiceImpl"></bean> -->

   <!--

   CustomerServiceImpl修改為CustomerServiceImpl2的配置

    -->

    <bean name="customerServiceImpl" class="cn.zj.spring.service.impl.CustomerServiceImpl2"></bean>

 

    <bean name="customerClient" class="cn.zj.spring.client.CustomerClient">

         <!-- 對應set方法關聯的對象 customerService

                  name:關聯對應的set方法,關聯規則:xxx對應setXxx();如:customerService() 對應setCustomerService()

                  ref:指向容器中的對象

          -->

         <property name="customerService" ref="customerServiceImpl"></property>

    </bean>

 

</beans>

 

4.3.6.  測試代碼

package cn.zj.spring.test;

 

 

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import cn.zj.spring.client.CustomerClient;

 

public class ClientTest {

   @Test

   public void testSave() throws Exception {

      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

      CustomerClient customerClient = context.getBean("customerClient", CustomerClient.class);

      // 調用方法

      customerClient.save();

   }

}

 

4.3.7.  7.測試結果

 

 

 

5.     標簽說明

5.1.  alias標簽

作用:為已配置的bean設置別名

 

<?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="user" name="test" class="cn.zj.spring.pojo.User"/>

  <!--

             標簽alias: 為已配置的bean設置別名

                         屬性name: 必要屬性, 代表為哪一個bean配置別名,

                                     此屬性的值為其他bean標簽的id或name屬性值

                         屬性alias: 必要屬性, 代表新命名的別名是什么

   -->

  <alias name="user" alias="user1"/>

                        

</beans>

 

--測試代碼

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import cn.zj.entity.User;

 

public class Test {

  public static void main(String[] args) {

             // 讀取Spring配置文件

             ApplicationContext context = new ClassPathXmlApplicationContext(

                                     "applicationContext.xml");

 

             // 通過id獲取User對象

             User user = (User) context.getBean("user");

             // 測試對象

             System.out.println(user);

             System.out.prntln("=====================================");

             // 通過alias獲取User對象

             user = (User) context.getBean("user1");

             // 測試對象

             System.out.println(user);

  }

}

 

 

5.2.  bean標簽的配置

5.2.1.   bean標簽作用

用於聲明一個類,在啟動Spring框架的時候根據該配置的類創建對象到容器里面

5.2.2.  屬性說明

    <!-- <bean>標簽:用於聲明一個類,在啟動Spring框架的時候根據該配置的類創建對象到容器里面

         name:設置對象名(唯一標識符),可以有多個名稱,每個名稱用逗號隔開 :  name1,name2

         id:設置對象名(唯一標識符,功能和name一樣)

         class:用於指定對象對應的類名

         scope:用於設置的對象的作用范圍,可選參數如下:

            *singleton:單例(默認)

                對象出生:當程序加載配置文件創建容器時,創建

                對象活着:只要容器還在,一直活着

                對象死亡:應用停止,容器銷毀,對象死亡

            *prototype:多例(原型對象)

                對象出生:當程序加載配置文件創建容器時,創建

                對象活着:只要對象被使用,一直活着

                對象死亡:對象長時間不用,會被Java垃圾回收機制回收

            *reqeust:web項目中,Spring將創建的對象放在request作用域中

            *session:web項目中,Spring將創建的對象放在session作用域中

            *globalSession:web項目中,應用域portlet環境,如果沒有protlet環境相當於session

        init-method:設置創建對象的時候,調用初始化方法

        destroy-method:設置對象被回收時,調用注銷的方法

       

      -->

    <bean name="customerServiceImpl"    class="com.zj.spring.service.impl.CustomerServiceImpl"></bean>

 

 

5.2.3.  Bean作用范圍

<bean id="" class="" scope="作用域"/>

singleton

 

 單例 ,在Spring IoC容器中僅存在一個Bean實例 (默認的scope)

prototype

多例 ,每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時 ,相當於執行new XxxBean():

request

用於web開發,將Bean放入request范圍 ,request.setAttribute("xxx") , 在同一個request 獲得同一個Bean

 

session

用於web開發,將Bean 放入Session范圍,在同一個Session 獲得同一個Bean

 

在開發中主要使用 scope="singleton" scope="prototype"

對於MVC中的Action/Controller使用prototype類型,其他使用singleton

 

<!--

         <bean id="" class="" scope="作用域"/>

         scope : 配置當前bena的范圍大小

        

         singleton: 單例 ,在Spring IoC容器中僅存在一個Bean實例 (默認的scope)

         prototype: 多例 ,每次從容器中調用Bean時,都返回一個新的實例,即每次調用getBean()時 ,相當於執行new XxxBean()

     -->

   

<bean id="someBean" class="cn.zj.spring.pojo.SomeBean" scope="prototype"></bean>

 

在Web開發的三層架構中

 

Web:一般都是多例

Service :單例

DAO :單例

 

5.3.  實例化Bean的四種方式

5.3.1.  構造器實例化(無參數構造器),最標准,使用最多。

public class SomeBean1 {

    public SomeBean1() {

         System.out.println("SomeBean.SomeBean1()");

    }

}

配置文件

<!-- ①.構造器實例化(無參數構造器),最標准,使用最多。 -->

    <bean id="someBean1" class="cn.zj.spring.pojo.SomeBean1"></bean>

 

 

5.3.2.  通過靜態方法工廠創建(了解)

--靜態工廠類

SomeBean2/SomeBean2Facotry

public class SomeBean2 {

    public SomeBean2() {

         System.out.println("SomeBean.SomeBean2()");

    }

}

public class SomeBean2Facotry {

    //靜態工廠方法

    public static SomeBean2 getSomeBean2() {

         System.out.println("執行靜態工廠方法");

         return new SomeBean2();

    }

}

 

--靜態工廠配置

<!-- ②.靜態工廠方法實例化:解決系統遺留問題 -->

    <bean id="someBean2" class="cn.zj.spring.pojo.SomeBean2Facotry"

         factory-method="getSomeBean2"></bean>

 

5.3.3.  通過實體工廠創建(了解)

--實體工廠

public class SomeBean3 {

    public SomeBean3() {

         System.out.println("SomeBean.SomeBean3()");

    }

}

public class SomeBean3Facotry {

    //實例工廠方法

    public SomeBean3 getSomeBean3() {

         System.out.println("執行實例工廠方法");

         return new SomeBean3();

    }

}

--配置方式

<!-- ③.實例工廠方法實例化:解決系統遺留問題 -->

    <!-- 1.配置工廠bean -->

    <bean id="someBean3Factory" class="cn.zj.spring.pojo.SomeBean3Facotry"></bean>

    <!-- 2.配置bena

         factory-bean : 創建bean的工廠對象對應的 id

         factory-method : 工廠bean中返回 bean對象的方法

     -->

    <bean id="someBean3" factory-bean="someBean3Factory" factory-method="getSomeBean3"/>

 

5.3.4.  實現FactoryBean接口實例化:實例工廠變種(了解)

實現FactoryBean接口,MyBatis和Spring集成就是使用的這種方式

此種方式,如果沒有使用Bean對應的對象,Spring就不會自動創建,只有在使用的時候Spring才會創建對應的對象

public class SomeBean4 {

    public SomeBean4() {

       System.out.println("SomeBean4.SomeBean4()");

    }

}

public class SomeBean4ObjectFactory implements FactoryBean<SomeBean4>{

 

    //返回的泛型類型對應的對象

    @Override

    public SomeBean4 getObject() throws Exception {

       SomeBean4 bean4 = new SomeBean4();

       return bean4;

    }

    @Override

    public Class<?> getObjectType() {

       return null;

    }

   

}

--配置方式

<!-- ④.實現FactoryBean接口實例化:實例工廠變種:集成其他框架使用:LocalSessionFactoryBean -->

<bean id="someBean4" class="cn.zj.domian.SomeBean4ObjectFactory"></bean>

5.4.  初始化和銷毀方法

比如DataSource,SessionFactory最終都需要關閉資源:在Bean銷毀之前,都要調用close方法.

<bean id="someBean" class="......"

        init-method="該類中初始化方法名" destroy-method="該類中銷毀方法名">

</bean>

init-method:bean生命周期初始化方法,對象創建后就進行調用

destroy-method:容器被銷毀的時候,如果bean被容器管理,會調用該方法。

 

default-init-method

 

分析原理:

如果bean的scope="prototype",那么容器只負責創建和初始化,它並不會被spring容器管理。交給用戶自己調用.

<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"

        

     default-init-method="init">

    <!-- 配置全局初始化方法,如果有100個bean中都有init方法,那么只要Spring容器一啟動,bean對象一創建

         默認對象中只要有 init方法,都全部會執行:一般不建議使用

     -->

    <!--

    init-method : 配置初始化方法名

    destroy-method : 配置銷毀方法名

     -->

    <bean id="someBean" class="cn.zj.spring.pojo.SomeBean"

         init-method="init"

         destroy-method="destory"></bean>

</beans>

6.     Spring依賴注入 DI

DI:Dependency Injection(依賴注入)

從字面上分析:

IoC:指將對象的創建權,反轉給了Spring容器;

DI :指Spring創建對象的過程中,將對象依賴屬性(簡單值,集合,對象)通過配置設值給該對象。

IoC和DI其實是同一個概念的不同角度描述,DI相對IoC而言,明確描述了“被注入對象依賴IoC容器配置依賴對象”。

 

所謂的依賴注入,就是屬性不創建對象,通過配置文件的配置將Spring容器里面的對象注入給對應的屬性

 

依賴注入有四種方式

 

6.1.  setter注入,(屬性注入)

1.setter注入,(也可以稱之為屬性注入)

使用setter注入:

1,使用bean元素的<property>子元素設置;

    1,簡單類型值,直接使用value賦值;

    2,引用類型,使用ref賦值;

    3,集合類型,直接使用對應的集合類型元素即可。

2,spring通過屬性的setter方法注入值;

3,在配置文件中配置的值都是string,spring可以自動的完成類型的轉換

 

public class Employee {

    private Integer age;

    private String name;

    private Department dept;

    public Integer getAge() {

       return age;

    }

    public void setAge(Integer age) {

       this.age = age;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Department getDept() {

       return dept;

    }

    public void setDept(Department dept) {

       this.dept = dept;

    }

    @Override

    public String toString() {

       return "Employee [age=" + age + ", name=" + name + ", dept=" + dept + "]";

    }

}

public class Department {

    private Integer id;

    private String name;

    public Integer getId() {

       return id;

    }

    public void setId(Integer id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

}

 

<?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="employee" class="cn.zj.spring.pojo.Employee" >

         <!-- setter方法注入: 屬性注入

             <property name="" value="">

             name : 屬性名稱

             value : 基本數據類型+String類型的值注入

             ref : 引用類型(對象類型)的注入

             value 和ref 只能二選一

         -->

         <property name="age" value="18"></property>

         <property name="name" value="jinken"></property>

         <property name="dept" ref="dept"></property>

    </bean>

    <!-- 部門 -->

    <bean id="dept" class="cn.zj.spring.pojo.Department" ></bean>

 

</beans>

6.2.  構造器注入

<!--

         1,默認情況下,constructor-arg的順序就是構造器參數的順序

         2,3中調整構造器順序:

            1.index:在構造器中的參數索引(從0開始)

            2.type:在構造器中的參數的類型

            3.name:在構造器中按照構造器的參數名字設置值

            ====================

         使用哪種注入方式比較好(setter?構造器?)?

         1,如果一個類必須依賴另一個類才能正常運行,用構造器;

         2,但是構造器的參數如果過多,構造器很難看;

         3,更多的還是使用setter注入;

         4,可以使用@Required標簽來要求一個屬性必須注入

     -->

   

    <!-- 員工 -->

    <bean id="employee" class="cn.zj.spring.pojo.Employee" >

         <!-- constructor注入 -->

         <constructor-arg index="1"  value="喬峰"/>

         <constructor-arg index="0" value="19"/>

         <constructor-arg  ref="dept"/>

    </bean>

    <!-- 部門 -->

    <bean id="dept" class="cn.zj.spring.pojo.Department" ></bean>

 

6.3.  p命名空間注入

使用p命名空間注入先在約束上面引入 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">

<!-- 員工 -->

    <bean id="employee" class="cn.zj.spring.pojo.Employee"

       p:age="30"

       p:name="段譽"

       p:dept-ref="dept">

    </bean>

    <!-- 部門 -->

    <bean id="dept" class="cn.zj.spring.pojo.Department" ></bean>

 

6.4.  集合類型值注入

在處理的數據中,

有標量類型=基礎數據類型以及包裝類+String  -- value屬性

也有Spring容器里面的對象  --ref屬性

還要很多數據JDK內置的數據結構:

  1. 鍵值對 Map 、Properties
  2. 數組
  3. 集合Set、List

 

public class CollectionBean {

    private Set<String> set;

    private List<String> list;

    private String[] array;

    private Map<String, String> map;

    private Properties prop; //讀取本地 xxx.properties文件(本質就是一個Map集合)

}

<bean id="collectionBean" class="cn.gzxst.spring.pojo.CollectionBean">

         <!-- set集合注入  -->

         <property name="set">

             <set>

                  <value>set1</value> 

                  <value>set2</value> 

                  <value>set3</value> 

             </set>

         </property>

         <!-- list集合注入  -->

         <property name="list">

             <list>

                  <value>list1</value>

                  <value>list2</value>

                 <value>list3</value>

             </list>

         </property>

         <!-- 數組注入 -->

         <property name="array">

             <array>

                  <value>AA</value>

                  <value>BB</value>

                  <value>CC</value>

             </array>

         </property>

         <!-- map集合注入 -->

         <property name="map">

             <map>

                  <entry key="key1" value="喬峰"/>

                  <entry key="key2" value="虛竹"/>

                  <entry key="key3" value="段譽"/>

             </map>

         </property>

         <!-- Properties注入 -->

         <property name="prop">

             <props>

                  <prop key="pro1">proVlaue1</prop>

                  <prop key="pro2">proVlaue2</prop>

                  <prop key="pro3">proVlaue3</prop>

             </props>

         </property>

    </bean>

7.     獲得properties文件的值

Spring配置文件支持通過xxx.properties文件的Key獲得對應的值。實現該功能是通過

通過${Key}來獲得Properties文件對應Key的值

 

使用Spring讀取配置文件必須導入新的命名空間 context

導入命名空間方法

將命名空間和約束重新拷貝一份,將對於的全部替換成 context,然后關聯context本地schema約束

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:p="http://www.springframework.org/schema/p"

    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/context

    http://www.springframework.org/schema/context/spring-context.xsd

    ">

 

7.1.  使用Spring創建阿里巴巴 Druid連接池,讀取配置文件

7.1.1.  拷貝Mysql驅動包和druid連接池jar包到項目中

 

 

7.1.2.  創建 db.properites

jdbc.driverClassName=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/jdbcdemo

jdbc.username=root

jdbc.password=root

jdbc.maxActive=10

 

 

7.1.3.  applicationContext.xml配置

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:p="http://www.springframework.org/schema/p"

    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/context

    http://www.springframework.org/schema/context/spring-context.xsd

    ">

    <!-- 讀取項目的配置文件 -->

    <context:property-placeholder location="classpath:db.properties" />

    <!-- 創建連接池對象 -->

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">

         <property name="driverClassName"

             value="${jdbc.driverClassName}" />

         <property name="url" value="${jdbc.url}" />

         <property name="username" value="${jdbc.username}" />

         <property name="password" value="${jdbc.password}" />

         <property name="maxActive" value="${jdbc.maxActive}" />

    </bean>

</beans>

7.1.4.  測試代碼

@Test

    public void testSave() throws Exception {

         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        

         DataSource dataSource = context.getBean(DataSource.class, "dataSource");

         Connection conn = dataSource.getConnection();

         System.out.println("數據庫連接對象:"+conn);

    }

7.1.5.  效果

 

8.     模擬注冊功能

此功能重點在於將每一層對象的創建交給Spring管理,對象之間的依賴關系交給Spring來維護

8.1.  Dao層接口以及實現代碼

public interface UserDao {

    void insert(User user);

}

public class UserDaoImpl implements UserDao {

    @Override

    public void insert(User user) {

         System.out.println("注冊的Dao方法執行");

    }

}

8.2.  Service層接口以及實現代碼

public interface UserService {

    void register(User user);

}

public class UserServiceImpl implements UserService {

    /*private UserDao dao = new UserDaoImpl(); 傳統做法

     * 現在交給Spring管理,使用Spring的setter方法注入

     *因為要交給Spring的setter方法注入,所以(必須)提供set方法

    */

    private UserDao dao;

   

    @Override

    public void register(User user) {

         dao.insert(user);

    }

    //因為要用

    public void setDao(UserDao dao) {

         this.dao = dao;

    }

}

8.3.  Web表現層實現代碼

public class UserServlet {

    /* 傳統做法

     * private UserService service = new UserServiceImpl();

     *  現在交給Spring管理,使用Spring的setter方法注入

     *  因為要交給Spring的setter方法注入,所以(必須)提供set方法

     */

    private UserService service;

   

    public void register(User user) {

        

         service.register(user);

    }

    public void setService(UserService service) {

         this.service = service;

    }

}

8.4.  applicationContext.xml文件配置代碼(重點),一定要掌握每層的配置,和每層之間對象的依賴關系的維護

!-- 配置 項目的bean -->

   

    <!-- 配置DAO層 -->

    <bean id="userDao" class="cn.zj.spring.dao.impl.UserDaoImpl"/>   

   

    <!-- 配置Service層 -->

    <bean id="userService" class="cn.zj.spring.service.impl.UserServiceImpl">

         <!-- DI: 依賴注入,使用 setter注入 dao層對象-->

         <property name="dao" ref="userDao"/>

    </bean>

    <!-- 配置web層/表現層  -->

    <bean id="userServlet" class="cn.zj.spring.controller.UserServlet">

         <!-- DI : 依賴注入,使用setter注入 service層對象 -->

         <property name="service" ref="userService"/>

    </bean>

8.5.  測試代碼

@Test

    public void testRegister() throws Exception {

         //創建用戶對象:模擬接受用戶參數,封裝對象的過程

         User user = new User();

         user.setUsername("張三");

         user.setPassword("admin");

         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

         //獲取表現層的Servlet即可

         UserServlet userServlet = context .getBean("userServlet", UserServlet.class);

         //執行注冊操作

         userServlet.register(user);

    }

 

 

 

9.     小結

優秀架構的點

高內聚(各司其職,分層開發)

低耦合 :降低代碼與代碼之間的直接new對象的操作

性能

Spring 是什么?

  輕量級,一站式框架

 核心功能

IOC :將對象創建權交給Spring(維護生命周期,作用范圍)

DI :依賴注入,將對象與對象之間依賴關系交給Spring維護

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM