Spring IOC中的Bean对象用法

目录
  • Spring IOC中的Bean对象
    • 一、Bean是什么
    • 二、Bean对象的三种构造方式
    • 三、依赖注入
    • 四、Bean的生命周期
  • Ioc中Bean的作用域
    • bean的作用范围和生命周期

Spring IOC中的Bean对象

一、Bean是什么

突然发现提到了好多次Bean,居然忘记了讲Bean是什么。没事,现在讲也不晚。Java中的Bean是一种规范,是一种特殊的java类。所以我们先来看看Bean的规范。

  • Bean必须生成public class类。
  • 所有属性必须封装,Bean类的属性都为private。
  • 属性值应该通过一组方法(getXxx 和 setXxx)来访问和修改。
  • Bean类必须有一个空的构造函数(默认构造函数)。

这些就是Bean的基本规范,我们可以进行扩充,但是这些最基本的都是要满足的,否则就算不上一个标准的Bean。下面我来举一个标准的Bean的例子,注意上面的四个要素。

public class User {
    private String id;
    private String name;
    public User(){}
    public User(String id, String name) {
        this.id = id;
        this.name = name;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

是的,Bean就是这样的一种特殊的类,这个东西必须要牢记,因为后面会经常用到。

二、Bean对象的三种构造方式

自从有了spring之后,对象的构造不用我们再去操心了,一切交给spring完成就行。但是,框架再高级,他的底层依旧是在做一些很简单的事,这些事可能我们过去也经常自己来做。因此,学习spring我们既要知其然也要知其所以然,下面我们就来看看有哪些构造Bean对象的方式。顺便了解一下他们的原理是什么。

1. 构造方法构造

这是我们用的最多的一种构造方式。你肯定很好奇,在以前的案例中,为啥我们在配置文件里面写一句:

<bean id="circle" class="com.demo.Circle"/>

然后这个Bean对象就被spring构造出来放入IOC容器中了?其实这东西没啥高大上的,实际上就是spring利用反射调用了这个类的默认构造方法而已。就是这么简单。

那么问题来了,如果我们对象中有属性(暂时假定属性只包含基本类型和String,对象属性会在后面讲),我们又该怎么来构造呢?这个配置文件应该怎么去写呢?很简单,每个Bean对象中都由setter方法(不记得的可以去复习一下上面写的的Bean的结构),框架可以通过调用setter方法,把需要的值传递给属性,这就是属性注入。比如我们试着构造一个本文开头提到了一个Bean的对象:

<bean id="user" class="com.beans.User">
	<property name="id" value="666"></property>
    <property name="name" value="666"></property>
</bean>

这段配置主要干了什么事呢?首先,就像往常一样,调用默认构造方法,构造出一个对象,然后调用两个setter方法,分别给两个属性赋值。用传统代码表示就是这样:

User user = new User();
user.setId("666");
user.setName("666");

当然,平时我们自己很少这么做,如果需要给属性赋值,我们可以直接重载构造方法,通过传参的方式在创建对象的同时直接给属性赋值,这样可以减少代码量。下面我们来看看怎样让框架调用Bean的有参构造方法:

<bean id="user" class="com.beans.User" >
	<constructor-arg name="id" value="666"></constructor-arg>
    <constructor-arg name="name" value="666"></constructor-arg>
</bean>

这段配置就相当于是直接对有参构造方法进行调用,这里的arg是arguement(参数)的缩写,所以constructor-arg就是构造方法的参数列表的意思,name很显然就是参数名了,value就是我们要填入的参数值。所以我们就要为参数列表中所有的参数进行填值,就像我们过去做的一样:

User user = new User("666", "666");

现在你应该已经了解了spring框架究竟干了什么了吧。看似高大上的框架做的事也不过如此嘛,最基本的东西是永远逃不掉的。

2. 静态工厂构造

这种方式一般只有特定场景会使用,所以我们就简单看看就行。这里的静态工厂和我们前面讲的工厂模式差不多,首先我们要有一个工厂:

public class UserFactory {
    public static User createPerson(){
        return new User();
    }
    public static User createPerson(Integer id,String name){
        return new User(id,name);
    }
}

下面我们来看看配置文件如何书写:

<bean id="user" class="com.beans.factory.UserFactory" factory-method="createPerson">
    <constructor-arg name="id" value="666"></constructor-arg>
    <constructor-arg name="name" value="666"></constructor-arg>
</bean>

使用静态工厂方法创建Bean实例需要为<bean />元素指定除id外如下属性:

  • class:指定静态工厂的全类名(相当于指定工厂的地址)
  • factory-method:指定由静态工厂的哪个方法创建该Bean实例(指定由工厂的哪个车间创建Bean)
  • 方法参数:如果静态工厂方法需要参数,则使用<constructor-arg />元素传入。

3. 实例工厂构造

实例工厂和静态工厂唯一的区别就是我们需要先实例化工厂对象,才能构造我们需要的Bean对象:

<!-- 先构造工厂对象,class指定该工厂的实现类,工厂对象负责产生其他Bean实例 -->
<bean id="userFactory" class="com.beans.factory.UserFactory"/>
<!-- 再引用工厂对象来配置其他Bean -->
<bean id="user" factory-bean="userFactory" factory-method="createPerson">
    <constructor-arg name="id" value="666"></constructor-arg>
	<constructor-arg name="name" value="666"></constructor-arg>
</bean>

调用实例化工厂需要为<bean />指定除id外如下属性:

  • factory-bean :该属性指定工厂Bean的id
  • factory-method:该属性指定实例工厂的工厂方法。
  • 方法参数:如果静态工厂方法需要参数,则使用<constructor-arg />元素传入。

实例工厂和静态工厂平时用的不算特别多,平时开发时用的最多的还是最开始说的构造方法构造。现在有个重要的问题,如果Bean对象的属性是一个对象呢?这就是我们下面要讲的——依赖注入(DI)

三、依赖注入

讲spring IOC,不能不讲DI,这两个东西基本上可以说是相辅相成、唇亡齿寒的,所以现在我们就来看看IOC和DI的关系。控制反转——IOC(Inversion of Control)的意思是创建对象的控制权进行转移。以前创建对象的主动权和创建时机是由自己把控,而现在这种权力转移到了spring。

IOC的最重要的一个功能是在系统运行中,动态的向某个对象提供它所需要的其他对象作为属性。这一点是通过DI(Dependency Injection,依赖注入)来实现的。下面我来举一个依赖注入的例子:

比如A类需要使用JBDC,以前我们要在A类中编写代码来自己new一个Connection对象(这边咱先不考虑数据库连接池)。现在有了 spring,我们就只需要用配置文件告诉spring,A类中需要一个Connection对象,至于这个Connection怎么构造,何时构造,A类不需要知道。在运行时,spring会在适当的时候构造一个Connection对象,然后注入到A类当中,这样就完成了对各个对象之间关系的控制。A类需要依赖Connection这个属性才能正常运行,而这个Connection对象是由spring注入到A中的,依赖注入的名字就这么来的。

看了这么多,是不是发现其实依赖注入和我们上文讲的属性注入其实是同一类东西,都是动态地给对象的属性赋值,只不过这里的属性是一个对象,上文讲的的属性是简单类型而已。依赖注入听起来很高端,实际上就是给对象的对象属性赋值而已。

四、Bean的生命周期

讲了如何编写配置文件,那么你一定好奇在spring内部每时每刻这个Bean的状态应该是怎么样的。于是我们就来看看spring中Bean的生命周期。不过,有一点要提前说明,Spring只帮我们管理单例模式(singleton)Bean的完整生命周期,对于 多例模式(prototype)的Bean,Spring 在创建好交给使用者之后则不会再管理后续的生命周期了。单例模式和多例模式放在后面讲。

来看看我们的Bean对象是如何产生的。这个图乍一看很吓人,其实里面许多东西都是一些扩展点,他们穿插于Bean的生命周期中,我们一开始不需要去折腾这些扩展点,我们的关注点应该在Bean的生命周期本身。

其实,Bean的生命周期一共只有四个阶段,分别是:

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

要彻底搞清楚Spring的生命周期,首先要把这四个阶段牢牢记住。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段,我们可以自己在这两个函数里面书写我们需要的逻辑。在这四个阶段之间穿插的各种扩展点,以后再讲。

首先我们先来看前三个,他们的主要逻辑都在doCreateBean方法中,顺序调用三个方法,这三个方法与三个生命周期阶段一一对应:

//PS:下面的代码已经删去暂时不用了解的部分,只留下核心部分
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (instanceWrapper == null) {
       // 实例化
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
       // 属性赋值
      populateBean(beanName, mbd, instanceWrapper);
       // 初始化
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
}

有了这三个,再加上一个销毁,组成了Bean的最重要的四个生命周期阶段。如下图所示,当然,下图除了这四个基本的生命周期阶段之外,还加上了一些扩展点:

初学时我们只需要知道这些扩展点的存在即可,至于他们具体该怎么用,后面用到的时候会讲。我们在这里需要明白的是四个最基本的生命周期。其他的扩展点平时开发很少用到,但是在读一些Java中间件源码的时候,这些扩展点就必须得弄明白了。

Ioc中Bean的作用域

在Spring中,可以在< bean >元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。

默认情况下,Spring值为每个在IOC容器里声明的bean创建唯一一个实例,整个Ioc容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean。该作用域被称为singleton,它是所有bean的默认作用域。

当bean的作用域为单例时,Spring会在IOC容器对象创建时就创建bean的对象实例。而当bean的作用域为prototype时,Ioc容器在获取bean的实例时创建bean的实例对象

bean的作用范围和生命周期

单例对象: scope=“singleton”

  • 一个应用只有一个对象的实例。他的作用范围就是整个引用
  • 生命周期:
  • 对象出生:当应用加载,创建容器时,对象创建
  • 对象活着:只要容器在,对象一直活着
  • 对象死亡:当应用卸载,销毁容器时,对象销毁

多例对象:scope=“prototype”

  • 每次访问对象时,都会重新创建对象实例
  • 生命周期:
  • 对象出生:当使用对象时,创建新的对象实例
  • 对象活着:只要对象在使用中,就一直活着
  • 对象死亡:当对象长时间不用时,就被java的垃圾回收器回收了。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 关于SpringBoot获取IOC容器中注入的Bean(推荐)

    一: 注入一个TestUtils类 package com.shop.sell.Utils; import com.shop.sell.dto.CartDTO; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TestUtils { @Bean(name="test

  • spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean实例放入bean缓存池: 应用程序使用bean. 1.2.基于xml的配置 (1)xml文件概述 xmlns------默认命名空间 xmlns:xsi-------标准命名空间,用于指定自定义命名空间的schema文件 xmlns:xxx="aaaaa"-------自定义命名空间,xx

  • Spring为IOC容器注入Bean的五种方式详解

    这篇文章主要介绍了Spring为IOC容器注入Bean的五种方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一 @Import导入组件,id默认是组件的全类名 //类中组件统一设置.满足当前条件,这个类中配置的所有bean注册才能生效: @Conditional({WindowsCondition.class}) @Configuration @Import({Color.class,Red.class,MyImportSelector

  • 详解SpringIOC容器中bean的作用范围和生命周期

    bean的作用范围: 可以通过scope属性进行设置: singleton 单例的(默认) prototype 多例的 request 作用于web应用的请求范围 session 作用于web应用的会话范围 global-session 作用于集群环境的会话范围(全局会话范围) 测试: <!-- 默认是单例的(singleton)--> <bean id="human" class="com.entity.Human"></bean&g

  • Spring IOC中的Bean对象用法

    目录 Spring IOC中的Bean对象 一.Bean是什么 二.Bean对象的三种构造方式 三.依赖注入 四.Bean的生命周期 Ioc中Bean的作用域 bean的作用范围和生命周期 Spring IOC中的Bean对象 一.Bean是什么 突然发现提到了好多次Bean,居然忘记了讲Bean是什么.没事,现在讲也不晚.Java中的Bean是一种规范,是一种特殊的java类.所以我们先来看看Bean的规范. Bean必须生成public class类. 所有属性必须封装,Bean类的属性都为

  • 谈谈Spring AOP中@Aspect的高级用法示例

    前言 本文主要跟大家分享介绍了关于Spring AOP中@Aspect的高级用法,下面话不多说了,来随着小编一起看看详细的介绍吧. 1 切点复合运算 支持在切点定义中加入以下运算符进行复合运算: 运算符 说明 && 与运算. ! 非运算. || 或运算. 2 切点命名 一般情况下,切点是直接声明在需要增强方法处,这种切点的声明方式称为匿名切点,匿名切点只能在声明处被使用 . 如果希望在其它地方可以重用这个切点,我们可以通过 @Pointcut 注解及切面类方法来命名它. public cl

  • Spring容器中添加bean的5种方式

    目录 @Configuration + @Bean @Componet + @ComponentScan @Import注解导入 @Import直接导入类 @Import + ImportSelector @Import + ImportBeanDefinitionRegistrar @Import + DeferredImportSelector 使用FactoryBean接口 使用 BeanDefinitionRegistryPostProcessor 小结 我们知道平时在开发中使用Spri

  • Spring IOC容器的Bean管理基于注解属性注入方式

    目录 基于注解方式进行属性注入 一.@Autowired 1. 添加对象注解 2. 在service中注入dao对象 3. 创建测试函数测试效果 二.@Qualifier 三.@Resource 1. 替代 @Autowired 2. 替换 @Qualifier 四.@Value 基于注解方式进行属性注入 涉及到 4 个注解 @Autowired:根据属性类型,进行自动装配 @Qualifier:根据属性名称进行注入,跟 @Autowired 一起使用 @Resource:既可以根据类型注入,也

  • Spring通过配置文件管理Bean对象

    目录 一.Bean对象 二.存储Bean对象 1. 添加配置xml文件 2. 创建上下文 三.获取Bean对象 提示:以下是本篇文章正文内容,Java系列学习将会持续更新 一.Bean对象 Bean是Spring框架在运行时管理的对象, 是需要放置在Spring容器中进行管理的. Spring容器: BeanFactory接口(bean工厂)——> ApplicationContext接口(应用上下文)实现Spring容器的方法:基于xml文件.基于注解,我们接下来演示通过修改xml配置文件的方

  • spring IOC中三种依赖注入方式

    一.Spring IOC(依赖注入的三种方式): 1.Setter方法注入. 2.构造方法注入. 使用构造方法,注入bean值. 关键代码: public UserServiceImpl(UserDao dao) { this.dao=dao; } <bean id="service" class="service.impl.UserServiceImpl"> <constructor-arg><ref bean="dao&q

  • spring IOC容器的Bean管理XML自动装配过程

    目录 什么是自动装配? 自动装配过程 1. 创建 2 个类 2. 配置文件 3. 测试方法 什么是自动装配? 在之前的内容中,每给属性注入值都要一个个的用 property 标签来完成,比如: <bean id="book" class="com.pingguo.spring5.collectiontype.Book" scope="prototype"> <property name="list" ref=

  • 如何动态替换Spring容器中的Bean

    目录 动态替换Spring容器中的Bean 原因 方案 实现 Spring中bean替换问题 动态替换Spring容器中的Bean 原因 最近在编写单测时,发现使用 Mock 工具预定义 Service 中方法的行为特别难用,而且无法精细化的实现自定义的行为,因此想要在 Spring 容器运行过程中使用自定义 Mock 对象,该对象能够代替实际的 Bean 的给定方法. 方案 创建一个 Mock 注解,并且在 Spring 容器注册完所有的 Bean 之后,解析 classpath 下所有引入该

  • ASP.NET中Application全局对象用法实例浅析

    本文实例讲述了ASP.NET中Application全局对象用法.分享给大家供大家参考.具体如下: Application是应用全局对象,被全体共享.无论通过哪个页面操作Application,另一个页面都可以读取Application信息. 由于Application是共享的,操作之前先Lock,操作完成后UnLock. 在一个页面设置数据: Application.Lock(); Application.Set("address", "上海"); Applica

  • Java中Map集合中的Entry对象用法

    Entry: 键值对 对象. 在Map类设计是,提供了一个嵌套接口(static修饰的接口):Entry.Entry将键值对的对应关系封装成了对象,即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值. Entry为什么是静态的? Entry是Map接口中提供的一个静态内部嵌套接口,修饰为静态可以通过类名调用. Map集合遍历键值对的方式: Set<Map.Entry<K,V>> entrySet(); //返回此映射中包含的映射

随机推荐