文章目錄
簡單記錄 Spring5企業級開發實戰 周冠亞,黃文毅著- 和 Spring5最新完整教程IDEA版-秦疆
Spring IoC的實現方式
IoC是Spring框架的核心內容,使用多種方式完美的實現了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置實現IoC。
Spring容器在初始化時先讀取配置文件,根據配置文件或元數據創建與組織對象存入容器中,程序使用時再從Ioc容器中取出需要的對象(容器中獲取Bean)。
采用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