Spring 6(二)【IOC(2)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Spring 6(二)【IOC

Spring 6(二)【IOC(1)https://developer.aliyun.com/article/1532215

1.5、特殊类型属性的注入

我们的对象类型还可能是其它类型,比如数组、集合类型。这些特殊类型属性的注入无非就是配置文件的写法变化罢了。

1.5.1、数组类型

我们给上面的 Student 类添加一个 Int[] 类型的 hobbies 属性,记得添加 setter (没有 setter 方法就无法注入)和 getter 方法。

<bean id="student6" class="com.lyh.study.bean.Student">
    <property name="id" value="1006"/>
    <property name="name" value="狄如燕"/>
    <property name="age" value="19"/>
    <property name="sex" value="女"/>
    <property name="address" ref="address1"/>
    <property name="hobbies">
        <array>
            <value>唱歌</value>
            <value>舞剑</value>
        </array>
    </property>
</bean>

1.5.2、集合类型

(1)List 类型

我们给上面的 Student 类添加一个 List 类型的 students 属性并添加 setter 和 getter 方法。

<bean id="student7" class="com.lyh.study.bean.Student">
        <property name="id" value="1006"/>
        <property name="name" value="狄如燕"/>
        <property name="age" value="19"/>
        <property name="sex" value="女"/>
        <property name="address" ref="address1"/>
        <property name="students">
            <list>
                <ref bean="student4"/>
                <ref bean="student5"/>
                <ref bean="student6"/>
            </list>
        </property>
    </bean>

注意:如果是 Set 集合,只需要将其中的list标签改为set标签即可。

(2)Map 类型

我们给上面的 Student 类添加一个 Map 类型的 studentMap 属性并添加 setter 和 getter 方法。

<bean id="student8" class="com.lyh.study.bean.Student">
        <property name="id" value="1006"/>
        <property name="name" value="狄如燕"/>
        <property name="age" value="19"/>
        <property name="sex" value="女"/>
        <property name="address" ref="address1"/>
        <property name="studentMap">
            <map>
                <entry>
                   <key>
                       <value>1001</value>
                   </key>
                    <!-- 如果value是基本类型,直接使用<value>标签即可 -->
                    <ref bean="student1"/>
                </entry>
                <entry>
                    <key>
                        <value>1002</value>
                    </key>
                    <ref bean="student2"/>
                </entry>
            </map>
        </property>
    </bean>

1.5.3、通过  标签实现集合类型属性的注入

要使用 util 标签就必须先引入它,在配置文件头部需要加入以下内容:

使用 util 标签实现 Map 集合类型注入:

    <bean id="student8" class="com.lyh.study.bean.Student">
        <property name="id" value="1008"/>
        <property name="name" value="狄如燕"/>
        <property name="age" value="19"/>
        <property name="sex" value="女"/>
        <property name="address" ref="address1"/>
        <property name="studentMap" ref="map"/>
    </bean>
 
    <util:map id="map">
        <entry>
            <key>
                <value>1001</value>
            </key>
            <ref bean="student1"/>
        </entry>
        <entry>
            <key>
                <value>1002</value>
            </key>
            <ref bean="student2"/>
        </entry>
    </util:map>

可以看到,效果和上面直接通过  标签注入是一样的,这个  标签就相当于一个 Map 对象。

1.6、P 命名空间注入

命名空间是啥东西,其实就是我们 Spring 配置文件的头部那些带有 xlms: xxx 的部分(比如 xmls:util 就是 util 命名空间),所以 P 命名空间注入其实就是加这么一行:

有啥用呢?其实也就是用来简化配置文件的代码量:

<bean id="student10" class="com.lyh.study.bean.Student" p:id="1010" p:name="武则天" p:age="58" p:address-ref="address1" p:studentMap-ref="map"/>

可以看到,引入 p命名空间后,我们的属性直接变成了 bean 标签的一个属性值 p:属性名,引用类型的属性也可以通过 p:属性名-ref 的方式来引用。

1.7、引入外部属性文件

我们经常需要把一些常用但是又经常需要修改的类写入到 Spring 配置文件(比如 MySQL 工具类),而这些 Bean 的属性值的修改就需要通过外部属性文件来进行注入了,这样更加灵活,方便维护。

(1)需求:

       把一些特定的固定值,放到一个特定的外部文件中去(比如 db.properties),在 Spring 配置文件中进行引入,这样我们要进行修改时,只需要修改外部文件,而不需要修改代码。

(2)导入依赖:

 <!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>
 
<!-- 数据源-连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>

(3)创建外部属性文件 db.properties

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

1.7.1、引入属性文件

(1)引入 context 名称空间:

(2)引入外部属性文件(db.properties)

<context:property-placeholder location="db.properties"/>

(3)配置连接池对应的 Bean

这个 Bean druid已经帮我们实现了,相当于一个工具类,我们都不用自己实现,只需要让 Spring 帮我管理即可。

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="username" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

(4)测试:

    @Test
    public void testDataSource() throws SQLException {
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        DataSource druidDataSource = ac.getBean("druidDataSource", DataSource.class);
        Connection connection = druidDataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }

(5)运行结果:

com.mysql.cj.jdbc.ConnectionImpl@5b56b654

1.8、Bean 的作用域

在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围:

取值 含义 创建对象的时机
singleton(默认) 在IOC容器中,这个bean的对象始终为单实例 IOC容器初始化时
prototype 这个bean在IOC容器中有多个实例 获取bean时

也就是我上一节说的,单例对象和多例对象的区别。

如果是在 WebApplicationContext 环境下还会有另外几个作用域(但不常用):

取值 含义
request 在一个请求范围内有效
session 在一个会话范围内有效

我是应该用不上了。

这里说一下单例模式(singleton)和非单例模式(prototype)的区别:

  • 单例模式下,每次 getBean 都会返回同一个对象(在内存中的地址相同,可以用 == 进行测试)
  • 非单例模式下,每次 getBena 都会创建一个新的对象,尽管我们在配置文件中设置的它们的属性是一样的,但是它们指向的是不同的内存地址。

1.9、Bean 的生命周期

  1. bean对象创建(调用无参构造器)
  2. 给bean对象设置属性(调用我们自己写的 setter 方法)
  3. bean的后置处理器(初始化之前)
  4. bean对象初始化(需在配置bean时指定初始化方法)
  5. bean的后置处理器(初始化之后)
  6. bean对象就绪可以使用
  7. bean对象销毁(需在配置bean时指定销毁方法)
  8. IOC容器关闭

1.9.1、初始化和销毁方法

上面的 Bean 对象的初始化方法和销毁方法是我们自己实现的,然后通过给  标签添加属性来实现:

<!-- 使用init-method属性指定初始化方法 -->
<!-- 使用destroy-method属性指定销毁方法 -->
<bean class="com.lyh.study.bean.User" scope="prototype" init-method="initMethod" destroy-method="destroyMethod">
    <property name="id" value="1001"></property>
    <property name="name" value="朱重八"></property>
    <property name="age" value="18"></property>
    <property name="sex" value="男"></property>
</bean>

1.8.2、后置处理器

bean 的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现 BeanPostProcessor 接口,且配置到IOC容器中。

需要注意的是:bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行  

package com.lyh.study;
    
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
 
public class MyBeanProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 初始化之前的处理代码
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 初始化之后的处理代码
        return bean;
    }
}

在 IOC 容器内配置后置处理器(放进去就行了):

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

1.10、FactoryBean

       FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean 类型的 bean(FactoryBean 是一个接口,所以这里说 FactoryBean类型的Bean 指的其实是 它的实现类),在获取 bean 的时候得到的并不是 class 属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。

       其实我们整合 Spring + Mybatis 时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
 
    @Nullable
    T getObject() throws Exception;
 
    @Nullable
    Class<?> getObjectType();
 
    default boolean isSingleton() {
        return true;
    }
}

(1)实现 FactoryBean 接口:

package com.lyh.study;
 
import com.lyh.study.bean.Student;
import org.springframework.beans.factory.FactoryBean;
 
public class StudentFactoryBean implements FactoryBean<Student> {
 
    @Override
    public Student getObject() throws Exception {
        return new Student();
    }
 
    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }
}

(2)添加到 IOC 容器:

<bean id="studentFactoryBean" class="com.lyh.study.StudentFactoryBean"/>

(3)测试:

    @Test
    public void testBeanFactory(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        // 转换出来的不是 StudentBeanFactory 对象,而是 Student 对象
        Student studentBeanFactory = (Student) ac.getBean("studentFactoryBean");
        System.out.println(studentBeanFactory);
    }

(4)运行结果:

Student{id=null, name='null', age=null, sex='null'}

当 Spring 容器遇到一个实现了 FactoryBean 接口的 Bean 时,它不会直接实例化这个 Bean,而是会调用该 Bean 的 getObject() 方法来获取对象。这样,我们就可以在 getObject() 方法中编写自定义的对象创建逻辑,从而实现与第三方框架的整合。

Spring 6(二)【IOC(3)https://developer.aliyun.com/article/1532219

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
12天前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
4天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
9 0
|
2月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
200 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
2月前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
121 9
|
1月前
|
存储 开发框架 Java
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
文章详细介绍了Spring、IOC、DI的概念和关系,解释了控制反转(IOC)和依赖注入(DI)的原理,并提供了IOC的代码示例,阐述了Spring框架作为IOC容器的应用。
26 0
什么是Spring?什么是IOC?什么是DI?IOC和DI的关系? —— 零基础可无压力学习,带源码
|
2月前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
40 4
|
25天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
61 0
|
2月前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
110 3
下一篇
无影云桌面