案例學編程系列:案例認識 Spring IOC

本文spring libs 地址:https://github.com/yizhiamumu/springlibsjava

Spring 能幫咱們作什麼

  • ①.Spring 能幫咱們根據配置文件建立及組裝對象之間的依賴關係。
  • ②.Spring 面向切面編程能幫助咱們無耦合的實現日誌記錄,性能統計,安全控制。
  • ③.Spring 能很是簡單的幫咱們管理數據庫事務。
  • ④.Spring 還提供了與第三方數據訪問框架(如Hibernate、JPA)無縫集成,並且本身也提供了一套JDBC訪問模板來方便數據庫訪問。
  • ⑤.Spring 還提供與第三方Web(如Struts1/二、JSF)框架無縫集成,並且本身也提供了一套Spring MVC框架,來方便web層搭建。
  • ⑥.Spring 能方便的與Java EE(如Java Mail、任務調度)整合,與更多技術整合(好比緩存框架)。

Spring 的優點

  • 低侵入 / 低耦合 (下降組件之間的耦合度,實現軟件各層之間的解耦)
  • 聲明式事務管理(基於切面和慣例)
  • 方便集成其餘框架(如MyBatis、Hibernate)
  • 下降 Java 開發難度
  • Spring 框架中包括了 J2EE 三層的每一層的解決方案(一站式)

Spring IoC 是什麼

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

讀做「反轉控制」更好理解。將本來在程序中手動建立對象的控制權,交由Spring框架來管理。python

  • 正控:若要使用某個對象,須要本身去負責對象的建立
  • 反控:若要使用某個對象,只須要從 Spring 容器中獲取須要使用的對象,不關心對象的建立過程,也就是把建立對象的控制權反轉給了Spring框架

在Java開發中,Ioc意味着將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。git

●誰控制誰?

咱們直接在對象內部經過new進行建立對象,是程序主動去建立依賴對象;而IoC是有專門一個容器來建立這些對象,即由Ioc容器來控制對象的建立;github

●控制什麼?

主要控制了外部資源獲取。web

●爲什麼是反轉?

有反轉就有正轉,傳統應用程序是由咱們本身在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙建立及注入依賴對象;spring

爲什麼是反轉?由於由容器幫咱們查找及注入依賴對象,對象只是被動的接受依賴對象,因此是反轉;數據庫

●反轉了什麼?

依賴對象的獲取被反轉了。編程

案例1:認識springIOC

正控

1.建立員工類緩存

Employee.java安全

public class Employee {

    /** 系統id */
    private int id;

    /** 員工編號 */
    private String employeeNo;

    /** 員工姓名 */
    private String employeeName;

    /** 員工性別 */
    private String sex;

    /** 出生日期 */
    private Date birthDay;

    /** 部門編號 */
    private String officeNo;

    /** 崗位編號 */
    private String postNo;

    /** 入職時間 */
    private Date entryTime;

    /** 特長 */
    private String speciality;

    /** 興趣愛好 */
    private String hobby;

    /** setter and getter */
}

 

2.建立測試方法,並調用構造函數建立對象。

TestSpringEmp.java

public class TestSpringEmp {

    public static void main(String[] args) {
        Employee emp = new Employee();

        System.out.println(emp);
    }
}

 

springIOC 控制反轉

環境搭建:

1.idea 工程添加Spring相關jar包。【libs 上傳至git 地址,操做方法見附錄】

2.建立配置文件,能夠自定義文件名spring.xml。

3.調用API。

程序思路:

1.在spring.xml中配置bean標籤,IOC容器經過加載bean標籤來建立對象。

2.調用API獲取IOC建立的對象。

兩種方式

2.1 經過id獲取對象

//1.加載spring.xml配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.經過id值獲取對象
        Employee emp = (Employee) applicationContext.getBean("emp");
        System.out.println(emp);

 

2.2 經過運行時類獲取對象

注意: 當spring.xml中配置兩個Employee的bean時程序報錯,由於此時兩個bean都是由Employee類生成的,IOC容器沒法將兩個bean都返回。

必須指定一個惟一的bean

spring.xml

 <bean id="emp1" class="com.spring.model.Employee">
        <property name="id" value="1"></property>
 </bean>
 
  <bean id="emp2" class="com.spring.model.Employee">
        <property name="id" value="2"></property>
 </bean>

 

TestSpringEmp.java

      //1.加載spring.xml配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.經過運行時類獲取對象
        Employee emp = applicationContext.getBean(Employee.class);
        System.out.println(emp);

 

無參構造代碼

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

        <!-- 配置員工 Employee 對象-->
        <bean id="emp" class="com.spring.model.Employee"></bean>

</beans>

 

TestSpringEmp.java

import com.spring.model.Employee;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpringEmp {

    public static void main(String[] args) {

        //1.加載spring.xml配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.經過id值獲取對象
        Employee emp = (Employee) applicationContext.getBean("emp");
        System.out.println(emp);
    }
}

 

第一步:加載spring.xml配置文件,生成ApplicationContext對象。

第二步:調用ApplicationContext的getBean方法獲取對象,參數爲配置文件中的id值。

程序在加載spring.xml時建立stu對象,經過反射機制調用無參構造函數,全部要求交給IOC容器管理的類必須有無參構造函數。

如何賦值呢?

調用無參構造只會建立對象而不會進行賦值,如何賦值呢?只須要在spring.xml中進行相關配置便可。

添加property標籤:name對應屬性名,value是屬性的值。

注:若包含特殊字符,好比name="<一隻阿木木>",使用<![CDATA[<一隻阿木木>]]>進行配置。

spring.xml

     <property name="id" value="1"></property>
        <property name="employeeNo" value="10001"></property>
        <property name="employeeName" value="一隻阿木木"></property>
        <property name="sex" value="1"></property>
        <property name="birthDay" value="1990-08-15"></property>
        <property name="officeNo" value="7"></property>
        <property name="postNo" value="1"></property>
        <property name="entryTime" value="2018-07-01"></property>
        <property name="speciality" value="java,python"></property>
        <property name="hobby">
            <value><![CDATA[<漫畫>]]></value>
        </property>

 

有參構造代碼

在實體類中建立有參構造

Employee.java

public Employee(int id, String employeeNo, String employeeName) {
        super();
        this.id = id;
        this.employeeNo = employeeNo;
        this.employeeName = employeeName;
    }

 

spring.xml

    <!-- 經過有參構造函數建立對象 -->
    <bean id="emp3" class="com.spring.model.Employee">
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="employeeNo" value="10001"></constructor-arg>
        <constructor-arg name="employeeName" value="一隻阿木木"></constructor-arg>
    </bean>

 

除了使用name對應參數外,還能夠經過下標index對應。

<!-- 經過有參構造函數建立對象 -->
    <bean id="emp3" class="com.spring.model.Employee">
        <constructor-arg index="0" value="3"></constructor-arg>
        <constructor-arg index="1" value="10001"></constructor-arg>
        <constructor-arg index="2" value="一隻阿木木"></constructor-arg>
    </bean>

 

進階1:多個對象級聯關係?

建立工做經歷類 job.java

public class Job {
    /** 序號 */
    private int id;
    
    /** 單位名稱 */
    private String companyName;

    /** 職位名稱 */
    private String position;

    /** 工做薪水 */
    private BigDecimal salary;
    
    /** setter and getter */
    
}

 

在員工Employee 類中添加工做經歷job 類:

Employee.java

    /** 工做經歷類*/
    private Job job;
   
    /** 系統id */
    private int id;

    /** 員工編號 */
    private String employeeNo;

    /** 員工姓名 */
    private String employeeName;

 

spring.xml中配置Job 對象,而後將該對象賦值給emp 對象。

spring.xml

    <!-- 建立job 對象 -->
    <bean id="job" class="com.spring.model.Job">
        <property name="id" value="1"></property>
        <property name="companyName" value="阿木木國際集團"></property>
        <property name="position" value="研發副總監"></property>
        <property name="salary" value="10000.00"></property>
    </bean>

    <!-- 建立emp對象 -->
    <bean id="emp" class="com.spring.model.Employee">
        <property name="id" value="1"></property>
        <property name="employeeNo" value="10001"></property>
        <property name="employeeName">
            <value><![CDATA[<一隻阿木木>]]></value>
        </property>
        <!-- 將job 對象賦給emp 對象-->
        <property name="job" ref="job"></property>
    </bean>
    </bean>

 

在spring.xml中,經過ref屬性將其餘bean賦給當前bean對象,這種方式叫作依賴注入(DI),是Spring很是重要的機制,DI是將不一樣對象進行關聯的一種方式,是IOC的具體實現方式,一般DI和IOC是緊密結合在一塊兒的,因此通常說的IOC包括DI。

若是是集合屬性如何依賴注入?

Job 類中添加List<Employee>屬性。

Job.java

    /** List<Employee>屬性*/
    private List<Employee> employeeList;

 

spring.xml中配置2個emp對象,1個job對象,並將2個emp對象注入到job對象中。

spring.xml

<bean id="job" class="com.spring.model.Job">
        <property name="id" value="1"></property>
        <property name="companyName" value="阿木木國際集團"></property>
        <property name="position" value="研發副總監"></property>
        <property name="salary" value="10000.00"></property>

        <property name="emp">
            <!-- 注入emp對象 -->
            <list>
                <ref bean="emp"/>
                <ref bean="emp2"/>
            </list>
        </property>
    </bean>

    <bean id="emp" class="com.spring.model.Employee">
        <property name="id" value="1"></property>
        <property name="employeeNo" value="10001"></property>
        <property name="employeeName">
            <value><![CDATA[<一隻阿木木>]]></value>
        </property>
    </bean>
    <bean id="emp2" class="com.spring.model.Employee">
        <property name="id" value="2"></property>
        <property name="employeeNo" value="10002"></property>
        <property name="employeeName">
            <value><![CDATA[<兩隻阿木木>]]></value>
        </property>
    </bean>

 

集合屬性經過list標籤和ref標籤完成注入。ref的bean屬性指向須要注入的bean對象。

IoC和DI

2004年大師級人物Martin Fowler:「依賴注入」明確描述了「被注入對象依賴IoC容器配置依賴對象」。

DI—Dependency Injection,即「依賴注入」:咱們只須要經過簡單的配置,而無需任何代碼就可指定目標須要的資源,完成自身的業務邏輯,而不須要關心具體的資源來自何處,由誰實現。

理解DI的關鍵是:「誰依賴誰,爲何須要依賴,誰注入誰,注入了什麼」。

  • 誰依賴於誰:固然是應用程序依賴於IoC容器;
  • 爲何須要依賴:應用程序須要IoC容器來提供對象須要的外部資源;
  • 誰注入誰:很明顯是IoC容器注入應用程序某個對象,應用程序依賴的對象;
  • 注入了什麼:就是注入某個對象所須要的外部資源(包括對象、資源、常量數據)。

IoC和DI 是什麼關係呢?

其實它們是同一個概念的不一樣角度描述。

IoC 是spring的核心,全部的類的建立、銷燬都由 spring來控制,也就是說控制對象生存週期的再也不是引用它的對象,而是spring。由spring來負責控制對象的生命週期和對象間的關係,這叫控制反轉。

Java 1.3以後一個重要特徵是反射(reflection),它容許程序在運行的時候動態的生成對象、執行對象的方法、改變對象的屬性,spring就是經過反射來實現注入的。IoC的一個重點是在系統運行中,動態的向某個對象提供它所須要的其餘對象。這一點是經過DI(Dependency Injection,依賴注入)來實現的。

控制的什麼被反轉了?就是:得到依賴對象的方式反轉了。

案例2:工廠方法

IOC是典型的工廠模式,IOC經過工廠模式建立bean有兩種方式:

  • 1.靜態工廠方法
  • 2.實例工廠方法

一.靜態工廠方法

1.1 建立工做實體類

job.java

public class Job {

    /** 序號 */
    private int id;

    /** 單位名稱 */
    private String companyName;

    /** 職位名稱 */
    private String position;

    public Job(int id, String companyName, String position) {
        super ();
        this.id = id;
        this.companyName = companyName;
        this.position = position;
    }

    public Job() {
        super();
    }

    @Override
    public String toString() {
        return "Job [id=" + id + ", companyName=" + companyName + ", postion=" + position + " ]";
    }
    
}

 

1.2 建立靜態工廠類,靜態工廠方法。

StaticFactoryJob.java

    private static Map<Integer, Job> jobs;

    static {
        jobs = new HashMap<>();
        jobs.put(1, new Job(1, "貓廠", "p7"));
        jobs.put(2, new Job(2, "鵝廠","T2"));
    }

    public static  Job getJob(int id) {
        return  jobs.get(id);
    }

 

1.3 在spring.xml中配置靜態工廠。

spring.xml

    <!-- 配置靜態工廠建立job對象 -->
    <bean id="job1" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
        <constructor-arg value="1"></constructor-arg>
    </bean>

 

factory-method指向靜態方法。

constructor-arg 的value屬性爲調用靜態方法所傳的參數。

1.4 在測試類中直接獲取job1對象。 TestSpringStatic.java

    public static void main(String[] args) throws SQLException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Job job = (Job) applicationContext.getBean("job1");
        System.out.println(job);
    }

// 打印:Job [id=1, companyName=貓廠, postion=p7 ]

 

二.實例工廠方法

2.1 建立實例工廠類,工廠方法 。

InstanceFactoryJob.java

    private Map<Integer, Job> jobs;

    public  InstanceFactoryJob() {
        jobs = new HashMap<>();
        jobs.put(1, new Job(1, "貓廠", "p7"));
        jobs.put(2, new Job(2, "鵝廠", "T2"));
    }
    public  Job getJob(int id) {
        return jobs.get(id);
    }

 

2.2 spring.xml 中配置 bean

spring.xml

<!-- 配置實例工廠對象 -->
    <bean id="jobFactory" class="com.spring.model.InstanceFactoryJob"></bean>

    <!-- 經過實例工廠對象建立car對象 -->
    <bean id="job2" factory-bean="jobFactory" factory-method="getJob">
        <constructor-arg value="2"></constructor-arg>
    </bean>

 

2.3 在測試類中直接獲取car2對象

    public static void main(String[] args) throws SQLException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Job job = (Job) applicationContext.getBean("job2");
        System.out.println(job);
    }


// 打印: Job [id=2, companyName=鵝廠, postion=T2 ]

 

區別

靜態工廠方法的方式建立job對象,不須要實例化工廠對象,由於靜態工廠的靜態方法,不須要建立對象便可調用。因此spring.xml只須要配置一個Job bean,而不須要配置工廠bean。

實例工廠方法建立job對象,必須先實例化工廠對象,由於調用的是非靜態方法,必須經過對象調用,不能直接經過類來調用,因此spring.xml中須要先配置工廠bean,再配置Job bean。

案例3:IOC自動裝載(autowire)

自動裝載有兩種方式:

  • byName:經過屬性名自動裝載
  • byType:經過屬性對應的數據類型自動裝載

3.1 經過屬性名自動裝載

1 新建BaseEmployee.java 類

public class BaseEmployee {

    /** 系統id */
    private int id;

    /** 員工編號 */
    private String employeeNo;

    /** 員工姓名 */
    private String employeeName;

    /** 工做經歷*/
    private Job job;

    /** setter and getter */
     
    @Override
    public String toString() {
        return "BaseEmployee [id=" + id + ", employeeNo=" + employeeNo + ", employeeName=" + employeeName + ", job=" + job + "]";
    }
    
}

 

2 spring.xml中配置Car bean和Person bean,並經過自動裝載進行依賴注入。

spring.xml

<!--autowire="byName"表示經過匹配屬性名的方式去裝載對應的bean,
    BaseEmployee實體類中有 job 屬性,因此就將id="job"的bean注入到baseEmployee中-->

    <bean id="emp" class="com.spring.model.BaseEmployee" autowire="byName">
        <property name="id" value="1"></property>
        <property name="employeeNo" value="10001"></property>
        <property name="employeeName" value="一隻阿木木"></property>
    </bean>

    <bean id="job" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
        <constructor-arg value="2"></constructor-arg>
    </bean>

 

注意:經過property標籤手動進行car的注入優先級更高,若兩種方式同時配置,以property的配置爲準。

3 測試類中獲取baseEmployee 對象。

TestSpringBaseEmployee.java

public class TestSpringBaseEmployee {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        BaseEmployee emp = (BaseEmployee) applicationContext.getBean("emp");
        System.out.println(emp);
    }
}

 

3.2 經過屬性對應的數據類型自動裝載

知識點:使用byType進行自動裝載時,spring.xml中只能配置一個裝載的bean。

1.spring.xml

    <bean id="emp" class="com.spring.model.BaseEmployee" autowire="byType">
        <property name="id" value="1"></property>
        <property name="employeeNo" value="10001"></property>
        <property name="employeeName" value="一隻阿木木"></property>
    </bean>

    <bean id="job" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
        <constructor-arg value="2"></constructor-arg>
    </bean>

    <!--<bean id="job2" class="com.spring.model.StaticFactoryJob" factory-method="getJob">
        <constructor-arg value="2"></constructor-arg>
    </bean>-->

 

2.測試類中獲取person對象

TestSpringBaseEmployee.java

// 打印:BaseEmployee [id=1, employeeNo=10001, employeeName=一隻阿木木, job=Job [id=2, companyName=鵝廠, postion=T2 ]]

 

案例4:程序架構MVC 分層

經典三層架構:Controller層,Service層,DAO層。

有兩種方式:

  • 基於xml配置文件
  • 基於註解

4.1 基於 xml 配置

model 層實體類:

BaseEmployee.java

public class BaseEmployee {

    /** 系統id */
    private int id;

    /** 員工編號 */
    private String employeeNo;

    /** 員工姓名 */
    private String employeeName;

    public BaseEmployee(int id, String employeeNo, String employeeName) {
        super();
        this.id = id;
        this.employeeNo = employeeNo;
        this.employeeName = employeeName;
    }
    public BaseEmployee() {
        super();
    }
    
    @Override
    public String toString() {
        return "BaseEmployee [id=" + id + ", employeeNo=" + employeeNo + ", employeeName=" + employeeName + "]";
    }
    
    /** setter and getter */
    
}

 

Dao 層接口

BaseEmployeeDao.java

    public interface BaseEmployeeDao {
        public BaseEmployee getBaseEmpById(int id);
    }

 

BaseEmployeeDaoImpl.java

public class BaseEmployeeDaoImpl implements BaseEmployeeDao{

    private static Map<Integer,BaseEmployee> baseEmployee;

    static{
            baseEmployee = new HashMap<Integer,BaseEmployee>();
            baseEmployee.put(1, new BaseEmployee(1, "10001", "一隻阿木木"));
            baseEmployee.put(2, new BaseEmployee(2, "10002", "兩隻阿木木"));
            baseEmployee.put(3, new BaseEmployee(3, "10003", "三隻阿木木"));
    }

    @Override
    public BaseEmployee getBaseEmpById(int id) {
        // TODO Auto-generated method stub
        return baseEmployee.get(id);
    }
}

 

Service 層

建立BaseEmployeeService 接口以及實現類BaseEmployeeServiceImpl。

BaseEmployeeService

public interface BaseEmployeeService {
    public BaseEmployee getBaseEmpById(int id);
}

 

BaseEmployeeServiceImpl.java

public class BaseEmployeeServiceImpl implements BaseEmployeeService {

    private BaseEmployeeDAO baseEmployeeDAO;

    public BaseEmployeeDAO getBaseEmployeeDAO() {
        return baseEmployeeDAO;
    }

    public void setBaseEmployeeDAO(BaseEmployeeDAO baseEmployeeDAO) {
        this.baseEmployeeDAO = baseEmployeeDAO;
    }

    @Override
    public User getBaseEmpById(int id) {
        // TODO Auto-generated method stub
        return baseEmployeeDAO.getBaseEmpById(id);
    }
}

 

Controller 層

BaseEmployeeController.java

public class BaseEmployeeController {

    private BaseEmployeeService baseEmployeeService;

    public BaseEmployeeService getBaseEmployeeService() {
        return baseEmployeeService;
    }

    public void setBaseEmployeeService(BaseEmployeeService baseEmployeeService) {
        this.baseEmployeeService = baseEmployeeService;
    }

    public BaseEmployee getBaseEmpById(int id){
        return baseEmployeeService.getBaseEmpById(id);
    }
}

 

spring.xml

在spring.xml配置Controller,Service,DAO,並完成依賴注入。 spring.xml

    <!-- 配置BaseEmployeeController -->
    <bean id="baseEmployeeController" class="com.spring.controller.BaseEmployeeController">
        <property name="baseEmployeeService" ref="baseEmployeeService"></property>
    </bean>

    <!-- 配置BaseEmployeeService -->
    <bean id="baseEmployee" class="com.spring.service.BaseEmployeeServiceImpl">
        <property name="baseEmployeeDAO" ref="baseEmployeeDAO"></property>
    </bean>

    <!-- 配置BaseEmployeeDAO -->
    <bean id="baseEmployeeDAO" class="com.spring.dao.BaseEmployeeDaoImpl"></bean>

 

測試

TestSpringBaseEmployee.java

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        BaseEmployeeController baseEmployeeController = (BaseEmployeeController) applicationContext.getBean("baseEmployeeController");
        BaseEmployee baseEmployee = baseEmployeeController.getBaseEmpById(1);
        System.out.println(baseEmployee);
    }

 

4.2基於註解的方式

4.2.1 默認byType 方式

第一步:將Controller,Service,DAO類掃描到IOC容器中。

第二步:在類中設置註解完成依賴注入。

1 修改 spring.xml

知識點:引入context 命名空間

<?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-4.0.xsd">


    <!-- 將類掃描到IOC容器中 -->
    <context:component-scan base-package="com.spring"></context:component-scan>
</beans>

 

2 修改DAOImpl

改動:在類名處添加@Repository註解,表示該類是數據接口層。

    @Repository
    public class BaseEmployeeDaoImpl implements BaseEmployeeDao{

        private static Map<Integer,BaseEmployee> baseEmployee;

        static{
            baseEmployee = new HashMap<Integer,BaseEmployee>();
            baseEmployee.put(1, new BaseEmployee(1, "10001", "一隻阿木木"));
            baseEmployee.put(2, new BaseEmployee(2, "10002", "兩隻阿木木"));
            baseEmployee.put(3, new BaseEmployee(3, "10003", "三隻阿木木"));
        }

        @Override
        public BaseEmployee getBaseEmpById(int id) {
            // TODO Auto-generated method stub
            return baseEmployee.get(id);
        }
    }

 

3 修改ServiceImpl。

  • 在類名處添加@Service註解,表示該類是業務層。
  • DAO屬性出添加@Autowired註解,表示IOC容器自動完成裝載,默認是byType的方式。
@Service
public class BaseEmployeeServiceImpl implements BaseEmployeeService{

    @Autowired
    private BaseEmployeeDAO baseEmployeeDAO;

    @Override
    public BaseEmployee getBaseEmpById(int id) {
        // TODO Auto-generated method stub
        return baseEmployeeDAO.getBaseEmpById(id);
    }
}

 

4 修改 Controller類,添加註解。

有兩處改動:

  • 在類名處添加@Controller註解,表示該類做爲一個控制器。
  • Service屬性出添加@Autowired註解,表示IOC容器自動完成裝載,默認是byType的方式。

BaseEmployeeControler.java

@Controller
public class BaseEmployeeController {

    @Autowired
    private BaseEmployeeService baseEmployeeService;

    public BaseEmployee getBaseEmpById(int id){
        return baseEmployeeService.getBaseEmpById(id);
    }

}

 

4.2.2 ByName

自動裝載除了byType的方式,還能夠結合@Qualifier註解, 使用byName的方式。

知識點:@Qualifier()中的值必須與@Service()中的值一致,才能完成自動裝載。

BaseEmployeeControler.java

@Controller
public class BaseEmployeeController {

    @Autowired
    @Qualifier("baseEmployeeService")
    private BaseEmployeeService baseEmployeeService;

    public BaseEmployee getBaseEmpById(int id){
        return baseEmployeeService.getBaseEmpById(id);
    }

}

 

基於註解的方式咱們並無給bean設置id,byName的方式是經過屬性名去匹配對應bean的id屬性值。

添加註解時,類名首字母小寫以後的值就是id的默認值。IOC容器中默認賦值,BaseEmployeeService bean的id=baseEmployeeService,與Controller中的屬性名一致

@Service
public class BaseEmployeeServiceImpl implements BaseEmployeeService

 

修改

BaseEmployeeService bean的id=sortBaseEmployeeService。

Service 層
@Service("sortBaseEmployeeService")
public class BaseEmployeeServiceImpl implements BaseEmployeeService{

    @Autowired
    private BaseEmployeeDAO baseEmployeeDAO;

    @Override
    public BaseEmployee getBaseEmpById(int id) {
        // TODO Auto-generated method stub
        return baseEmployeeDAO.getBaseEmpById(id);
    }
}

 

Controller 層

Controller中的Service屬性也須要去匹配name=sortBaseEmployeeService的bean,因此設置@Qualifier("sortBaseEmployeeService")。

@Controller
public class BaseEmployeeController {

    @Autowired
    @Qualifier("sortBaseEmployeeService")
    private BaseEmployeeService baseEmployeeService;

    public BaseEmployee getBaseEmpById(int id){
        return baseEmployeeService.getBaseEmpById(id);
    }

}

 

小結

IOC概念

spring IoC的思想:依賴注入就是A開放接口,將B傳遞進來(注入);控制反轉,AB雙方不相互依賴,整個活動的進行由第三方負責管理。

控制反轉,由容器建立組件對象,而後注入參數創建應用關係。

例如EmployeeDao調用Data,由Spring容器建立EmployeeDao和Data對象,而後再由容器將Data對象注入給EmployeeDao中的屬性。

Data注入途徑能夠是set方法,也能夠是帶參數構造器等。

編寫規則

EmployeeDao類在編寫時,須要定義一個set方法或帶參數構造器,參數類型爲Data。

public class EmployeeDao {
    private Data data;

    //1 set 方法注入
    private void setData(Data data) {
        this.data = data;
    }

    //2 帶參數構造器注入
    private EmployeeDao(Data data) {
        this.data = data;
    }

}

 

配置原理

    <!--原理,利用反射建立對象(無參構造器), 而後利用反射注入參數-->
    <bean id="" class="">
        <property name="" value|ref=""></property>
    </bean>
    
    <!--原理:利用反射直接調用帶參數構造器建立對象-->
    <bean id="" class="">
        <constructor-arg index=""  value|ref=""></constructor-arg>
    </bean>

 

裝配 Spring Bean 小結

集合注入總結:

List 屬性使用 <list> 元素定義注入,使用多個 <ref> 元素的 Bean 屬性去引用以前定義好的 Bean

<property name="list">
    <list>
        <ref bean="bean1"/>
        <ref bean="bean2"/>
    </list>
</property>

 

Map 屬性使用 <map> 元素定義注入,使用多個 <entry> 元素的 key-ref 屬性去引用以前定義好的 Bean 做爲鍵,而用 value-ref 屬性引用以前定義好的 Bean 做爲值

<property name="map">
    <map>
        <entry key-ref="keyBean" value-ref="valueBean"/>
    </map>
</property>

 

Set 屬性使用 <set> 元素定義注入,使用多個 <ref> 元素的 bean 去引用以前定義好的 Bean

<property name="set">
    <set>
        <ref bean="bean"/>
    </set>
</property>

 

命名空間裝配

須要引入其聲明

C命名空間

<!-- 引入 c-命名空間以前 -->
<bean name="emp1" class="spring.Employee">
    <constructor-arg name="id" value="1" />
    <constructor-arg name="name" value="姓名1"/>
</bean>

<!-- 引入 c-命名空間以後 -->
<bean name="emp2" class="spring.Employee"
      c:id="2" c:name="姓名2"/>

<!--參數的索引。XML中不容許數字做爲屬性的第一個字符,所以添加一個下劃線來做爲前綴。-->
<bean name="emp2" class="spring.Employee"
      c:_0="2" c:_1="姓名2"/>

 

p-命名空間

c-命名空間經過構造器注入的方式來配置 bean,p-命名空間則是用setter的注入方式來配置 bean

<!-- 引入p-命名空間以前 -->
<bean name="emp1" class="spring.Employee">
    <property name="id" value="1" />
    <property name="name" value="姓名1"/>
</bean>

<!-- 引入p-命名空間以後 -->
<bean name="emp2" class="spring.Employee" 
      p:id="2" p:name="姓名2"/>


<!--屬性須要注入其餘 Bean 的話也能夠在後面跟上 -ref-->
<bean name="emp2" class="spring.Employee"
          p:id="2" p:name="姓名2" p:cdCard-ref="cdCard1"/>

 

util-命名空間

工具類的命名空間,能夠簡化集合類元素的配置

<!-- 引入util-命名空間以前 -->
<property name="list">
    <list>
        <ref bean="bean1"/>
        <ref bean="bean2"/>
    </list>
</property>

<!-- 引入util-命名空間以後 -->
<util:list id="list">
    <ref bean="bean1"/>
    <ref bean="bean2"/>
</util:list>

 

引入配置文件

【src】文件下新建一個 bean.xml

在 applicationContext.xml 文件中寫入:

<import resource="bean.xml" />

 

自動裝配 autowired

  • 理解: @Autowired 註解表示在 Spring IoC 定位全部的 Bean 後,再根據類型尋找資源,而後將其注入。
  • 過程: 定義 Bean ——> 初始化 Bean(掃描) ——> 根據屬性須要從 Spring IoC 容器中搜尋知足要求的 Bean ——> 知足要求則注入
  • 問題: IoC 容器可能會尋找失敗,此時會拋出異常(默認狀況下的Spring IoC 容器會認爲必定要找到對應的 Bean 來注入到這個字段,但有些時候並非必定須要,好比日誌)
  • 解決: 經過配置項 required 來改變,好比 @Autowired(required = false)

一切須要 Spring IoC 去尋找 Bean 資源的地方均可以用到

自動裝配的歧義性(@Primary和@Qualifier)

@Primary 註解:

  • 首要的。當 Spring IoC 檢測到有多個相同類型的 Bean 資源的時候,會優先注入使用該註解的類。
  • 問題:只是解決了首要的問題,可是並無選擇性的問題

@Qualifier 註解:

  • 產生歧義性的一個重要的緣由是 Spring 在尋找依賴注入的時候是按照類型注入引發的。除了按類型查找 Bean,Spring IoC 容器最底層的接口 BeanFactory 還提供了按名字查找的方法,若是按照名字來查找和注入不就能消除歧義性了嗎?
  • 使用方法: 指定注入名稱爲 "source1" 的 Bean 資源
/* 包名和import */
public class SpringZhujie {
    ......
    @Autowired
    @Qualifier("source1")
    public void setSource(Source source) {
        this.source = source;
    }
}

 

使用@Bean 裝配 Bean

問題:

經過 @Component 註解來裝配 Bean ,而且只能註解在類上,當你須要引用第三方包的(jar 文件),並且每每並無這些包的源碼,這時候將沒法爲這些包的類加入 @Component 註解,讓它們變成開發環境中的 Bean 資源。

解決方案:
  • 1.本身建立一個新的類來擴展包裏的類,而後再新類上使用 @Component 註解,但這樣很 low
  • 2.使用 @Bean 註解,註解到方法之上,使其成爲 Spring 中返回對象爲 Spring 的 Bean 資源。

@Configuration 註解至關於 XML 文件的根元素,解析其中的 @Bean 註解

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TestBean {

    @Bean(name = "testBean")
    public String test() {
        String str = "測試@Bean註解";
        return str;
    }
}

 

使用方法

  1. 引入spring 開發包
  2. 配置文件.xml
  3. 編寫組件,定義到xml 配置中
  4. 建立窗口對象,調用 getBean 獲取Bean 對象使用
 
 

因爲Java語言自己的類反射功能,使得僅憑一個配置文件,就能魔法般地實例化並裝配好程序所用的Bean。容器啓動時,Spring根據配置文件的描述信息,自動實例化Bean並完成依賴關係的裝配,從容器中便可返回準備就緒的Bean實例,後續可直接使用之。

 

 

本文spring libs 地址:https://github.com/yizhiamumu/springlibs


公衆號:一隻阿木木

博客園:http://www.cnblogs.com/yizhiamumu/

github : https://github.com/yizhiamumu/

相關文章
相關標籤/搜索