Spring之IOC

发布时间:2024年01月01日

1 IOC介绍

IOC(Inversion Of Control),即控制反转,是一种能够指导我们设计出松耦合、高可扩展应用程序的设计思想。

  • 反转的是什么
    正常情况下,我们会主动创建对象,然后再使用,对象的生命周期有我们通过编码控制。
    而IOC思想是将对象的创建及对对象之间关系的维护交由第三方容器实现,反转的正式这个方面的内容。
  • 实现方式
    DI(Dependency Injection),即依赖注入,是实现IOC的一种方式,指Spring创建对象的过程中,将对象依赖属性通过配置进行注入。
    IOC 就是一种控制反转的思想, 而 DI 是对IoC的一种具体实现。

2 Spring

Spring框架提供了IOC容器相关的实现方式,Spring通过IOC容器管理Bean及Bean之间的依赖关系,其实现方式包括如下两种:

  • BeanFactory
    这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。
  • ApplicationContext
    BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。
类型名说明
ClassPathXmlApplicationContext通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
FileSystemXmlApplicationContext通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象
  • Spring管理bean的两种方式:xml方式和注解

3 Spring基于xml管理bean

3.1 基础环境搭建

创建子模块giser-java-spring6-01,并引入配置文件beans.xml、log4j2.xml,添加如下依赖:

<dependencies>
	<!-- Spring依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.1.1</version>
    </dependency>

    <!--junit5测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.10.1</version>
    </dependency>

    <!--log4j2的依赖-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.19.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j2-impl</artifactId>
        <version>2.19.0</version>
    </dependency>
</dependencies>

创建实体类:

public class HelloWorld {
    public HelloWorld(){
        System.out.println("constructor execute...");
    }
    public void sayHello(){
        System.out.println("hello world!");
    }
}

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

    <!--
        向Spring容器中注册bean信息
        id: 注册的bean的id,作为bean的唯一标识
        class: 注册bean的类全路径,用户创建bean对象
    -->
    <bean id="helloWorld" class="com.giser.spring6.HelloWorld"></bean>

</beans>

log4j配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <loggers>
        <!--
            level指定日志级别,从低到高的优先级:
                TRACE < DEBUG < INFO < WARN < ERROR < FATAL
                trace:追踪,是最低的日志级别,相当于追踪程序的执行
                debug:调试,一般在开发中,都将其设置为最低的日志级别
                info:信息,输出重要的信息,使用较多
                warn:警告,输出警告的信息
                error:错误,输出错误信息
                fatal:严重错误
        -->
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
            <appender-ref ref="RollingFile"/>
            <appender-ref ref="log"/>
        </root>
    </loggers>

    <appenders>
        <!--输出日志信息到控制台-->
        <console name="spring6log" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        </console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
        <File name="log" fileName="d:/spring6_log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>

        <!-- 这个会打印出所有的信息,
            每次大小超过size,
            则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,
            作为存档-->
        <RollingFile name="RollingFile" fileName="d:/spring6_log/app.log"
                     filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
            <SizeBasedTriggeringPolicy size="50MB"/>
            <!-- DefaultRolloverStrategy属性如不设置,
            则默认为最多同一文件夹下7个文件,这里设置了20 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
    </appenders>
</configuration>
3.2 获取bean的三种方式
public class HelloWorldTest {
    private Logger logger = LoggerFactory.getLogger(HelloWorldTest.class);
    @Test
    public void testSpringBean() {
        // 读取配置信息
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    }
}
  • 根据bean标签的id获取
// 根据id获取bean
HelloWorld bean1 = (HelloWorld) applicationContext.getBean("helloWorld");
  • 根据bean的类型获取
// 根据bean的类型获取bean,此时要求此类型的bean只能存在一个,否则会抛异常
HelloWorld bean2 = applicationContext.getBean(HelloWorld.class);
  • 根据id和类型获取bean
HelloWorld bean3 = applicationContext.getBean("helloWorld", HelloWorld.class);
3.3 DI之setter注入

实体:

public class User {
    private String userName;
    private Integer userAge;
    // 无参构造函数
    // 全参构造函数
    // getter setter toString
}

beans-di.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">
    <!--
        set方法注入
    -->
    <bean id="user" class="com.giser.spring6.entity.User">
        <property name="userName" value="张三"/>
        <property name="userAge" value="13" />
    </bean>

</beans>

测试

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-di.xml");
        User user = applicationContext.getBean("user", User.class);
3.4 DI之构造器注入
    <!--
        constructor注入
        name: 指定参数名
        value: 参数值
        index属性:指定参数所在位置的索引(从0开始)
    -->
    <bean id="user1" class="com.giser.spring6.entity.User">
        <constructor-arg name="userName" value="张三" />
        <constructor-arg name="userAge" value="23" />
    </bean>

测试

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-di.xml");
        User user1 = applicationContext.getBean("user1", User.class);
3.5 DI之特殊值注入

    <!--
        特殊值处理:字面量赋值
    -->
    <!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
    <bean id="user2" class="com.giser.spring6.entity.User">
        <property name="userName" value="张三"/>
        <property name="userAge" value="13" />
    </bean>

    <!--
        特殊值处理:null值
    -->
    <bean id="user3" class="com.giser.spring6.entity.User">
        <property name="userName">
            <null />
        </property>
        <property name="userAge" value="13" />
    </bean>

    <!--
        特殊值处理:xml实体
    -->
    <bean id="user4" class="com.giser.spring6.entity.User">
        <property name="userName" value="a &lt; b"></property>
        <property name="userAge" value="13" />
    </bean>

    <!--
        特殊值处理:CDATA节
            CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据;
            XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析;
            所以CDATA节中写什么符号都随意;
    -->
    <bean id="user5" class="com.giser.spring6.entity.User">
        <property name="userName">
            <value><![CDATA[A<=B]]></value>
        </property>
        <property name="userAge" value="13" />
    </bean>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-di.xml");
User user2 = applicationContext.getBean("user2", User.class);
User user3 = applicationContext.getBean("user3", User.class);
User user4 = applicationContext.getBean("user4", User.class);
User user5 = applicationContext.getBean("user5", User.class);
logger.info("特殊值处理-字面量赋值:{}", user2);
logger.info("特殊值处理-null值:{}", user3);
logger.info("特殊值处理-xml实体:{}", user4);
logger.info("特殊值处理-CDATA节:{}", user5);
3.6 DI之对象类型赋值

包括三种方式:引入外部bean、使用内部bean、级联属性赋值。
实体:

public class Dept {
    private String deptName;
    // getter setter toString
}
public class Emp {

    private String empName;
    private Integer empAge;
    private Dept dept;
    // getter setter toString
}

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
    -->
    <bean id="dept" class="com.giser.spring6.iocpojo.Dept">
        <property name="deptName" value="产品研发部" />
    </bean>

    <bean id="emp1" class="com.giser.spring6.iocpojo.Emp">
        <property name="empName" value="小明" />
        <property name="empAge" value="32" />
        <!-- 对象类型属性,通过ref引入外部bean -->
        <property name="dept" ref="dept" />
    </bean>

    <!--
        对象类型赋值方式二:使用内部bean
    -->
    <bean id="emp2" class="com.giser.spring6.iocpojo.Emp">
        <property name="empName" value="小明" />
        <property name="empAge" value="32" />
        <!-- 对象类型属性,使用内部bean -->
        <property name="dept" >
            <!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
            <bean class="com.giser.spring6.iocpojo.Dept">
                <property name="deptName" value="董事会" />
            </bean>
        </property>
    </bean>

    <!--
        对象类型赋值方式三:级联属性赋值
    -->
    <bean id="dept3" class="com.giser.spring6.iocpojo.Dept">
        <property name="deptName" value="产品研发部" />
    </bean>
    <bean id="emp3" class="com.giser.spring6.iocpojo.Emp">
        <property name="empName" value="小明" />
        <property name="empAge" value="32" />
        <!-- 对象类型属性,级联属性赋值 -->
        <property name="dept" ref="dept3" />
        <property name="dept.deptName" value="中央办公室" />
    </bean>

</beans>

测试:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-obj-di.xml");
Emp emp = applicationContext.getBean("emp3", Emp.class);
logger.info("对象类型属性赋值:{}", emp);
3.7 DI之数组类型属性赋值
public class Student {

    private String stuName;
    private String[] hobbyArr;

    // 无参构造函数
    // 全参构造函数
    // getter setter toString
}
<?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.giser.spring6.iocarray.Student">
        <property name="stuName" value="张三" />
        <property name="hobbyArr">
            <array>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>敲代码</value>
            </array>
        </property>
    </bean>

</beans>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-arr-di.xml");
Student stu = applicationContext.getBean("stu", Student.class);
logger.info("数组类型属性赋值:{}", stu);
3.8 DI之List类型属性赋值
public class Cls {
    private List<Stu> stuList;
    private String clsName;

    // 无参构造函数
    // 全参构造函数
    // getter setter toString
}
public class Stu {
    private String stuName;
    private List<String> hobbyList;

    // 无参构造函数
    // 全参构造函数
    // getter setter toString
}
<?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.giser.spring6.ioclist.Stu">
        <property name="stuName" value="张三" />
        <property name="hobbyList">
            <list>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>敲代码</value>
            </list>
        </property>
    </bean>

    <bean id="stu2" class="com.giser.spring6.ioclist.Stu">
        <property name="stuName" value="李四" />
        <property name="hobbyList">
            <list>
                <value>烧烤</value>
                <value>炸鸡</value>
                <value>胡辣汤</value>
            </list>
        </property>
    </bean>

    <!--
    数组类型属性赋值: 引用类型
    -->
    <bean id="cls" class="com.giser.spring6.ioclist.Cls">
        <property name="clsName" value="中一班" />
        <property name="stuList">
            <list>
                <ref bean="stu" />
                <ref bean="stu2" />
            </list>
        </property>
    </bean>

</beans>
private Logger logger = LoggerFactory.getLogger(SpringListDITest.class);

@Test
public void testSpecialVal(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-list-di.xml");
    Stu stu = applicationContext.getBean("stu", Stu.class);
    logger.info("List集合类型属性赋值:{}", stu);
}

@Test
public void testSpecialVal2(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-list-di.xml");
    Cls cls = applicationContext.getBean("cls", Cls.class);
    logger.info("List集合类型属性赋值:{}", cls);
}
3.9 DI之Map类型属性赋值
public class Family {

    private String familyName;
    private Map<String, Mem> memMap;

    // 无参构造函数
    // 全参构造函数
    // getter setter toString
}
public class Mem {
    private String memName;
    private Integer memAge;    
    // 无参构造函数
    // 全参构造函数
    // getter setter toString
}
<?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="mem1" class="com.giser.spring6.iocmap.Mem">
        <property name="memAge" value="11" />
        <property name="memName" value="小李" />
    </bean>

    <bean id="mem2" class="com.giser.spring6.iocmap.Mem">
        <property name="memAge" value="22" />
        <property name="memName" value="小张"/>
    </bean>

    <!--
    数组类型属性赋值: 引用类型
    -->
    <bean id="family" class="com.giser.spring6.iocmap.Family">
        <property name="familyName" value="梦想家" />
        <property name="memMap">
            <map>
                <entry>
                    <key>
                        <value>1001</value>
                    </key>
                    <ref bean="mem1"/>
                </entry>
                <entry>
                    <key>
                        <value>1002</value>
                    </key>
                    <ref bean="mem2"/>
                </entry>
            </map>
        </property>
    </bean>

    <bean id="family2" class="com.giser.spring6.iocmap.Family">
        <property name="familyName" value="梦想家" />
        <property name="memMap">
            <map>
                <entry value-ref="mem1">
                    <key>
                        <value>1001</value>
                    </key>
                </entry>
                <entry value-ref="mem2">
                    <key>
                        <value>1002</value>
                    </key>
                </entry>
            </map>
        </property>
    </bean>

</beans>
public class SpringMapDITest {

    private Logger logger = LoggerFactory.getLogger(SpringMapDITest.class);

    @Test
    public void testSpecialVal(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-map-di.xml");
        Family family = applicationContext.getBean("family", Family.class);
        logger.info("对象类型属性赋值:{}", family);
        Family family2 = applicationContext.getBean("family2", Family.class);
        logger.info("对象类型属性赋值:{}", family2);
    }

}
3.10 DI之引用集合类型注入
public class Family {

    private String familyName;
    private Map<String, Mem> memMap;

    private List<Mem> memList;
    // 无参构造函数
    // 全参构造函数
    // getter setter toString
public class Mem {
    private String memName;
    private Integer memAge;
    // 无参构造函数
    // 全参构造函数
    // getter setter toString
<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="family" class="com.giser.spring6.iocref.Family">
        <property name="familyName" value="一家人" />
        <!--
            引用集合类型的bean
        -->
        <property name="memMap" ref="memMap" />
        <property name="memList" ref="memList" />
    </bean>

    <util:list id="memList">
        <ref bean="mem1" />
        <ref bean="mem2" />
        <ref bean="mem3" />
    </util:list>

    <util:map id="memMap">
        <entry>
            <key>
                <value>1001</value>
            </key>
            <ref bean="mem1"/>
        </entry>
        <entry>
            <key>
                <value>1002</value>
            </key>
            <ref bean="mem2"/>
        </entry>
    </util:map>

    <bean id="mem1" class="com.giser.spring6.iocref.Mem">
        <property name="memAge" value="11" />
        <property name="memName" value="小李" />
    </bean>
    <bean id="mem2" class="com.giser.spring6.iocref.Mem">
        <property name="memAge" value="22" />
        <property name="memName" value="小张"/>
    </bean>
    <bean id="mem3" class="com.giser.spring6.iocref.Mem">
        <property name="memAge" value="33" />
        <property name="memName" value="小王"/>
    </bean>
</beans>
3.11 DI之通过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:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        p标签使用
    -->
    <bean id="family" class="com.giser.spring6.iocref.Family"
        p:familyName="一家人"
          p:memMap-ref="memMap"
          p:memList-ref="memList"
    >
    </bean>

    <util:list id="memList">
        <ref bean="mem1" />
        <ref bean="mem2" />
        <ref bean="mem3" />
    </util:list>

    <util:map id="memMap">
        <entry>
            <key>
                <value>1001</value>
            </key>
            <ref bean="mem1"/>
        </entry>
        <entry>
            <key>
                <value>1002</value>
            </key>
            <ref bean="mem2"/>
        </entry>
    </util:map>

    <bean id="mem1" class="com.giser.spring6.iocref.Mem">
        <property name="memAge" value="11" />
        <property name="memName" value="小李" />
    </bean>
    <bean id="mem2" class="com.giser.spring6.iocref.Mem">
        <property name="memAge" value="22" />
        <property name="memName" value="小张"/>
    </bean>
    <bean id="mem3" class="com.giser.spring6.iocref.Mem">
        <property name="memAge" value="33" />
        <property name="memName" value="小王"/>
    </bean>
</beans>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-p-di.xml");
Family family = applicationContext.getBean("family", Family.class);
logger.info("p标签属性赋值:{}", family);
3.12 DI之引入外部属性文件

jdbc.properties

jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver

beans-jdbc.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/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        引入外部属性文件
        注意:在使用 context:property-placeholder 元素加载外包配置文件功能前,首先需要在 XML 配置的一级标签 <beans> 中添加 context 相关的约束。
    -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="password" value="${jdbc.password}" />
        <property name="username" value="${jdbc.user}" />
        <property name="driverClassName" value="${jdbc.driver}" />
    </bean>
</beans>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-ds.xml");
DruidDataSource druidDataSource = applicationContext.getBean(DruidDataSource.class);
logger.info("数据库对象:{}", druidDataSource);
3.13 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">

    <!--
        创建对象,并设置作用域范围:
        默认为单例singleton,bean在IOC容器中只有一个实例,IOC容器初始化时创建对象;
        可通过scope属性设置为多实例对象[scope为prototype],bean在IOC容器中可以有多个实例,getBean()时创建对象
    -->
    <bean id="apple" class="com.giser.spring6.scope.Apple" scope="prototype" />

</beans>
public class SpringScopeTest {

    private final Logger logger = LoggerFactory.getLogger(SpringScopeTest.class);

    /**
     * scope=singleton时:
     * [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'apple'
     * [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@436390f4
     * [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@436390f4
     *
     * scope="prototype"时:
     * [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [beans-scope.xml]
     * [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@733037
     * [main] INFO spring6.SpringScopeTest - 单例对象:com.giser.spring6.scope.Apple@7728643a
     *
     * 如果是在WebApplicationContext环境下还会有另外几个作用域(但不常用)
     * request:在一个请求域内有效
     * session:在一个会话范围内有效
     */
    @Test
    public void testScope(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-scope.xml");
        Apple apple = applicationContext.getBean(Apple.class);
        logger.info("单例对象:{}", apple);
        Apple apple2 = applicationContext.getBean(Apple.class);
        logger.info("单例对象:{}", apple2);
    }

}
3.14 bean的生命周期
package com.giser.spring6.lifecycle;

/**
 * @author giserDev
 * @description
 * @date 2023-12-31 21:22:01
 */
public class Phone {

    private String phoneName;

    public Phone() {
        System.out.println("Bean生命周期:[1 bean对象创建(调用无参构造方法)]");
    }

    public void initMethod(){
        System.out.println("Bean生命周期:[4 bean对象初始化(调用bean配置时init-method属性指定的初始化方法)] ");
    }

    public void destroyMethod(){
        System.out.println("Bean生命周期:[7 bean对象销毁(调用bean配置时destroy-method属性指定的销毁方法)] ");
    }

    public String getPhoneName() {
        return phoneName;
    }

    public void setPhoneName(String phoneName) {
        System.out.println("Bean生命周期:[2 为对象属性赋值(调用属性set方法)] ");
        this.phoneName = phoneName;
    }
}
package com.giser.spring6.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author giserDev
 * @description
 * @date 2023-12-31 21:26:40
 */
public class MyBeanProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean生命周期:[3 bean后置处理器(在bean初始化之前执行)] ");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean生命周期:[5 bean后置处理器(在bean初始化之后执行)] ");
        return 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">

    <!--
        init-method: 设置对象初始化方法
        destroy-method: 设置对象销毁方法
        scope: 设置对象作用域
    -->
    <bean id="phone" class="com.giser.spring6.lifecycle.Phone"
          init-method="initMethod"
          destroy-method="destroyMethod"
          scope="singleton" >
        <property name="phoneName" value="小米手机" />
    </bean>

    <!-- bean的后置处理器要放入IOC容器才能生效 -->
    <bean id="myBeanProcessor" class="com.giser.spring6.lifecycle.MyBeanProcessor" />

</beans>
import com.giser.spring6.lifecycle.Phone;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author giserDev
 * @description
 * @date 2023-12-31 21:30:42
 */
public class SpringBeanLifeCycleTest {
    private Logger logger = LoggerFactory.getLogger(SpringBeanLifeCycleTest.class);

    /**
     * 在scope="singleton"情况下:
     * 2023-12-31 22:09:45 404 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@422c3c7a
     * 2023-12-31 22:09:45 631 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [beans-lifecycle.xml]
     * 2023-12-31 22:09:45 679 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBeanProcessor'
     * 2023-12-31 22:09:45 713 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'phone'
     * Bean生命周期:[1 bean对象创建(调用无参构造方法)]
     * Bean生命周期:[2 为对象属性赋值(调用属性set方法)]
     * Bean生命周期:[3 bean后置处理器(在bean初始化之前执行)]
     * Bean生命周期:[4 bean对象初始化(调用bean配置时init-method属性指定的初始化方法)]
     * Bean生命周期:[5 bean后置处理器(在bean初始化之后执行)]
     * 2023-12-31 22:09:45 787 [main] INFO spring6.SpringBeanLifeCycleTest - Bean生命周期:[6 bean对象准备就绪,可以使用了]
     * 2023-12-31 22:09:45 789 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@422c3c7a, started on Sun Dec 31 22:09:45 CST 2023
     * Bean生命周期:[7 bean对象销毁(调用bean配置时destroy-method属性指定的销毁方法)]
     * 2023-12-31 22:09:45 793 [main] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter - Custom destroy method 'destroyMethod' on bean with name 'phone' completed
     */
    @Test
    public void test01(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-lifecycle.xml");
        Phone phone = applicationContext.getBean(Phone.class);
        logger.info("Bean生命周期:[6 bean对象准备就绪,可以使用了]");
        applicationContext.close();
    }

}
3.15 FactoryBean
public class UserInfo {
}
public class UserFactoryBean implements FactoryBean<UserInfo> {

    @Override
    public UserInfo getObject() throws Exception {
        return new UserInfo();
    }

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

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}
<?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="userInfo" class="com.giser.spring6.factorybean.UserFactoryBean" />

</beans>
public class SpringFactoryBeanTest {

    private Logger logger = LoggerFactory.getLogger(SpringFactoryBeanTest.class);

    /**
     * FactoryBean是Spring提供的一种整合第三方框架的常用机制。
     * 和普通的bean不同,配置一个FactoryBean类型的bean,
     *      在获取bean的时候得到的并不是class属性中配置的这个类的对象,
     *      而是getObject()方法的返回值。
     * 在整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
     *
     * [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@14b030a0
     * [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [beans-factorybean.xml]
     * [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userInfo'
     * [main] INFO spring6.SpringFactoryBeanTest - 通过FactoryBean获取的对象为com.giser.spring6.factorybean.UserInfo@255990cc
     */
    @Test
    public void testFactoryBean(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-factorybean.xml");
        UserInfo userInfo = applicationContext.getBean(UserInfo.class);
        logger.info("通过FactoryBean获取的对象为{}", userInfo);
    }

}
3.16 自动装配

UserDao

public interface UserDao {
    void sayHello();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void sayHello() {
        System.out.println("userDao sayHello");
    }
}

UserService

public interface UserService {
    void sayHello();
}
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void sayHello() {
        userDao.sayHello();
    }
}

UserController

public class UserController {

    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void sayHello(){
        userService.sayHello();
    }

}

自动装配

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

    <!--
        自动装配:byType 根据类型自动装配bean
    -->
    <!--
    <bean id="userController" class="com.giser.spring6.autowire.controller.UserController" autowire="byType" />
    <bean id="userService" class="com.giser.spring6.autowire.service.impl.UserServiceImpl" autowire="byType" />
    <bean id="userDao" class="com.giser.spring6.autowire.dao.impl.UserDaoImpl" autowire="byType" />
    -->

    <!--
        自动装配:byName 根据名称自动装配bean
    -->
    <bean id="userController" class="com.giser.spring6.autowire.controller.UserController" autowire="byName" />
    <bean id="userService" class="com.giser.spring6.autowire.service.impl.UserServiceImpl" autowire="byName" />
    <bean id="userDao" class="com.giser.spring6.autowire.dao.impl.UserDaoImpl" autowire="byName" />

</beans>

测试

import com.giser.spring6.autowire.controller.UserController;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author giserDev
 * @description
 * @date 2023-12-31 22:51:15
 */
public class SpringAutowiredTest {

    @Test
    public void testAutowired(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans-autowire.xml");
        UserController userController = applicationContext.getBean(UserController.class);
        userController.sayHello();
    }

}
文章来源:https://blog.csdn.net/SUNBOYmxbsH/article/details/135320584
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。