Spring入门系列:篇3——再探IOC

Posted thinmoon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring入门系列:篇3——再探IOC相关的知识,希望对你有一定的参考价值。

前言

在上一篇SpringIOC入门中我们介绍了SpringIOC的基本使用,现在我们更加深入的学习一下SpringIOC。

一、Bean的相关配置

在前文我们简单了解了bean的使用,下面我们再来具体介绍一下bean。

1.名称与标识

  • id: 使用了约束中的唯一约束。里面不能出现特殊字符的
  • name: 没有使用约束中的唯一约束。里面可以出现特殊字符。

id我们前文有提到过,就是指定我们需要管理的类方便我们进行获取对象。name作用也是一样,只不过id具有唯一性,name不具有唯一性。我们一般都是使用id不会去使用name。

2.设置对象的生命周期

我们还可以通过bean属性来设置对象的生命周期主要有以下两个属性:

  • init-method:Bean被初始化的时候执行的方法
  • destroy-method:Bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)

在前文我们说过对象是在ApplicationContext创建时就创建好了,所以init-method会在ApplicationContext创建完就执行,当ApplicationContext工厂关闭时就会执行destroy-method(手动关闭)。接下来我们举个例子:

首先创建一个Person类,并将Person类交由Spring管理:

public class Person {
    public void init() {
        System.out.println("person---init");
    }

    public void destroy() {
        System.out.println("person---destroy");
    }
}
<?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="person" class="icu.thinmoon.demo2.Person" init-method="init" destroy-method="destroy"></bean>

</beans>

接着编写测试类运行一下看看结果:

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

public class PersonTest {
    @Test
    public void test() {
        ApplicationContext applicationContext
                = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("--------------");
    }
}

运行结果:

person---init
--------------

可以看到,在applicationContext初始化完成便调用了person类的init方法。当我们手动关闭工厂的时候,工厂内的所有对象都会被销毁可以看如下代码:

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

public class PersonTest {
    @Test
    public void test() {
        ClassPathXmlApplicationContext applicationContext
                = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("--------------");
        applicationContext.close();
    }
}

运行结果:

person---init
--------------
person---destroy

需要注意的是:

ClassPathXmlApplicationContext applicationContext
                = new ClassPathXmlApplicationContext("applicationContext.xml");

我们在这使用的是ClassPathXmlApplicationContext 子类,父类接口没有close方法。

3.Bean的作用范围scope

我们可以通过配置scope属性来配置bean的作用范围,其具体的值有以下几种:

意义
singleton 默认采用此方式,Spring会采用单例模式创建这个对象。工厂关闭自动销毁
prototype 多例模式。工厂关闭对象不会自动销毁,依旧需要垃圾回收
request 应用在web项目中,Spring创建这个类以后,将这个对象存入到request范围中。
session 应用在web项目中,Spring创建这个类以后,将这个对象存入到session范围中
globalsession 应用在web项目中,必须在porlet(基于Java的Web组件,子域名)环境下使用。但是如果没有这种环境,相对于session。

我们需要重点关注spring默认是采用单例的方式创建对象,若需改成多例我们需要将scope配置成prototype

4.工厂实例化的方式

工厂实例化的方式是指Spring在帮我们生成对象时我们可以指定Spring如何去生成对象,主要有以下三种实现方法:

  • 无参构造:这是默认方法,即Spring调用该类的默认无参构造函数去帮我们创建对象

  • 静态工厂实例化:我们可以利用factory-method属性指定一个静态方法帮助我们生产对象

    public class User {
        public static User create() {
            System.out.println("----create user----");
            return new User();
        }
    }
    
    <bean id="user" class="icu.thinmoon.demo3.User" factory-method="create"></bean>
    
  • 实例工厂实例化:实例工厂实例化是指在利用已有的bean来创建对象

     <bean id="user" class="icu.thinmoon.demo3.User" factory-method="create"></bean>
     <bean id="user2" class="icu.thinmoon.demo3.User" factory-bean="user"></bean>
    

综上,我们可以通过上述3种方式来设置Spring实例化的方式,在实际使用中一般使用第一种方式比较多。

二、再探属性注入

上一篇文章中我们提到了set方法属性注入方式,其实属性注入方式还有很多种我们来挨个学习一下:

1.set方法属性注入

前文有提到set方法属性注入,在这我们加上引用类型属性注入方式:

Student:

public class Student {
    String name;
    Integer id;
    Dog dog;

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

    public void setId(Integer id) {
        this.id = id;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }
}

Dog:

public class Dog {
    String name;

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

配置applicationContext.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="dog" class="icu.thinmoon.demo4.Dog">
        <property name="name" value="旺财"/>
    </bean>

    <bean id="student" class="icu.thinmoon.demo4.Student">
        <property name="name" value="小明"/>
        <property name="id" value="001"/>
        <property name="dog" ref="dog"/>
    </bean>

</beans>

使用测试类测试一下:

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

public class StudentTest {
    @Test
    public void test() {
        ApplicationContext applicationContext
                = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = (Student) applicationContext.getBean("student");
        System.out.println(student.id);
        System.out.println(student.name);
    }
}

测试结果:

1
小明

可以看到,引用类型的属性注入方式与基本类型相似,只不过我们在这使用的是ref属性,表示的是应用工厂内的某个bean,所以我们需要将引用的对象也加入工厂。

 <property name="dog" ref="dog"/>

2.构造方法属性注入

使用构造方法属性注入肯定需要我们提供构造方法,使用constructor-arg便能完成,修改上面代码如下:

Student:

public class Student {
    String name;
    Integer id;
    Dog dog;

    public Student(String name, Integer id, Dog dog) {
        this.name = name;
        this.id = id;
        this.dog = dog;
    }
}

applicationContext.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="dog" class="icu.thinmoon.demo4.Dog">
        <property name="name" value="旺财"/>
    </bean>

    <bean id="student" class="icu.thinmoon.demo4.Student">
        <constructor-arg name="name" value="小明"/>
        <constructor-arg name="id" value="001"/>
        <constructor-arg name="dog" ref="dog"/>
    </bean>

</beans>

测试类及测试结果同上。

3.p名称空间属性注入

p名称空间属性注入其实就是set方法属性注入的一种简化写法,使用p名称空间属性注入我们首先要在配置文件中加上下面这条代码:

xmlns:p="http://www.springframework.org/schema/p"

使用p名称空间后的配置文件如下:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dog" class="icu.thinmoon.demo4.Dog" p:name="旺财"/>

    <bean id="student" class="icu.thinmoon.demo4.Student" p:name="小明" p:id="001" p:dog-ref="dog"/>
        

</beans>

以上配置文件和set属性注入执行效果完全一致。

4.spEL表达式属性注入

spEL表达式也是一种简写方式,我们可以通过spEL表达式直接引用对象甚至对象的属性,比如说:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dog" class="icu.thinmoon.demo4.Dog">
        <property name="name" value="旺财"/>
    </bean>

    <bean id="student" class="icu.thinmoon.demo4.Student">
        <property name="name" value="#{‘小明’}"/>
        <property name="id" value="#{1}"/>
        <property name="dog" value="#{dog}"/>
    </bean>

</beans>

我们可以通过#{}的形式进行注入,字符串需要加上单引号。我们还可以在括号内调用对象属性、方法等,类似这样:

<property name="name" value="#{dog.name}"/>

这种方式开发过程一般不使用,了解即可。

5.集合属性注入

修改Student如下:

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

public class Student {

    String[] array;
    List<String> list;
    Set<String> set;
    Map<Integer, String> map;

    public void setArray(String[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

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

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

applicationContext.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="student" class="icu.thinmoon.demo4.Student">
        <!--数组注入-->
        <property name="array">
            <list>
                <value>小明</value>
                <value>小红</value>
                <value>小红</value>
                <value>小红</value>
            </list>
        </property>

        <!--List注入-->
        <property name="list">
            <list>
                <value>小明</value>
                <value>小红</value>
                <value>小红</value>
                <value>小红</value>
            </list>
        </property>

        <!--set注入-->
        <property name="set">
            <set>
                <value>小明</value>
                <value>小红</value>
                <value>小红</value>
                <value>小红</value>
            </set>
        </property>

        <!--map-->
        <property name="map">
            <map>
                <entry key="001" value="abc"/>
                <entry key="002" value="def"/>
                <entry key="003" value="ghj"/>
            </map>
        </property>


    </bean>

</beans>

附录:分模块配置

我们在开发中每个人都可以写一个自己的配置文件,然后在主配置文件中进行引入即可:

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

    <!--id: 为自己取得名称  class:具体实现类的全路径-->
    <bean id="userDao" class="icu.thinmoon.demo1.UserDaomysqlImpl">
        <!--
        name: 属性名称
        value: 属性的值
        注意:需要提供set方法
        -->
        <property name="name" value="thinmoon"/>
    </bean>

    <!--导入另外的配置文件-->
    <import resource="applicationContext2.xml"/>

</beans>

applicationContext2.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="user" class="icu.thinmoon.demo3.User" factory-method="create"></bean>
    <bean id="user2" class="icu.thinmoon.demo3.User" factory-bean="user"></bean>

</beans>

以上是关于Spring入门系列:篇3——再探IOC的主要内容,如果未能解决你的问题,请参考以下文章

《Java从入门到放弃》入门篇:spring中IOC的注入姿势

Java之Spring入门到精通IDEA版Spring的IoC和DI(一篇文章精通系列)

Java之Spring入门到精通IDEA版Spring的IoC和DI(一篇文章精通系列)

Spring入门篇——第2章 Spring IOC容器

spring入门篇2 --- IOC设计思想

Spring 从入门到精通系列框架教程(这个掌握了考试就不怕了)❤️