1. 程式人生 > 其它 >Spring5——IOC操作Bean管理(基於xml檔案)

Spring5——IOC操作Bean管理(基於xml檔案)

前言

最近在學習Spring5框架,下面關於Spring5之IOC容器管理Bean的學習筆記和心得,如有錯誤,歡迎指正。

學習資源:

尚矽谷Spring5框架教程(idea版)

IOC容器

控制反轉(IOC)。IOC容器就是具有依賴注入功能的容器,面向物件中的一種設計原則,可以降低程式碼之間的耦合度。通過IOC,物件在被建立的時候,由一個調控系統內所有物件的外界實體將其所有依賴的物件的引用傳遞給它,即依賴被注入到物件中。

通俗點來講,就是通過IOC我們可以使用第三方工具來建立物件,而不必再使用傳統方法 new 一個物件,並且可以通過IOC容器將其他物件、屬性注入到需要建立的物件中去,這一切都交給IOC進行管理,大大降低程式碼的耦合度。

  • 把物件的建立和物件之間呼叫的操作都交給Spring進行管理;
  • 使用IOC的目的:降低耦合度;

IOC底層原理

  • xml解析、工廠模式、反射

IOC介面(BeanFactory)

IOC的思想要基於IOC的容器來完成,本質上就是物件工廠(主要還是要實現 BeanFactory 這個介面);

Spring中對於容器的實現提供了兩種方法(也就是兩個介面):

  • BeanFactory:IOC容器內部使用的介面,一般不提供給開發人員使用(載入配置檔案的時候,不會建立物件,而是在獲取物件(使用物件)的時候才去建立物件);
  • ApplicationContext:BeanFactory的子介面,提供更強大的功能,一般給開發人員進行使用(載入配置檔案的時候,就會將配置檔案中物件進行建立)。
  • l兩者都可以載入配置檔案,建立物件
  • ApplicationContext中介面有實現類

IOC操作Bean管理(基於xml檔案)

建立物件:通過在xml檔案中使用bean標籤,並且在標籤中的屬性設定值,我們就可以在Java程式中建立一個物件。

比如下面的配置檔案中,我們就建立了一個Users類的物件users,並且可以通過users來呼叫Users類中的add方法。

<?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="users" class="com.blue.spring5.Users"></bean>
</beans>
        //在Spring的配置檔案中,使用bean標籤,並在標籤中新增對應的屬性,就可以實現物件的建立
        //常用屬性
        id屬性:給物件起一個標識,可以通過id獲得物件
        class屬性:寫要建立的物件所在的類的全路徑
        name屬性:與id作用類似,但是id中不能新增特殊符號,id中可以
        //在建立物件的時候預設執行無參構造器
package com.blue.spring5;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * User: Blueshadow
 * Date&Time: 2021/12/8 21:10
 */
public class TestUsers {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        Users users = context.getBean("users", Users.class);
        users.add();
    }
}

注入屬性

  • 通過xml檔案,我們可以在建立物件過程中,將給物件注入需要的屬性值。
//DI:依賴注入(注入屬性),DI是IOC中的一種具體實現,必須在建立物件的基礎上實現

package com.blue.spring5.testDemo;

public class Book {
    private String bName;//書名

    public void setbName(String bName) {
        this.bName = bName;
    }
    public Book(){}
    public Book(String bName) {
        this.bName = bName;
    }

    public static void main(String[] args) {
        //set方法注入
        Book book = new Book();
        book.setbName("西遊記");
        System.out.println(book.bName);
        
        //有參構造器引數注入
        Book book = new Book("西遊記");
        System.out.println(book.bName);
    }
}

  • 基於Spring的xml配置檔案配置物件建立,配置set方法屬性注入
 <!--配置屬性注入-->
    <!--set方法注入屬性-->
    <bean id="book" class="com.blue.spring5.testDemo.Book">
        <!--在bean標籤裡面使用property標籤完成屬性注入
            name 類裡面屬性名稱
            value 向屬性注入的值
        -->
        <property name="bName" value="西遊記"></property>
        <property name="bauthor" value="羅貫中"></property>
  • 基於Spring的xml配置檔案配置物件建立,配置引數方法屬性注入
<!--用有參構造器注入-->
    <!--建立物件-->
    <bean id="orders" class="com.blue.spring5.Orders">
        <constructor-arg name="oName" value="abc"></constructor-arg>
        <constructor-arg name="address" value="china"></constructor-arg>
    </bean>
  • 基於Spring的xml配置檔案注入空值和特殊符號
    • 字面量:給類中的屬性設定的固定值
    • null;
    • 特殊符號。
 <property name="address">
            <value>
                <![CDATA[《北京》]]>
            </value>
  </property>

注入集合型別屬性

可以通過配置檔案,將集合型別的資料注入到物件屬性中去。

  • 注入陣列型別屬性

  • 注入List集合型別屬性

  • 注入Map集合型別屬性

<?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="stu" class="com.blue.spring5.collectiontype.Student">
        <!--集合型別屬性注入-->
        <!--陣列型別屬性注入-->
        <property name="course">
            <array>
                <value>語文</value>
                <value>數學</value>
            </array>
        </property>
        <!--list型別集合屬性注入-->
        <property name="lists">
            <list>
                <value>張三</value>
                <value>李四</value>
            </list>
        </property>
        <!--map型別集合屬性注入-->
        <property name="map">
            <map>
                <entry key="JAVA" value="java"></entry>
                <entry key="PYTHON" value="python"></entry>
            </map>
        </property>
        <!--set型別集合屬性注入-->
        <property name="set">
            <set>
                <value>Redis</value>
                <value>MySQL</value>
            </set>
        </property>
    </bean>


</beans>
package com.blue.spring5.testDemo;


import com.blue.spring5.collectiontype.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@SuppressWarnings({"all"})
/**
 * @Author Blueshadow
 * @Date 2021/10/24 20:55
 * @Version 1.0
 */
public class TestSpring5 {
    @Test
    public void testCourse(){
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean1.xml");
        Student stu = context.getBean("stu", Student.class);
        stu.testDemo();
    }
}



package com.blue.spring5.collectiontype;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Student {
    //陣列型別的屬性
    private String[] course;
    private List<String> lists;
    private Map<String,String> map;//k-v結構
    private Set<String> set;

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setCourse(String[] course) {
        this.course = course;
    }

    public void setLists(List<String> lists) {
        this.lists = lists;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void testDemo(){
        System.out.println(Arrays.toString(course));
        System.out.println(lists);
        System.out.println(map);
        System.out.println(set);
    }
}

注入外部Bean

注入外部bean,就是在xml檔案中建立兩個物件,然後將其中一個物件注入到另一個物件中去,這種方法可以用於處理業務邏輯層和DAO層之間的物件引用。

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

<!--    service 和 DAO 的物件進行建立-->
    <bean id="userService" class="com.blue.service.UserService">
<!--        在 service 中注入 userDAO 物件-->
        <property name="userDAO" ref="userDAO"></property>
<!--        完成了注入-->    
    </bean>
    
<!--    建立 DAO 物件-->
    <bean id="userDAO" class="com.blue.dao.UserDAOImpl"></bean>
    
</beans>
  • service
package com.blue.service;

import com.blue.dao.UserDAOImpl;
import com.blue.dao.UserDAOInterface;

/**
 * User: Blueshadow
 * Date&Time: 2021/12/6 16:42
 */
public class UserService {
    //建立 UserDAO 型別屬性
    private UserDAOInterface userDAO;

    public UserDAOInterface getUserDAO() {
        return userDAO;
    }

    public void setUserDAO(UserDAOInterface userDAO) {
        this.userDAO = userDAO;
    }

    public void add(){
        System.out.println("Service add ...");
        userDAO.upDate();
    }
}

注入內部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注入操作-->
    <bean id="emp" class="com.blue.bean.Emp">
        <property name="name" value="jack"></property>
        <property name="gender" value="男"></property>
        <property name="dept">
<!--            再巢狀定義一個物件-->
            <bean id="dept" class="com.blue.bean.Dept">
                <property name="dname" value="開發部"></property>
            </bean>
        </property>
    </bean>



</beans>
  • 級聯賦值1
<?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="emp" class="com.blue.bean.Emp">
        <property name="name" value="jack"></property>
        <property name="gender" value="男"></property>
<!--        級聯賦值-->
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="com.blue.bean.Dept">
        <property name="dname" value="財務部"></property>
    </bean>




</beans>
  • 級聯賦值2
<?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="emp" class="com.blue.bean.Emp">
        <property name="name" value="jack"></property>
        <property name="gender" value="男"></property>
<!--        級聯賦值-->
        <property name="dept" ref="dept"></property>
        <!--        需要有dept物件的get方法-->
        <property name="dept.dname" value="技術部"></property>
    </bean>
    <bean id="dept" class="com.blue.bean.Dept">
    </bean>




</beans>

Bean管理

Factory Bean

  • Spring中有兩種bean,一種是普通bean,一種是 FactoryBean(工廠bean)
  • 普通bean在配置檔案中,定義的物件型別就是返回型別
  • FactoryBean在配置檔案中定義的物件型別可以和返回型別不同
package com.blue.factorybean;

import com.blue.colectiontype.Course;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * User: Blueshadow
 * Date&Time: 2021/12/7 20:15
 * 該類作為一個工廠bean
 */
public class FactoryBean_ implements FactoryBean<Course> {

    //自定義要返回的型別
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("1906");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

Bean的作用域

  • 在Spring中可以設定,建立的ben例項是單例項還是多例項
  • 預設情況下建立的是單例項物件
  • 顧名思義:單例項物件就是一個物件,多例項物件就是兩個不同的物件
<?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="student" class="com.blue.colectiontype.Stu"></bean>


</beans>
package com.blue.scope;

import com.blue.colectiontype.Stu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * User: Blueshadow
 * Date&Time: 2021/12/7 20:56
 */
public class Scope_ {
    public static void main(String[] args) {
        new Scope_().testScope();
    }
    public void  testScope(){
        ApplicationContext context = new ClassPathXmlApplicationContext("scope.xml");
        Stu student1 = context.getBean("student", Stu.class);
        Stu student2 = context.getBean("student",Stu.class);
        System.out.println("stu1: "+student1);
        System.out.println("stu2: "+student2);
        //stu1: com.blue.colectiontype.Stu@5f341870
        //stu2: com.blue.colectiontype.Stu@5f341870
    }
}

  • 多例項物件
    • 通過bean標籤中的scope屬性來設定多例項物件(scope屬性值:singleton 單例項物件、prototype 多例項物件)
    • 兩者區別
      • singleton 單例項、prototype 多例項
      • 設定singleton時,在載入配置檔案過程中,會建立單例項物件
      • 設定prototype時,不是在載入配置檔案過程中建立物件,而是在呼叫 getBean 方法過程中建立物件,即每次建立的都是一個新的物件
<?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="student" class="com.blue.colectiontype.Stu" scope="prototype"></bean>


</beans>
package com.blue.scope;

import com.blue.colectiontype.Stu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * User: Blueshadow
 * Date&Time: 2021/12/7 20:56
 */
public class Scope_ {
    public static void main(String[] args) {
        new Scope_().testScope();
    }
    public void  testScope(){
        ApplicationContext context = new ClassPathXmlApplicationContext("scope.xml");
        Stu student1 = context.getBean("student", Stu.class);
        Stu student2 = context.getBean("student",Stu.class);
        System.out.println("stu1: "+student1);
        System.out.println("stu2: "+student2);
        //stu1: com.blue.colectiontype.Stu@f6c48ac
        //stu2: com.blue.colectiontype.Stu@13deb50e
    }
}

Bean的生命週期

  • 物件建立~物件銷燬的過程被稱作bean的生命週期
    • 通過無參構造器去建立例項;
    • 為bean的屬性設定對應的值或者對其他bean的引用(呼叫set方法);
    • 把bean的例項傳遞給bean的後置處理器的方法 postProcessBeforeInitialization;
    • 呼叫bean裡面初始化的方法(需要進行配置);
    • 把bean的例項傳遞給bean的後置處理器的方法 postProcessAfterInitialization;
    • bean可以使用了(物件獲取到了);
    • 當容器在關閉的時候,會呼叫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="orders" class="com.blue.lifecycle.Orders" init-method="initMethod" destroy-method="destoryMethod">
        <property name="oname" value="vivo"></property>
    </bean>


</beans>
package com.blue.lifecycle;

/**
 * User: Blueshadow
 * Date&Time: 2021/12/7 21:18
 */
public class Orders {
    private String oname;
    public Orders() {
        System.out.println("執行了Orders的無參構造器 ...");
    }
    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("呼叫了setOname 設定屬性值 ...");
    }

    //建立執行的初始化方法
    public void initMethod(){
        System.out.println("執行初始化方法 ...");
    }

    //銷燬物件的方法
    public void destoryMethod(){
        System.out.println("執行銷燬物件方法 ...");
    }

    @Override
    public String toString() {
        return "Orders{" +
                "oname='" + oname + '\'' +
                '}';
    }
}

package com.blue.lifecycle;

import com.sun.xml.internal.ws.api.pipe.ClientTubeAssemblerContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * User: Blueshadow
 * Date&Time: 2021/12/7 21:19
 */
public class TestOrders {
    public static void main(String[] args) {
        new TestOrders().testOrders();
    }
    public void testOrders(){
        ApplicationContext context = new ClassPathXmlApplicationContext("lifecycle.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("獲取到了創建出來的例項物件 ... "+orders);
        System.out.println(orders);

        //手動銷燬例項物件
        ((ClassPathXmlApplicationContext)context).close();
    }
    //執行了Orders的無參構造器 ...
    //呼叫了setOname 設定屬性值 ...
    //執行初始化方法 ...
    //獲取到了創建出來的例項物件 ... Orders{oname='vivo'}
    //Orders{oname='vivo'}
    //執行銷燬物件方法 ...
}

xml自動裝配

  • 手動裝配:在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 id="emp" class="com.blue.autowire.Emp" autowire="byType">
<!--        <property name="dept" ref="dept"></property>-->
    </bean>
    <bean id="dept" class="com.blue.autowire.Dept"></bean>


</beans>

外部屬性檔案

這種操作在連線資料庫的過程中會用到,可以將properties配置檔案引入到xml檔案中,然後在程式中引用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"
       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/beans/spring-context.xsd">
<!--    直接配置連線池-->
<!--    建立druid連線物件-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!-- dataSource.setDriverClassName("com.mysql.jdbc.Driver");
			set方法注入
		-->
        <!-- 獲取properties檔案內容,根據key獲取,使用spring表示式獲取 -->
<!--        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>-->
<!--        <property name="url" value="jdbc:mysql://locahost:3306/test"></property>-->
<!--        <property name="username" value="root"></property>-->
<!--        <property name="password" value="xxx"></property>-->

<!--        引入外部的properties屬性檔案-->
        <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--        配置連線池-->
        <property name="driverClassName" value="${driverClassName}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>
    </bean>


</beans>
#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
#url=jdbc:mysql://localhost:3306/girls
username=root
password=xxx
#initial connection Size
initialSize=10
#min idle connecton size

minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000