【Spring】XML方式實現(無參構造 有參構造)和注解方式實現 IoC



簡單記錄 Spring5企業級開發實戰 周冠亞,黃文毅著- 和 Spring5最新完整教程IDEA版-秦疆

Spring IoC的實現方式

IoC是Spring框架的核心內容,使用多種方式完美的實現了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置實現IoC。

Spring容器在初始化時先讀取配置文件,根據配置文件或元數據創建與組織對象存入容器中,程序使用時再從Ioc容器中取出需要的對象(容器中獲取Bean)。

container magic

采用XML方式配置Bean的時候,Bean的定義信息是和實現分離的,而采用注解的方式可以把兩者合為一體,Bean的定義信息直接以注解的形式定義在實現類中,從而達到了零配置的目的。

控制反轉是一種通過描述(XML或注解)並通過第三方去生產或獲取特定對象的方式。在Spring中實現控制反轉的是IoC容器,其實現方法是依賴注入(Dependency Injection,DI)。

一個程序、對象創建方式、配置說明

導入Jar包

注 : spring 需要導入commons-logging進行日志記錄 . 我們利用maven , 他會自動下載對應的依賴項 .

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.22.RELEASE</version>
</dependency>

https://repo.spring.io/release/org/springframework/spring/

創建一個空白maven項目實現IoC。

XML方式實現

XML方式實現用構造器方式實現IoC分為無參構造器和有參構造器兩種。

通過無參構造方法來創建

User使用無參構造器的方式,實現無參構造器的IoC。

1、編寫一個User實體類

User類的實現如下:

User.java

package com.test.ioc.xml;

/** * 無參構造器實現IoC */
public class User  {
    /** * 姓名 */
    private String name;
    /** * 無參構造器 */
    public User () {
        System.out.println("user無參構造方法");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
    /** * 顯示姓名 */
    public void showName(){
        System.out.println("我叫 " + name +",哈哈!");
    }
    /** * 說話的方法 */
   
    public void say() {
        System.out.println("大家好!");
    }
}


2、編寫我們的spring文件

編寫我們的spring文件 , 這里我們命名為spring-chapter2.xml

在resources下spring-chapter2.xml文件中,通過bean標簽將User類交給IoC容器管理,代碼如下:

<?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就是java對象 , 由Spring創建和管理-->
    <!-- User無參構造器 -->
    <bean id="user" class="com.test.ioc.xml.User">
        <property name="name" value="柳小子"/>
    </bean>

</beans>

3、測試類 UserTest.java

我們可以去進行測試了,哈哈

UserTest.java

package ioc.xml;

import com.test.ioc.xml.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @author Liu Awen Email:willowawen@gmail.com * @create 2020-01-14 9:47 AM */
public class UserTest {
    @Test
    public void test(){
         //解析beans.xml文件 , 生成管理相應的Bean對象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-chapter2.xml");
         //getBean : 參數即為spring配置文件中bean的id .
        User user = (User) context.getBean("user");
        user.say();
        user.showName();
    }
}

4、測試結果

D:\Environments\jdk-11.0.2\bin\java.exe...

user無參構造方法
大家好!
我叫 柳小子,哈哈!



Process finished with exit code 0

結果可以發現,在調用showName方法之前,User對象已經通過無參構造初始化了!

User使用無參構造器的方式,實現無參構造器的IoC。

OK , 到了現在 , 我們徹底不用再去程序中去改動了 , 要實現不同的操作 , 只需要在xml配置文件中進行修改 , 所謂的IoC,一句話搞定 : 對象由Spring 來創建 , 管理 , 裝配 !

思考

  • user 對象是誰創建的 ?

    【 user 對象是由Spring創建的 】

  • user 對象的屬性是怎么設置的 ?

    【user 對象的屬性是由Spring容器設置的 】

這個過程就叫控制反轉(IoC) :

  • 控制 : 誰來控制對象的創建 , 傳統應用程序的對象是由程序本身控制創建的 , 使用Spring后 , 對象是由Spring來創建的
  • 反轉 : 程序本身不創建對象 , 而變成被動的接收對象 .

依賴注入 : 就是利用set方法來進行注入的.

IOC是一種編程思想,由主動的編程變成被動的接收

可以通過newClassPathXmlApplicationContext去瀏覽一下底層源碼 .

通過有參構造方法來創建

與User類不同的是,Order類是沒有無參構造器的,Order類含有一個帶有兩個參數——訂單號和訂單金額的有參構造器。

1、Order.java

Order類的定義如下:

package com.test.ioc.xml;

/** * 有參構造器實現IoC */
public class Order implements Deliverable {
    /** * 訂單號 */
    private long orderId;
    /** * 訂單金額 */
    private double amount;

    /** * 有參構造器 * @param orderId * @param amount */
    public Order (long orderId, double amount) {
        this.orderId = orderId;
        this.amount = amount;
    }

    public long getOrderId() {
        return orderId;
    }

    public void setOrderId(long orderId) {
        this.orderId = orderId;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return "Order{" +
                "orderId=" + orderId +
                ", amount=" + amount +
                '}';
    }

    /** * 訂單發貨方法 */
    @Override
    public void delivery() {
        System.out.printf("訂單號%s,金額%s,已發貨!", orderId, amount);
    }
}

interface 接口 Deliverable

package com.test.ioc.xml;

public interface Deliverable {
    /** * 發貨 */
    void delivery();
}

2、spring-chapter2.xml

在spring-chapter2.xml文件中通過bean標簽將User類交給IoC容器管理。具體配置如下:

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

   <!--Order有參構造器-->
    <bean id="order" class="com.test.ioc.xml.Order">
        <constructor-arg index="0" value="202001141004"/>
        <constructor-arg index="1" value="8888"/>
    </bean>

</beans>

*.xml 有三種方式編寫

<!-- 第一種根據index參數下標設置 -->
<bean id="order" class="com.test.ioc.xml.Order">
    <!-- index指構造方法 , 下標從0開始 -->
    <constructor-arg index="0" value="202001141004"/>
     <constructor-arg index="1" value="8888"/>
</bean>
<!-- 第二種根據參數名字設置 -->
<bean id="order" class="com.test.ioc.xml.Order">
    <!-- name指參數名 -->
    <constructor-arg name="orderId" value="202001141004"/>
    <constructor-arg name="amount" value="8888"/>
</bean>
<!-- 第三種根據參數類型設置 -->
<bean id="order" class="com.test.ioc.xml.Order>
    <constructor-arg type="java.lang.Long" value="202001141004"/>
  <constructor-arg type="java.lang.Double" value="8888"/>                                             </bean>

3、測試類 OrderTest.java

在單元測試類OrderTest中,通過依賴注入得到Deliverable的對象Order,單元測試代碼如下:

package ioc.xml;

import com.test.ioc.xml.Deliverable;
import com.test.ioc.xml.Speakable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/** * 測試XML方式的IoC */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-chapter2.xml")
public class XmlTest {
    //Spring 容器注入依賴的Speakable對象
    @Autowired
    private Speakable speakable;
    //Spring 容器注入依賴的Deliverable對象
    @Autowired
    private Deliverable deliverable;
    @Test
    public void test() {
        speakable.say();
        deliverable.delivery();
    }
}

其中@RunWith這個注解指定了讓單元測試運行於Spring的環境中,@ContextConfiguration這個注解指定Spring加載的配置文件。

4、測試結果

執行單元測試,測試結果如下。

D:\Environments\jdk-11.0.2\bin\java.exe...

訂單號202001141004,金額8888.0,已發貨!
Order{orderId=202001141004, amount=8888.0}



Process finished with exit code 0

結論:在配置文件加載的時候。其中管理的對象都已經初始化了!

Order使用有參構造器的方式,實現有參構造器的IoC。

通過注解方式實現

除了通過構造器實現IoC,還可以通過Spring提供的注解方法實現IoC,這也是企業開發過程中最常用的一種IoC實現方式。

1、編寫一個Student實體類

下面通過學生類Student闡述注解的方式實現IoC。

接口 HomeWork.java

package com.test.ioc.annotation;

public interface HomeWork {
    /** * 寫家庭作業 */
    void doHomeWork();
}

Student類的定義如下:

package com.test.ioc.annotation;

import org.springframework.stereotype.Service;

@Service
public class Student implements HomeWork {
    /** * 寫家庭作業 */
    @Override
    public void doHomeWork() {
        System.out.println("我是學生,我要寫家庭作業");
    }
}

注意此時的Student類上加了一個@Service注解,這告訴Spring,讓其管理這個類的對象,因此開發人員就不再需要管理Student對象了。

2、編寫我們的spring文件

與XML方式實現的IoC不同的是,注解方式除了配置@Service注解外,還需要指定Spring對需要管理的bean目錄,否則Spring不能定位其需要管理的bean。具體配置如下:

<!--spring 管理的bean的路徑-->
    <context:component-scan base-package="com.test.ioc"></context:component-scan>

spring-chapter2.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">
	 
    <!--spring 管理的bean的路徑-->
    <context:component-scan base-package="com.test.ioc"></context:component-scan>

</beans>

3、依賴注入,將對象注入到測試類中

接下來在測試類AnnotationTest中通過依賴注入,將HomeWork對象注入到AnnotationTest測試類中,測試代碼如下:

package ioc.annotation;

import com.test.ioc.annotation.HomeWork;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;

/** * 測試注解方式的IoC */
@RunWith(SpringRunner.class)
@ContextConfiguration("classpath:spring-chapter2.xml")
public class AnnotationTest {
    @Autowired
    private HomeWork homeWork;
    //Spring 容器注入依賴的Deliverable對象
    @Test
    public void test() {
        homeWork.doHomeWork();
    }
}

4、測試結果

運行單元測試,測試結果如下:

D:\Environments\jdk-11.0.2\bin\java.exe 

我是學生,我要寫家庭作業



Process finished with exit code 0

除了例中的注解@Service可以實現Bean的IoC以外,Spring還提供了很多其他的注解來實現IoC。

(1)@Component將Java類標記成一個Spring Bean組件。

(2)@Service將業務層實現類標記成一個Spring Bean組件。

(3)@Controller將控制層類標記成一個Spring Bean組件。

(4)@Repository將一個持久層實現類標記成一個Spring Bean組件。

Spring 配置

別名

alias 設置別名 , 為bean設置別名 , 可以設置多個別名

<!--設置別名:在獲取Bean的時候可以使用別名獲取-->
<alias name="user" alias="userNew"/>

Bean配置

<!--bean就是java對象,由Spring創建和管理-->

<!-- id 是bean的標識符,要唯一,如果沒有配置id,name就是默認標識符 如果配置id,又配置了name,那么name是別名 name可以設置多個別名,可以用逗號,分號,空格隔開 如果不配置id和name,可以根據applicationContext.getBean(.class)獲取對象; class是bean的全限定名=包名+類名 -->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
    <property name="name" value="Spring"/>
</bean>

import

團隊的合作通過import來實現 .

<import resource="{path}/beans.xml"/>

參考資料

1.Spring 5企業級開發實戰/周冠亞,黃文毅著.—北京:清華大學出版社,2019

2.Spring:概述、IOC理論-秦疆-–https://www.bilibili.com/video/av71110355

3.Spring:第一個程序、對象創建方式、配置說明-秦疆。https://www.bilibili.com/video/av71110355


免責聲明!

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



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