Spring IOC—基于XML配置和管理Bean 万字详解(通俗易懂)

2023-12-05

目录

一、前言

二、通过类型来获取Bean

0.总述(重要) :

1.基本介绍 :

2.应用实例 :

三、通过指定构造器为Bean注入属性

1.基本介绍 :

2.应用实例 :

四、通过p命名空间为Bean注入属性

1.基本介绍 :

2.应用实例 :

五、通过ref引用实现Bean的相互引用

1.基本介绍 :

2.应用实例 :

六、对Bean注入属性的内容延伸

1.准备工作 :

2.注入List类型的属性 :

3.注入Set类型的属性 :

4.注入Map类型的属性 :

5.注入数组类型的属性 :

6.注入Properties类型的属性 :

7.List属性注入之通过util命名空间注入 :

8.级联属性注入 :

七、通过静态工厂获取Bean

1.基本介绍 :

2.应用实例 :

八、通过实例工厂获取Bean

1.基本介绍 :

2.应用实例 :

九、通过FactoryBean获取Bean

1.基本介绍 :

2.应用实例 :

十、关于Bean配置的更多内容和细节

十一、总结


一、前言

  • 第二节内容 ,up打算和大家分享一下 Spring IOC——基于XML方式对Bean的配置和管理 。(PS: 若对XML文件未曾了解,可以去快速阅读一下up的“ 速通XML ”一文。)
  • 注意事项—— 代码中的注释也很重要; 不要眼高手低,自己跟着过一遍才有收获; 点击文章的侧边栏目录或者文章开头的目录可以进行跳转。
  • 良工不示人以朴,所有文章都会适时补充完善。大家如果有问题都可以在评论区进行交流或者私信up。 感谢阅读!

二、通过类型来获取Bean

0.总述( 重要 ) :

(1) Spring对 Bean的管理 主要包括两方面内容—— 创建bean对象 为bean注入属性

(2) Spring对 Bean的配置方式 也主要是两种—— 基于XML文件配置的方式 基于注解配置的方式

(3) 上一小节中,我们已经演示过“通过id属性来获取bean对象”的方式( 基于beans.xml配置文件 ),因此这一小节,我们直接演示其他方式(这一小节均是基于XML文件配置的方式)。

1.基本介绍 :

(1) 通过类型来获取bean对象 ,其实是调用了 getBean(Class<T> aClass) 方法,该方法与我们上一小节中演示的“ 通过id获取bean对象 ”的方法构成重载,如下图所示 :

(2) 通过类型来获取bean时,要求 ioc容器中同一类型的bean对象只能有一个 ,否则会抛出异常 NoUniqueBeanDefinitionException( 不唯一Bean定义异常 ,如下图所示 :

(3) “通过类型获取Bean”方式的 适用场景 —— 在一个线程中只需要一个对象实例(单例)的情况 ,eg : XxxAction / Servlet / Controller / XxxService。

(4) PS : 在容器配置文件(eg : beans.xml)中给bean对象的属性赋值,底层是通过 setter 方法完成的 ,因此我们定义的JavaBean(比如之前的Student)类中,必须提供相应的setter方法,否则报错。

2.应用实例 :

需求 : 在beans.xml配置文件中配置一个bean对象,并通过Class类型的方式来获取到该bean对象。
首先,我们需要创建一个JavaBean类,以Student类为例, Student类代码如下 :

package com.cyan.spring.bean;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class Student {
    private String name;
    private int age;
    private int score;

    //PS : 无参构造器必须给出,因为底层要通过反射来创建对象。
    public Student() {

    }
    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

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

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

然后,在beans.xml配置文件中,配置一个Student类对象, beans.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">

    <!--
        (1) 在根元素beans中,通过<bean></bean>子元素来配置JavaBean对象。
            每配置一个bean,相当于配置了一个Java对象。
        (2) bean子元素需要配置两个属性———class 和 id。其中,
            class表示所要实例化类的正名(全类名);
            id表示该对象在Spring容器中的标识,通过id可以获取到对象。
        (3) property子元素用于配置该对象的成员变量(对象的属性),其中,
            name表示属性名称,value表示属性的值。
        (4) XML内容回顾———若一个标签没有标签体,以<age></age>为例,可以简写为<age/>。
    -->

    <!-- 注意———此处我们没有为bean标签配置id属性,默认的分配id为:全类名#0 -->
    <bean class="com.cyan.spring.bean.Student">
        <property name="name" value="Rain"></property>
        <property name="age" value="19"></property>
        <property name="score" value="439"></property>
    </bean>
</beans>

接着,在测试类中调用 getBean(Class<T> aClass) 方法,以StudentBeanByXML类为测试类,通过JUnit框架进行单元测试, StudentBeanByXML类代码如下 :

package com.cyan.spring.test;

import com.cyan.spring.bean.Student;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class StudentBeanByXML {
    //1.通过类型来获取Bean
    @Test
    public void getBeanByClass() {
        //(1) 获取Spring容器对象
            //IOC : Inversion Of Control
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        //(2) 通过JavaBean的类型来获取bean
        Student bean = ioc.getBean(Student.class);

        //(3) 打印出获取到的bean对象的信息
        System.out.println(bean);
    }
}

运行结果 :


三、通过指定构造器为Bean注入属性

1.基本介绍 :

通过指定构造器为Bean注入属性 ”,即在beans.xml配置文件中通过 <constructor-arg/>标签 来指定一个JavaBean中的带参构造,利用该 带参构造 来完成对Bean的属性的初始化,其配置方式本质仍然是“ IOC——基于XML文件配置Bean ”。如下图所示 :

上图中演示的为通过 index索引 来确定参数,还可以通过 type类型 或者 name属性名 来确定参数,本质都是根 据形参来唯一确定一个带参构造

2.应用实例 :

需求 : 在beans.xml文件中新配置一个Bean对象,并通过<constructor-arg/>标签指定Student类的一个带参构造来初始化该Bean的属性。在StudentBeanByXML类中新定义一个单元测试方法,通过id属性获取到该Bean对象,并检测属性注入是否成功。
仍然使用Student类作为JavaBean类,首先我们要在beans.xml文件中配置Bean对象,up为了演示一下 index, type, name 三种形式的<constructor-arg/>标签,此处配置了三个Bean对象, 代码如下 :

    <bean class="com.cyan.spring.bean.Student" id="stu03">
        <constructor-arg value="Cyan" index="0"></constructor-arg>
        <constructor-arg value="21" index="1"></constructor-arg>
        <constructor-arg value="453" index="2"></constructor-arg>
    </bean>
    <bean class="com.cyan.spring.bean.Student" id="stu04">
        <constructor-arg value="Eisen" type="java.lang.String"></constructor-arg>
        <constructor-arg value="21" type="int"></constructor-arg>
        <constructor-arg value="442" type="int"></constructor-arg>
    </bean>
    <bean class="com.cyan.spring.bean.Student" id="stu05">
        <constructor-arg value="Five" name="name"></constructor-arg>
        <constructor-arg value="20" name="age"></constructor-arg>
        <constructor-arg value="460" name="score"></constructor-arg>
    </bean>

接着,在StudentBeanByXML类中新定义一个方法,分别获取到id = stu03, id = stu04, id = stu05的对象, insertPropertiesByConstructor()方法代码如下 :

    //2.通过指定构造器为Bean注入属性
        //回顾————
        //对Bean的管理包括两方面 (1) 创建bean对象;(2) 为bean对象注入属性。
    @Test
    public void insertPropertiesByConstructor() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        Student stu03 = ioc.getBean("stu03", Student.class);
        Student stu04 = ioc.getBean("stu04", Student.class);
        Student stu05 = ioc.getBean("stu05", Student.class);

        System.out.println("stu03 = " + stu03);
        System.out.println("stu04 = " + stu04);
        System.out.println("stu05 = " + stu05);
    }

运行结果 :

可以看到,打印出的属性值与我们配置的一致,说明带参构造成功初始化该bean对象。


四、通过p命名空间为Bean注入属性

1.基本介绍 :

前文中用<bean></bean>标签配置Bean对象时,我们用到了 class属性(JavaBean的全类名),id属性(对象在容器中的标识) 。现在我们可以用" p:property_name = property_value "( 注意冒号 )的形式,直接在bean标签内部为Bean注入属性,但直接使用会报错,如下图所示 :

报错提示 : " Namespace 'p' is not bound "(命名空间p未绑定)。

解决方法 : 将鼠标悬停在报错处,按下Alt + Enter,选择" Create namespace declaration "(创建命名空间声明),如下图所示 :

创建命名空间声明后, 可以看到beans.xml 根元素中已经自动加入了p命名空间的声明 ,如下图所示 :

2.应用实例 :

需求 : 在beans.xml文件中新配置一个Bean对象,并通过p命名空间为该对象注入属性。在StudentBeanByXML类中新定义一个单元测试方法,打印该对象信息,检测属性注入是否成功。
仍然使用Student类作为JavaBean类,首先我们要在beans.xml文件中配置Bean对象, 代码如下 :

    <bean class="com.cyan.spring.bean.Student" id="stu06" p:name="Peter" p:age="33" p:score="1024">

    </bean>

接着,在StudentBeanByXML测试类中新定义一个方法,获取到id = stu06的对象, injectPropertiesByP()方法代码如下 :

    //3.通过p命名空间为Bean注入属性
    @Test
    public void injectPropertiesByP() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        Student stu06 = ioc.getBean("stu06", Student.class);

        System.out.println("stu06 = " + stu06);
    }

运行结果 :


五、通过ref引用实现Bean的相互引用

1.基本介绍 :

(1) 在JavaWeb中(比方说我们之前的Web项目——尘歌壶摆设购买系统),我们利用“ 分层设计 ”的思想,会分别建立DAO层,Service层,Web层;并根据“Web层调用Service层,Service层调用DAO层”的思想,在XxxServlet类中new一个XxxService对象,在XxxService类中new一个XxxDao对象。如下图所示 :

(2) 而有了 Spring 的加持后,我们可以 通过ref(引用)来实现IOC容器中bean对象的相互引用, 其本质是通过ref引用来为一个对象的引用类型的属性进行初始化,即属于“Bean管理——为bean注入属性”的范畴

(3) ref在使用时,是作为property标签的一个属性(我们之前已经多次用到了property标签), 格式如下 :

<property name="property_name" ref ="otherBeans id"></property>(更多说明见beans.xml中的注释)

2.应用实例 :

需求 : 参照之前JavaWeb中“分层设计”的思想,在Service层中调用DAO层,但是不直接new出实例,而是在beans.xml文件中通过ref进行配置,试着根据输出语句,测试注入属性是否成功。
首先,我们需要创建用于测试的Service层和DAO层的类,以我们之前的尘歌壶摆设购买系统为参考,如下图所示 :

FurnishingDAOImpl类代码如下 : (定义了一个用于添加摆设的addFurnishing方法)

package com.cyan.spring.dao;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class FurnishingDAOImpl {
    public FurnishingDAOImpl() {
        System.out.println("FurnishingDAOImpl的无参构造被调用~");
    }
    public void addFurnishing() {
        System.out.println("FurnishingDAOImpl的addFurnishing方法被调用~");
    }
}

FurnishingServiceImpl类代码如下 : (定义了一个FurnishingDAOImpl类型的属性,我们将在beans.xml文件中对其进行初始化;此外,定义addFurnishing()方法,实现Service层调用DAO层)

package com.cyan.spring.service;

import com.cyan.spring.dao.FurnishingDAOImpl;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class FurnishingServiceImpl {
    //Service层调用DAO层(但通过beans.xml文件进行配置)
    private FurnishingDAOImpl furnishingDAO;

    public FurnishingServiceImpl() {
    }

    //About DAO's setter,getter
    public FurnishingDAOImpl getFurnishingDAO() {
        return furnishingDAO;
    }

    public void setFurnishingDAO(FurnishingDAOImpl furnishingDAO) {
        this.furnishingDAO = furnishingDAO;
    }

    //Add Furnishing
    public void addFurnishing() {
        System.out.println("FurnishingServiceImpl的addFurnishing()方法被调用~");
        furnishingDAO.addFurnishing();
    }
}

在beans.xml中配置这两个对象, 代码如下 : ( 注意看注释

    <!--
        (1) 配置一个FurnishingDAOImpl对象;
        (2) 由于该类暂时没有设置属性,所以此处不需要注入属性(下面furnishingService01同理)
     -->
    <bean class="com.cyan.spring.dao.FurnishingDAOImpl" id="furnishingDAO01"/>
    <!--
        (1) 配置一个FurnishingServiceImpl对象;
        (2) 仍然是通过property子元素来为id = furnishingService01的对象注入属性,
            注意,此处的"ref" 表示————
                id = furnishingService01的对象的furnishingDAO属性,
                引用了上面配置的id = furnishingDAO01的对象
            PS : ref体现了Spring的依赖注入(即一个对象的属性,引用了另一个对象)
     -->
    <bean class="com.cyan.spring.service.FurnishingServiceImpl" id="furnishingService01">
        <property name="furnishingDAO" ref="furnishingDAO01"></property>
    </bean>

最后,仍是在StudentBeanByXML测试类中新定义一个方法,测试FurnishingServiceImpl的FurnishingDAOImpl属性是否被初始化。
injectPropertiesByRef()方法代码如下 :

    //4.通过ref引用实现Bean的相互引用
    @Test
    public void injectPropertiesByRef() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        FurnishingServiceImpl furnishingService01 = ioc.getBean("furnishingService01", FurnishingServiceImpl.class);

        furnishingService01.addFurnishing();
    }

运行结果 :

可以看到,FurnishingDAOImpl类的无参构造成功被调用,说明它被成功初始化。
其实, 除了使用ref属性外,还可以直接通过配置内部bean来完成对属性的初始化,如下所示 :

    <bean class="com.cyan.spring.service.FurnishingServiceImpl" id="furnishingService02">
        <property name="furnishingDAO">
            <bean class="com.cyan.spring.dao.FurnishingDAOImpl"/>
        </property>
    </bean>

这种方法的意思是,对引用类型属性的初始化不再使用Spring容器中已经配置好的对象,而是自己重新配置一个bean。经过测试,配置内部bean的方法也可以成功注入,大家有兴趣可以自己去试试。


六、对Bean注入属性的内容延伸

1.准备工作 :

上文中我们已经演示过多种为bean注入属性的方式,比如“通过指定构造器注入”,“通过p命名空间注入”,“通过ref引用实现Bean的相互引用”等。现在,让我们来讨论一下, 如果bean对象的属性是数组或者集合类型,我们又该怎样去注入呢?

为了实现“注入数组 or 集合类型的属性”,我们先来创建一个类去维护这些属性, School类代码如下 :

package com.cyan.spring.bean;

import java.util.*;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class School {
    private List<Student> studentList;
    private Set<Student> studentSet;
    private Map<String, Student> studentMap;
    private String[] studentNames;
    private Properties pros;

    public School() {

    }
    public School(List<Student> studentList, Set<Student> studentSet, Map<String, Student> studentMap, String[] studentNames, Properties pros) {
        this.studentList = studentList;
        this.studentSet = studentSet;
        this.studentMap = studentMap;
        this.studentNames = studentNames;
        this.pros = pros;
    }

    public List<Student> getStudentList() {
        return studentList;
    }
    public void setStudentList(List<Student> studentList) {
        this.studentList = studentList;
    }

    public Set<Student> getStudentSet() {
        return studentSet;
    }
    public void setStudentSet(Set<Student> studentSet) {
        this.studentSet = studentSet;
    }

    public Map<String, Student> getStudentMap() {
        return studentMap;
    }
    public void setStudentMap(Map<String, Student> studentMap) {
        this.studentMap = studentMap;
    }

    public String[] getStudentNames() {
        return studentNames;
    }
    public void setStudentNames(String[] studentNames) {
        this.studentNames = studentNames;
    }

    public Properties getPros() {
        return pros;
    }
    public void setPros(Properties pros) {
        this.pros = pros;
    }

    @Override
    public String toString() {
        return "School{" +
                "studentList=" + studentList +
                ", studentSet=" + studentSet +
                ", studentMap=" + studentMap +
                ", studentNames=" + Arrays.toString(studentNames) +
                ", pros=" + pros +
                '}';
    }
}

接着,我们在beans.xml中 配置一个School类型的Bean对象 ,代码如下 :

    <bean class="com.cyan.spring.bean.School" id="school01">
        <!-- 暂未给属性赋值 -->
    </bean>

2.注入List类型的属性 :

在刚刚配置的id = school01的bean对象中,通过property标签为 List 类型的属性初始化,代码如下 :

        <property name="studentList">
            <list>
                <ref bean="stu03"></ref>
                <ref bean="stu04"></ref>
            </list>
        </property>

注入, 除了"通过ref元素配置"的形式外,也可以在List元素中直接配置内部Bean 。仍然是在StudentBeanByXML测试类中,我们新定义一个方法测试List属性是否注入成功, injectList()方法代码如下 :

    //5.为Bean注入集合 or 数组类型的属性
        //5.1 注入List类型的属性
    @Test
    public void injectList() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        School school01 = ioc.getBean("school01", School.class);

        System.out.println("School中的studentList属性如下 : ");
        System.out.println(school01.getStudentList());
    }

运行结果 :

3.注入Set类型的属性 :

在“准备工作”中配置的id = school01的bean对象中,通过property标签为 Set 类型的属性初始化,代码如下 :

        <property name="studentSet">
            <set>
                <ref bean="stu03"></ref>
                <ref bean="stu06"></ref>
            </set>
        </property>

可以看到,Set类型属性的配置和List类型属性的配置非常类似,只不过前者是放在set元素里了。仍然是在StudentBeanByXML测试类中,我们新定义一个方法测试Set属性是否注入成功, injectSet()方法代码如下 :

        //5.2 注入Set类型的属性
    @Test
    public void injectSet() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        School school01 = ioc.getBean("school01", School.class);

        System.out.println("School中的studentSet属性如下 : ");
        System.out.println(school01.getStudentSet());
    }

运行结果 :

4.注入Map类型的属性 :

在“准备工作”中配置的id = school01的bean对象中,通过property标签为 Map 类型的属性初始化,代码如下 :

        <property name="studentMap">
            <map>
                <!-- entry表示一个键值对  -->
                <entry>
                    <!-- key元素用于配置key,注意此处的value是指key的值,字面意思 -->
                    <key>
                        <value>keyStu05</value>
                    </key>
                    <!-- 紧跟key元素其后的ref元素才是真正的当前键值对的value! -->
                    <ref bean="stu05"></ref>
                </entry>
                <entry>
                    <key>
                        <value>keyStu06</value>
                    </key>
                    <ref bean="stu06"></ref>
                </entry>
            </map>
        </property>

仍然是在StudentBeanByXML测试类中,我们新定义一个方法测试Map属性是否注入成功, injectMap()方法代码如下 :

        //5.3 注入Map类型的属性
    @Test
    public void injectMap() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        School school01 = ioc.getBean("school01", School.class);

        System.out.println("School中的studentMap属性如下 : ");
        System.out.println(school01.getStudentMap());
    }

运行结果 :

5.注入数组类型的属性 :

在“准备工作”中配置的id = school01的bean对象中,通过property标签为 String[] 类型的属性初始化,代码如下 :

        <property name="studentNames">
            <array>
            <!-- 由于School类中维护的数组为String类型,所以此处直接以value元素配置 -->
                <value>Cyan</value>
                <value>Rain</value>
                <value>Five</value>
                <value>Ice</value>
            </array>
        </property>

仍然是在StudentBeanByXML测试类中,我们新定义一个方法测试String[]属性是否注入成功, injectArray()方法代码如下 :

        //5.4 注入数组类型的属性
    @Test
    public void injectArray() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        School school01 = ioc.getBean("school01", School.class);

        System.out.println("School中的studentNames属性如下 : ");
        System.out.println(Arrays.toString(school01.getStudentNames()));
    }

运行结果 :

6.注入Properties类型的属性 :

在“准备工作”中配置的id = school01的bean对象中,通过property标签为 Properties 类型的属性初始化,代码如下 :

        <property name="pros">
            <props>
                <prop key="username">Cyan_RA9</prop>
                <prop key="password">55555233</prop>
                <prop key="ip">127.0.0.1</prop>
            </props>
        </property>

仍然是在StudentBeanByXML测试类中,我们新定义一个方法测试Properties属性是否注入成功, injectProperties()方法代码如下 :

        //5.5 注入Properties类型的属性
    @Test
    public void injectProperties() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        School school01 = ioc.getBean("school01", School.class);

        System.out.println("School中的pros属性如下 : ");
        System.out.println(school01.getPros());
    }

运行结果 :

7.List属性注入之通过util命名空间注入 :

方才我们已经见过了如何通过property元素注入List类型的属性,其实是通过list子元素来实现的。
那么,假设现在给出一个 需求: 已知成华大道到二仙桥的路上开着两家书店,它们都卖《生死疲劳》《镜花缘》《湘行散记》《明朝那些事儿》《三体》这几本书,让你在beans.xml中配置这俩个书店对象,你能吗?
你可能会说:哟瞧你这话说的,这不是张飞吃豆芽——小菜一碟么?看我一波张飞穿针——粗中有细,给你整得明明白白,服服帖帖。

于是你就开整了,先新定义一个BookStore的JavaBean类,代码如下 :

package com.cyan.spring.bean;

import java.util.List;

public class BookStore {
    private List<String> bookList;

    public BookStore() {
    }
    public BookStore(List<String> bookList) {
        this.bookList = bookList;
    }

    public List<String> getBookList() {
        return bookList;
    }
    public void setBookList(List<String> bookList) {
        this.bookList = bookList;
    }
}

再去beans.xml文件中配置一波,代码如下 :

    <bean class="com.cyan.spring.bean.BookStore" id="bookStore01">
        <property name="bookList">
            <list>
                <value>生死疲劳</value>
                <value>镜花缘</value>
                <value>湘行散记</value>
                <value>明朝那些事儿</value>
                <value>三体</value>
            </list>
        </property>
    </bean>
    <bean class="com.cyan.spring.bean.BookStore" id="bookStore02">
        <property name="bookList">
            <list>
                <value>生死疲劳</value>
                <value>镜花缘</value>
                <value>湘行散记</value>
                <value>明朝那些事儿</value>
                <value>三体</value>
            </list>
        </property>
    </bean>

你还不尽兴, 继续去测试类中定义了一个单元测试的方法,设法输出bookList属性进行检验, testMySB()方法代码如下 :

    @Test
    public void testMySB() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        BookStore bookStore01 = ioc.getBean("bookStore01", BookStore.class);
        BookStore bookStore02 = ioc.getBean("bookStore02", BookStore.class);

        System.out.println("bookStore01's bookList = " + bookStore01.getBookList());
        System.out.println("bookStore02's bookList = " + bookStore02.getBookList());
    }

运行结果 :

对此,我只能说:“你™是真????B呀”。是的,坦白说你做的针不戳儿。但是呢,假如现在成华大道到二仙桥的路上 又开了5家书店 ,阁下又如何应对呢?
你可能会想:那我再配5个Bean不就完事儿了么,这up????怎么磨磨唧唧的,阴阳怪气,你到底想说啥你说呗,整这么绕一大圈子。对此,我想说:“你再配5个Bean也确实能成事儿,但我说你这么配就慢了,我们不仅要配得对,而且要配得快。

于是便要引出 util命名空间 了。 直接上代码 : (当你使用<util:list>时,IDEA会自动帮你引入util命名空间)

    <util:list id="commonBookList">
        <value>生死疲劳</value>
        <value>镜花缘</value>
        <value>湘行散记</value>
        <value>明朝那些事儿</value>
        <value>三体</value>
    </util:list>

    <bean class="com.cyan.spring.bean.BookStore" id="bookStore01">
        <property name="bookList" ref="commonBookList">
        </property>
    </bean>
    <bean class="com.cyan.spring.bean.BookStore" id="bookStore02">
        <property name="bookList" ref="commonBookList">
        </property>
    </bean>

可以看到,其实就是将大家都有的????放到了<util:list></util:list>元素中,然后在每个BookStore类型的Bean对象中,利用ref引用到<util:list>中。经测试,输出结果是一样的,这里就不再放图了。

8.级联属性注入 :

所谓 “级联属性注入”,其实指的是Spring的IOC容器可以直接为“属性的属性”赋值 ,即当类中的某个属性有自己的属性时,我们希望在配置该类Bean对象时将对象属性和对象属性的属性都注入。

需求 : 定义一个员工类,维护员工id,员工姓名,员工的部门名称三个属性,其中,员工的部门名称通过部门类的deptName属性表示。要求设法实现“级联属性注入”。
首先,我们需要定义员工类和部门类,如下 :
Employee类代码如下 :

package com.cyan.spring.bean;

public class Employee {
    private Integer id;
    private String name;
    private Department department;

    public Employee() {
    }
    public Employee(Integer id, String name, Department department) {
        this.id = id;
        this.name = name;
        this.department = department;
    }

    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;
    }

    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", department=" + department +
                '}';
    }
}

Department类代码如下:

package com.cyan.spring.bean;

public class Department {
    private String deptName;

    public Department() {
    }
    public Department(String deptName) {
        this.deptName = deptName;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

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

接着,在beans.xml文件中配置Employee对象和Department对象。 代码如下 :

    <!-- 配置Employee类对象 -->
    <bean class="com.cyan.spring.bean.Employee" id="employee01">
        <property name="id" value="1"></property>
        <property name="name" value="Cyan"></property>
        <property name="department" ref="department01"></property>
        <!-- [级联属性注入] -->
        <!-- 其实是通过"对象名.属性名"的形式,对属性的属性进行注入操作 -->
        <property name="department.deptName" value="Back-End"></property>
        <!-- 此处,底层实际调用了setDeptName方法 -->
    </bean>
    <!-- 配置Department类对象 -->
    <bean class="com.cyan.spring.bean.Department" id="department01"/>

最后,在测试类StudentBeanByXML中新定义一个单元测试方法,输出配置的Employee对象,查看级联属性注入是否成功。 testCascade()方法代码如下 :

    //PS : 测试级联属性赋值
    @Test
    public void testCascade() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        Employee employee01 = ioc.getBean("employee01", Employee.class);

        System.out.println("employee01 = \n" + employee01);
    }

运行结果 :

可以看到,employee对象的属性department的属性deptName被成功初始化,说明级联属性注入成功。


七、通过静态工厂获取Bean

1.基本介绍 :

通过静态工厂获取Bean ”,本质上还是“ 基于XML方式配置Bean ”;只不过我们 并不直接在配置Bean时就为Bean对象注入属性,而是事先在静态工厂类的static代码块中完成了初始化(用静态的Map容器来存储Student类对象),并提供了一个静态方法用于获取已经初始化好的Student对象 ,然后在beans.xml配置文件中,我们只需要给定一个key,并指定调用静态工厂提供的用于获取Student对象的方法,Spring容器便可以根据该key获取到对应的Student类对象。

注意 :

(1) “通过静态工厂获取Bean”,在配置bean时, class 不再是Student类的全路径,而 是静态工厂类的全路径 .

(2) 除了id和class外,还需要一个 属性factory-method,表示指定一个静态工厂类的用于返回Bean对象的方法 .

(3) 至于 bean元素内部 ,则需要 使用<construcotr-arg value="key"/>标签,说明要获取的对象在静态工厂类中对应的key

2.应用实例 :

上面说了一堆,只是看肯定多少觉得一头雾水,下面我们来个实例感受一下。
首先,up定义一个自己的静态工厂类, CyanStaticFactory类代码如下 :

package com.cyan.spring.factory;

import com.cyan.spring.bean.Student;

import java.util.HashMap;
import java.util.Map;

public class CyanStaticFactory {
    //维护一个静态Map集合,用于保存Student对象
    private static Map<String, Student> studentMap;

    //在静态代码块中初始化Student对象
    static {
        studentMap = new HashMap<>();

        studentMap.put("student01", new Student("Cyan", 21, 450));
        studentMap.put("student02", new Student("Rain", 19, 460));
    }

    //提供一个获取Student对象的静态方法
    public static Student getStudent(String key) {
        return studentMap.get(key);
    }
}

然后在beans.xml文件中完成配置, 代码如下 : (注意看up配置的id,表明最终返回的其实是一个Student类对象)

    <bean class="com.cyan.spring.factory.CyanStaticFactory" id="stu07"
        factory-method="getStudent">
        <constructor-arg value="student02"/>
    </bean>

最后,仍然是在测试类StudentBeanByXML中,定义一个单元测试方法,获取到Student对象,
getBeanByStaticFactory()方法代码如下 : (注意此处getBean方法得到的是Student类型的对象)

    //6.通过静态工厂获取Bean
    @Test
    public void getBeanByStaticFactory() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        Student stu07 = ioc.getBean("stu07", Student.class);

        System.out.println(stu07);
    }

运行结果 :


八、通过实例工厂获取Bean

1.基本介绍 :

通过实例工厂获取Bean ”,和通过静态工厂获取Bean类似,只不过见名知意,我们在 自定义实例工厂类 中通过 非静态 Map容器来保存Student类对象,并在 非静态 代码块中对Map容器进行初始化,并提供一个用于获取Student对象的 非静态 方法。然后 在beans.xml文件 中,除了指定一个用于获取Bean对象的方法,以及给出key外, 必须先指定一个实例工厂对象

回顾一下 代码块 ——

静态代码块随着类的加载而被隐式地调用,最多只能执行一次 而对于非静态代码块,每实例化一次包含该非静态代码块的类,都会执行一次该类中的非静态代码块

结合代码块的内容回顾,我们可以猜到 必须先实例化“实例工厂对象”,以执行其非静态代码块中的内容,完成对非静态Map集合的初始化;然后才能获取到其保存的学生对象

注意 :

(1) “通过实例工厂获取Bean”,在配置bean时, 需要同时配置实例工厂对象和学生对象 .

(2) 属性factory-method,表示指定一个实例工厂类的用于返回Bean对象的方法; 属性factory-bean,表示指定使用一个特定的实例工厂对象返回Bean

(3) bean元素内部 ,仍需要 使用<construcotr-arg value="key"/>标签,说明要获取的对象在实例工厂类中对应的key

2.应用实例 :

首先,up定义一个自己的实例工厂类, CyanInstanceFactory类代码如下 :

package com.cyan.spring.factory;

import com.cyan.spring.bean.Student;

import java.util.HashMap;
import java.util.Map;

public class CyanInstanceFactory {
    private Map<String, Student> studentMap;

    {
        studentMap = new HashMap<>();

        studentMap.put("student03", new Student("Eisen", 22, 437));
        studentMap.put("student04", new Student("Five", 20, 429));
    }

    public Student getStudent(String key) {
        return studentMap.get(key);
    }
}

然后在beans.xml文件中完成配置, 代码如下 :

    <!-- 配置实例工厂对象 -->
    <bean class="com.cyan.spring.factory.CyanInstanceFactory" id="cyanInstanceFactory01"/>
    <!-- 配置学生对象 -->
    <bean id="stu08" factory-bean="cyanInstanceFactory01" factory-method="getStudent">
        <constructor-arg value="student03"/>
    </bean>

最后,仍然是在测试类StudentBeanByXML中,定义一个单元测试方法,获取到Student对象,
getBeanByInstanceFactory()方法代码如下 :

    //7.通过实例工厂获取Bean
    @Test
    public void getBeanByInstanceFactory() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        Student stu08 = ioc.getBean("stu08", Student.class);

        System.out.println(stu08);
    }

运行结果 :


九、通过FactoryBean获取Bean

1.基本介绍 :

通过FactoryBean获取Bean ”,又和上文中通过实例工厂获取Bean类似,都是维护了一个非静态Map容器来保存Bean对象,并在非静态代码块中对Map容器进行初始化,此外, 还需要单独维护一个String类型的key属性 。并且,我们 需要去实现FactoryBean<>接口,并重写接口中的方法

注意 :

(1) “通过FactoryBean获取Bean”,在配置bean时, class为FactoryBean的全类名 .

(2) 通过property子元素为key属性初始化

2.应用实例 :

首先,我们需要定义一个自己的FactoryBean类并实现FactoryBean接口, CyanFactoryBean类代码如下 :

package com.cyan.spring.factory;

import com.cyan.spring.bean.Student;
import org.springframework.beans.factory.FactoryBean;

import java.util.HashMap;
import java.util.Map;

public class CyanFactoryBean implements FactoryBean<Student> {
    private String key;
    private Map<String, Student> studentMap;
    {
        studentMap = new HashMap<>();

        studentMap.put("student05", new Student("Irving", 32, 427));
        studentMap.put("student06", new Student("Rose", 23, 431));
    }

    public void setKey(String key) {
        this.key = key;
    }

    @Override
    public Student getObject() throws Exception {
        return studentMap.get(key);
    }

    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

接着,在beans.xml中配置bean对象, 代码如下 :

    <!-- 配置Student对象,通过FactoryBean获取 -->
    <bean class="com.cyan.spring.factory.CyanFactoryBean" id="stu09">
        <property name="key" value="student05"/>
    </bean>

最后,在StudentBeanByXML测试类中定义一个单元测试方法,测试是否配置成功。 getBeanByFactoryBean()方法代码如下 :

    //8.通过实例工厂获取Bean
    @Test
    public void getBeanByFactoryBean() {
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");

        Student stu09 = ioc.getBean("stu09", Student.class);

        System.out.println(stu09);
    }

运行结果 :


十、关于Bean配置的更多内容和细节

由于“ Spring IOC—基于XML配置和管理Bean ”内容较多,而up写到这里时编辑器已经很卡了????。故打算将 Bean配置信息重用,Bean生命周期,以及Bean后置处理器等内容 单独放一篇文章中。

链接如下 :

待更新--- ????????


十一、总结

  • ????,以上就是Spring系列博文第二小节的全部内容了。
  • 总的来看,Spring 基于XML配置和管理Bean内容很多,我们可以通过多种方式获取Bean或者为Bean注入属性,足以感受到Spring配置和管理Bean的 灵活性 。再来简单回顾一下上文的总述,如下图所示 :

  • 下一节内容——Spring IOC——基于注解配置和管理Bean 感谢阅读!

System.out.println("END-------------------------------------------------");

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring IOC—基于XML配置和管理Bean 万字详解(通俗易懂) 的相关文章

  • 通过 RMI 的服务器,无需注册

    我有一个可以通过 RMI 连接的服务对象 目前我正在这样做 Server Registry r LocateRegistry createRegistry 1234 r bind server UnicastRemoteObject exp
  • iText7:如何获取段落的实际宽度

    在添加到文档之前 我需要知道段落的宽度 以磅为单位 我在这里搜索并找到了 Alexey 关于段落高度的答案 所以我用宽度做了它 但它不起作用 无论段落有多长 始终返回矩形的宽度 我尝试了这段代码 private float getRealP
  • 可以显式删除 lambda 的序列化支持

    As 已经知道 https stackoverflow com a 22808112 2711488很容易添加序列化当目标接口尚未继承时支持 lambda 表达式Serializable 就像 TargetInterface Seriali
  • Lambda 表达式更慢?

    我有下面这段代码 PriorityQueue
  • JUnit 测试方法无法返回值

    为什么 JUnit 测试方法无法返回值 文档 https junit org junit5 docs current user guide writing tests classes and methods说 强调我的 测试方法和生命周期方
  • 我如何通过代码在 Anylogic 中创建路径空间标记元素

    我在anyloigic方面完全是菜鸟 现在我正在尝试通过代码创建简单的网络 具有两个点节点的网络 以及链接这些节点的路径 遇到一些问题 当我运行模型时 控制台显示 使用初始化 方法 但我已经知道 初始化方法在较低版本中已被弃用 我使用的是8
  • Tomcat:具有强密码的 TLSv1.2 不起作用

    我安装了Tomcat 7 配置了对 TLSv1 2 的支持在端口 8443 上 我的连接器配置 协议 org apache coyote http11 Http11NioProtocol SSLEnabled true 方案 https 安
  • 关于java中同步的问题;何时/如何/到什么程度

    我正在开发我的第一个多线程程序 并在同步的几个方面陷入困境 我已经浏览了 oracle sun 主页上的多线程教程 以及这里的一些关于 SO 的问题 所以我相信我知道什么是同步 然而 正如我提到的 有几个方面我不太确定如何弄清楚 我以明确问
  • Spring的@PreDestroy导致随机记录而不记录

    我正在使用 Spring 并且在终止时我让 PreDestroy 清理 bean 我不明白为什么日志记录有时会成功 而有时会失败 Using Log4j2 Logger log LogManager getLogger MyClass cl
  • 如何在 ASP.NET MVC 中将 XML 文件发送到客户端

    在 ASP NET MVC 中 我有一个数据库表 我想在某个视图页面上有一个按钮 如果某个用户单击该按钮 我的应用程序将生成包含数据库中所有行的 XML 文件 然后 应将包含 XML 的文件发送到客户端 以便用户看到下载弹出窗口 同样 我希
  • 改造添加带有令牌和 ID 的标头

    我在获取经过身份验证的用户时遇到问题 在此之前我得到了令牌和用户 ID 现在我需要使用访问令牌和 ID 从服务器获取用户 我有标题格式 https i stack imgur com OQ87Y png 现在我尝试使用拦截器添加带有用户令牌
  • 如何自定义 JFrame 上的标题栏?

    我想在我的 Java Swing 桌面应用程序中拥有一个自定义的标题栏 最好的方法是什么 我可以通过在 JFrame 的构造函数中使用以下代码来使用 Swing 标题栏 this setUndecorated true this getRo
  • Spring-data-cassandra:创建名称为“sessionFactory”的 bean 时出错,并且无法解析对 bean“cassandraTemplate”的引用

    我有一个 springboot 应用程序 在其中连接到 cassandra DB 我的 pom xml parent gt
  • 将 try catch finally 块放入另一个 finally 块中

    try catch finally try catch finally 上面的代码好不好 是的 你可以这样做 实际上 在处理想要正确关闭的流时 您甚至需要这样做 InputStream in try catch finally try in
  • 通过API更新Twitter背景

    我在通过 Twitter 的 API 更新背景时遇到了一些问题 target url http www google com logos 11th birthday gif ch curl init curl setopt ch CURLO
  • 用于验证 InetSocketAddresses 的正则表达式(ipv4/v6 + 端口地址)

    我在寻找testedipv4 和 ipv6 的正则表达式InetSocket地址 http download oracle com javase 6 docs api java net InetSocketAddress html toSt
  • 为什么我们在同一台服务器上使用多个应用程序服务器实例

    我想这是有充分理由的 但我不明白为什么有时我们会在同一物理服务器上放置例如 5 个具有相同 Web 应用程序的实例 这与多处理器架构的优化有关吗 JVM 或其他允许的最大内存限制 嗯 过了很长一段时间我又看到这个问题了 一台机器上的多个 J
  • SWIG C 函数指针和 JAVA

    我有一些 C 代码 其中一个方法有一个函数指针作为参数 我正在尝试在我的 Android 应用程序中使用 C 代码 我决定使用 SWIG 来完成生成我需要的 java 文件的所有工作 一切都适用于常规函数 没有函数指针作为参数的函数 但我不
  • 使用基于Optional内容的流

    我从不受我控制的服务获取可能为空的地图 并且想要处理它 比方说 过滤 映射并减少到我需要的单个元素 问题 是否有从Optional到Stream的 链接 我尝试过 除其他外 return Optional ofNullable getMap
  • JAXB 枚举字段未序列化

    我有以下课程 package dictionary import java io Serializable import java util Objects import javax xml bind annotation XmlEleme

随机推荐

  • WebGL笔记:矩阵平移的数学原理和实现

    矩阵平移的数学原理 让向量OA位移 x方向 tx y方向 ty z方向 tz 最终得到向量OB 矩阵平移的应用 再比如我要让顶点的x移动0 1 y移动0 2 z移动0 3 1 顶点着色器核心代码
  • 有效表达观点的艺术

    有效表达观点的艺术 在人际交往中 有效地表达自己的观点是建立良好关系和实现有效沟通的关键 然而 这并不总是易如反掌 有时候 我们可能会遇到表达困难 或者我们的观点可能被误解 本文将探讨如何有效地表达观点 以及掌握说话的艺术的重要性 首先 清
  • 人工智能:开启未来商业新篇章

    人工智能 开启未来商业新篇章 随着科技的快速发展 人工智能 AI 在商业领域的应用越来越广泛 成为企业把握未来商业机遇的重要方向 本文将探讨人工智能如何重塑商业格局 为企业提供新的增长点 以及企业如何抓住AI的商业契机 一 AI重塑商业格局
  • 机器人学英语

    我的prompt i want to you act as an english language teacher asistant to help me study english you could teach me in such a
  • 详解Hotspot的经典7种垃圾收集器原理特点与组合搭配

    详解Hotspot的经典7种垃圾收集器原理特点与组合搭配 HotSpot共有7种垃圾收集器 3个新生代垃圾收集器 3个老年代垃圾收集器 以及G1 一共构成7种可供选择的垃圾收集器组合 新生代与老年代垃圾收集器之间形成6种组合 每个新生代垃圾
  • 在深圳月入一万的很丢人吗

    在深圳 月入一万的收入是否丢人 这是一个很主观的问题 因为每个人的生活需求和价值观不同 从经济学的角度来看 深圳作为中国的经济特区和一线城市 其生活成本相对较高 从这个角度看 月入一万的收入在某种程度上可能不足以满足一些人的生活需求 根据最
  • 给自己泡了一壶茶

    清晨 当第一缕阳光透过窗户照亮了房间 我慵懒地爬起床 开始享受新的一天 我泡了一壶早茶 浅浅的茶香立刻弥漫在空气中 让我感到宁静而放松 我坐在窗边 静静地看着窗外的世界 清晨的街道上 行人和车辆都还不多 显得格外的宁静 微风吹过树叶 带来阵
  • 拍图识字软件哪个好用?这些好用的软件推荐给你们

    在快节奏的现代生活中 你可能会遇到需要从图片中获取文字信息的情况 无论是读书 工作还是生活中 有时候会需要从图片中提取文字 当你收到了一份手写的便签或菜单 上面的字迹可能很模糊 或者你需要在没有文字的地方快速获取信息 这时 你可能会想 如果
  • 详解十大经典排序算法(四):希尔排序(Shell Sort)

    算法原理 希尔排序是一种基于插入排序的排序算法 也被称为缩小增量排序 它通过将待排序的序列分割成若干个子序列 对每个子序列进行插入排序 然后逐步缩小增量 最终使整个序列有序 算法描述 希尔排序 Shell Sort 是一种基于插入排序的算法
  • 使用tensorrt加速深度学习模型推断

    使用tensorrt加速深度学习模型推断 1 import以及数据加载 构建engine函数 2 导入官方模型及CIFAR100数据集 3 不采用tensort的推断时间 4 采用tensort加速 使用tensorrt 库 4 1 导出o
  • 京东商品详情接口在电商行业中的重要性及实时数据获取实现

    一 引言 随着电子商务的快速发展 商品信息的准确性和实时性对于电商行业的运营至关重要 京东作为中国最大的电商平台之一 其商品详情接口在电商行业中扮演着重要的角色 本文将深入探讨京东商品详情接口的重要性 并介绍如何通过API实现实时数据获取
  • 城市化人群隔离悖论

    城市是人群大规模聚集的过程 表面上似乎会提高人与人之间相互接触和交往的效率 但不可思议的是 美国学者的研究发现 城市越大 人和人之间相互隔离越严重 这显然是违背直觉的现象 反直觉往往意味着新发现 就给这种现象命名为城市化人群隔离悖论吧 这是
  • 未来已来,AI与情报分析,是黑暗或光明?

    这篇文章有点像一个实验 在乔治城大学 Georgetown University 举行的 负责任的人工智能和情报 Responsible AI and Intelligence 会议上 ChatGPT被要求撰写一篇文章 陈述关于我将如何评估
  • 外卖小程序需要多大云服务器?

    外卖小程序是一种基于互联网技术实现的餐饮电商平台 具有实时配送 快速响应和跨地区订餐等特点 为保证外卖小程序在高并发和业务繁忙的情况下能够稳定运行 需要具备一定的云服务器配置 具体也有考虑公司业务规模大小 用户量 原文地址 外卖小程序需要多
  • 服务器2g内存个人使用可以吗?

    对于个人日常使用而言 云服务器2G内存是足够的 一般来说 对于普通用户而言 使用云服务器主要是用来搭建网站 存储文件和数据备份等基本操作 虽然这些操作看似比较简单 但是实际上还是需要一定的计算资源才能完成的 原文地址 服务器2g个人使用可以
  • 淘宝商品详情接口在电商运营中的应用实例

    一 背景 某电商企业A在运营过程中 发现手动更新商品信息效率低下 且容易出现信息不一致的情况 为了解决这个问题 企业A决定采用淘宝商品详情接口 实现商品信息的自动获取和更新 二 目标 通过集成淘宝商品详情接口 企业A希望实现以下目标 自动获
  • Latex公式中矩阵的方括号和圆括号表示方法

    一 背景 在使用Latex写论文时 不可避免的涉及到矩阵公式 有的期刊要求矩阵用方括号 有的期刊要求矩阵用圆括号 因此 特记录一下Latex源码在两种表示方法上的区别 以及数组和方程组的扩展 二 矩阵的方括号表示 首先所有的矩阵肯定都是在标
  • Python机器学习、深度学习入门丨气象常用科学计算库、气象海洋常用可视化库、爬虫和气象海洋数据、气象海洋常用插值方法、EOF统计分析、WRF模式后处理等

    目录 专题一 Python软件的安装及入门 专题二 气象常用科学计算库 专题三 气象海洋常用可视化库 专题四 爬虫和气象海洋数据 专题五 气象海洋常用插值方法 专题六 机器学习基础理论和实操 专题七 机器学习的应用实例 专题八 深度学习基础
  • 糟了,数据库崩了,又好像没崩

    前言 2023 年某一天周末 新手程序员小明因为领导安排的一个活来到公司加班 小明三下五除二 按照领导要求写了一个跑批的数据落库任务在测试环境执行 突然间公司停电了 小明大惊 糟了 MySQL 还在跑任务 会不会因为突然断电 导致数据库崩了
  • Spring IOC—基于XML配置和管理Bean 万字详解(通俗易懂)

    目录 一 前言 二 通过类型来获取Bean 0 总述 重要 1 基本介绍 2 应用实例 三 通过指定构造器为Bean注入属性 1 基本介绍 2 应用实例 四 通过p命名空间为Bean注入属性 1 基本介绍 2 应用实例 五 通过ref引用实