Spring中IoC容器和Bean

news2024/9/22 13:26:28

目录

IoC(Inversion of Control)控制反转思想

Spring技术对IoC思想的实现

DI(Dependency Injection)依赖注入

目标

最终效果

IoC入门案例

传统方法,不使用IoC思想调用dao层 

使用IoC思想调用dao层

第一步:导入Spring坐标

第二步:创建Spring配置文件

 第三步:初始化IoC容器,并通过容器来获取bean对象

不使用IoC思想调用service层

使用IoC思想调用service层

总结:如何将对象交给spring容器管理

Bean的基础配置

标签中的name属性:给一个bean变量起别名 

标签中的scope属性:控制bean变量是单例还是多例,默认是单例(多次从容器获取的bean对象是同一个)

 适合交给IoC容器管理的bean

不适合交给IoC容器管理的bean

 Bean的实例化

第一种:通过无参构造,初始化IoC容器时就会调用所有bean对象的无参构造方法,创建每个bean对象

第二种:通过静态工厂

第三种:通过实例化工厂类

 依赖注入方式

 第一种setter注入

第二种:构造器注入


IoC(Inversion of Control)控制反转思想

        使用对象时,由主动的new产生对象转换成由外部提供对象,此过程对象控制权由程序转移到外部,此思想称为控制反转。

Spring技术对IoC思想的实现

        spring提供了一种容器,叫做IoC容器,用来充当IoC思想的"外部”

        IoC容器负责对象的创建,初始化一系列工作,被创建或被管理的对象在IoC容器中都叫做Bean

DI(Dependency Injection)依赖注入

        在容器中建立bean和bean之间的依赖关系的整个过程,称为依赖注入

目标

  1.          在IoC容器中管理bean
  2.         在IoC容器中将有依赖关系bean进行绑定(DI)

最终效果

        使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean都已经绑定了所有的依赖关系

IoC入门案例

传统方法,不使用IoC思想调用dao层 

 

public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("bookDao save");
    }
}

 不使用IoC思想(自己new一个对象,缺点:接口与实现类的耦合性太高)


/*
传统方法
 */
public class Book {
    public static void main(String[] args) {
        BookDao bookDao=new BookDaoImpl();
        bookDao.save();
    }
}

使用IoC思想调用dao层

第一步:导入Spring坐标

 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>

第二步:创建Spring配置文件

<?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="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    id是为这个实现类起别名
</beans>

 第三步:初始化IoC容器,并通过容器来获取bean对象

public class App {
    public static void main(String[] args) {
        //初始化容器,加载配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");//从容器中new一个id为bookDao的实现类对象,并依赖注入到这
        bookDao.save();
    }
}

我们可以发现使用IoC思想可以把接口和实现类的耦合度降低很多,由于这个实现类在IoC容器里注册为了Bean对象,所以我们可以直接通过容器来获取接口对应的Bean对象(实现类对象)

不使用IoC思想调用service层

BookServiceImpl

public class BookServiceImpl implements BookService {
    BookDao bookDao;
    @Override
    public void save() {
        System.out.println("bookService");
        bookDao.save();
    }

    @Override
    public void setBookDao(BookDao bookDao) {
        this.bookDao=bookDao;
    }
}
public class Test {
    public static void main(String[] args) {
        BookService bookService=new BookServiceImpl();
        BookDao bookDao=new BookDaoImpl();
        bookService.setBookDao(bookDao);
        bookService.save();
    }
}

使用IoC思想调用service层

springContext.xml文件的配置,由于bookServiceImpl实现类里有一个dao层的成员变量,所以在这个<bean>中要给这个dao层的成员变量单独配置

  <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
<!--        name属性是实现类中dao层的成员变量的名字
            ref属性是id-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

调用

public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

 

总结:如何将对象交给spring容器管理

  • 配置文件使用<bean>标签配置
  • 初始化IoC容器,加载配置文件 

Bean的基础配置

<bean>标签中的name属性:给一个bean变量起别名 

<bean id="bookService" name="service service2" class="com.hhh.service.impl.BookServiceImpl">
<!--        name属性是实现类中dao层的成员变量的名字
            ref属性是id-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

如图:给bookServiceImpl实现类Bean对象起了两个别名,可以使用空格,也可以使用, ; 这两种符号来间隔别名 

public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        //BookService bookService = (BookService) ctx.getBean("bookService");
        BookService bookService = (BookService) ctx.getBean("service");
        bookService.save();
    }
}

<bean>标签中的scope属性:控制bean变量是单例还是多例,默认是单例(多次从容器获取的bean对象是同一个)

public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        //BookService bookService = (BookService) ctx.getBean("bookService");
        BookService bookService1 = (BookService) ctx.getBean("service");
        BookService bookService2 = (BookService) ctx.getBean("service");
        System.out.println(bookService1);
        System.out.println(bookService2);
         //com.hhh.service.impl.BookServiceImpl@4c1d9d4b
        //com.hhh.service.impl.BookServiceImpl@4c1d9d4b

    }
}

可以这两个Bean对象都是同一个,接下来我们修改一下

 <bean id="bookService" name="service service2" class="com.hhh.service.impl.BookServiceImpl"
    scope="prototype"
    >
<!--        name属性是实现类中dao层的成员变量的名字
            ref属性是id-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

可以发现修改之后这两个bean对象就是不同的 

 适合交给IoC容器管理的bean

  • dao层对象
  • service层对象
  • web层对象
  • 工具对象

不适合交给IoC容器管理的bean

封装实体的域对象(实体类)

 Bean的实例化

第一种:通过无参构造,初始化IoC容器时就会调用所有bean对象的无参构造方法,创建每个bean对象

第二种:通过静态工厂

创建静态工厂类

public class StaticBookDaoFactory {
    public static BookDao getBookDao(){
        return new BookDaoImpl();
    }

}

配置

 <bean id="bookDao" class="com.hhh.factory.StaticBookDaoFactory" factory-method="getBookDao"> </bean>

通过factory-method属性来指定通过静态工厂的静态成员方法来返回的对象与id="bookDao"对应

相当于:

BookDao bookDao= StaticBookDaoFactory.getBookDao();

第三种:通过实例化工厂类

public class InstanceBookDaoFactory {
    public  BookDao getBookDao(){
        return new BookDaoImpl();
    }
}

配置

<bean id="factoryBean" class="com.hhh.factory.InstanceBookDaoFactory"></bean>
        <bean id="bookDao" factory-bean="factoryBean" factory-method="getBookDao"></bean>

先配置实例化工厂类的bean对象,再通过factory-bean和factory-method来获取BookDaoImpl实现类的对象与id对应,相当于

InstanceBookDaoFactory instanceBookDaoFactory = new InstanceBookDaoFactory();
        BookDao bookDao1 = instanceBookDaoFactory.getBookDao();

但是这样相当的麻烦,还要先配置实例化工厂类的bean对象,所以我们可以让实例化工厂类实现FactoryBean接口,让程序知道不是获取这个实例化工厂类的bean对象,而是通过它里面的方法来获取指定的bean对象

public class InstanceBookDaoFactory implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new BookDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}
<bean id="bookDao" class="com.hhh.factory.InstanceBookDaoFactory"></bean>

因为InstanceBookDaoFactory实现了FactoryBean接口,所以不会获取InstanceBookDaoFactory的bean对象而是获取getObject()方法返回对象的bean对象

 依赖注入方式

 第一种setter注入

  • 简单类型
  • 引用类型(自定义类型)
public class BookServiceImpl implements BookService {
    BookDao bookDao;
    Integer num;
    @Override
    public void save() {
        System.out.println("bookService");
        System.out.println("num="+num);
        bookDao.save();
    }

    @Override
    public void setBookDao(BookDao bookDao) {
        this.bookDao=bookDao;
    }

    @Override
    public void setNum(Integer num) {
        this.num=num;
    }

}
<bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"></property>
        <property name="num" value="10"></property>
    </bean>

简单类型使用value属性进行赋值(依赖注入)

结果:

 

如果没有setXxx()方法,就会报错:Bean property 'num' is not writable or has an invalid setter method. 

第二种:构造器注入

  • 简单类型
  • 引用类型(自定义类型)
public class BookServiceImpl implements BookService {
    BookDao bookDao;
    Integer num;

    public BookServiceImpl(BookDao bookDao, Integer num) {
        this.bookDao = bookDao;
        this.num = num;
    }

    @Override
    public void save() {
        System.out.println("bookService");
        System.out.println("num="+num);
        bookDao.save();
    }
}

 

 <bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
       <constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
        <constructor-arg name="num" value="20"></constructor-arg>
    </bean>

<constructor-arg>name属性是有参构造函数里面的参数名字

结果

或者也可以这样配置

<bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
       <constructor-arg type="com.hhh.dao.BookDao"  ref="bookDao"></constructor-arg>
        <constructor-arg index="1" value="20"></constructor-arg>
    </bean>

 type就是参数的类型,index就是有参构造函数里参数位置的索引

 依赖自动装配,<autowire>

public class BookServiceImpl implements BookService {
    BookDao bookDao;

    @Override
    public void save() {
        System.out.println("bookService");
        bookDao.save();
    }

    @Override
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}
 <bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl" autowire="byType">
    </bean>

byType是容器通过类型匹配来查看自己是否有与BookServiceImpl类的成员变量相同类型bean对象,如果有就进行注入,没有就空指针异常

也可以使用byName,通过成员变量的名字来寻找,必须与id的名字一样 

集合注入

public class ResourceServiceImpl implements ResourceService {
    private String[] array;
    private List<String> list;
    private Set<String>set;
    private Map<String,String>map;
    private Properties properties;

    @Override
    public String toString() {
        return "ResourceServiceImpl{" +
                "array=" + Arrays.toString(array) +
                ", list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }

    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<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

 配置

<bean id="resourceService" class="com.hhh.service.impl.ResourceServiceImpl">
        <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
                <value>array3</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        <property name="set">
            <set>
<!--                set会去重-->
                <value>set1</value>
                <value>set1</value>
                <value>set3</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="mapKey1" value="value1"></entry>
                <entry key="mapKey2" value="value2"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="propKey1">value1</prop>
                <prop key="propKey2">value2</prop>
            </props>
        </property>
    </bean>
public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        ResourceService resourceService = (ResourceService) ctx.getBean("resourceService");
        System.out.println(resourceService);
    }
}

结果:

 Bean的生命周期

public class BookDaoImpl implements BookDao {
    public void init(){
        System.out.println("bookDao init");
    }
    @Override
    public void save() {
        System.out.println("bookDao save");
    }
    public void destroy(){
        System.out.println("bookDao destroy");
    }
}

配置

<bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl" init-method="init" destroy-method="destroy"></bean>
public class App {
    public static void main(String[] args) {
        //初始化容器
        ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        ctx.registerShutdownHook();//使用完自己关闭,写在哪都可以
        //暴力关闭
        //ctx.close();
    }
}

结果:

我们可以发现自己写init方法,和destroy方法还要再bean标签中自己配置,太过麻烦,我们可以实现spring提供的接口来重写方法

public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
   
    @Override
    public void save() {
        System.out.println("bookDao save");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("bean destroy");
    }

    @Override
//根据名字我们可以发现是先依赖注入再初始化bean对象
    public void afterPropertiesSet() throws Exception {
        System.out.println("bean init");
    }
}

根据方法名字我们可以发现是先依赖注入再初始化bean对象

这样一来我们就不用自己配置了

   <bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1932876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

stm32:CAN通讯

目录 介绍 协议层 CAN的 帧/报文 种类 数据帧 远程帧&#xff08;遥控帧&#xff09; 错误帧 过载帧 帧间隔 总线仲裁 stm32的CAN外设 工作模式 测试模式 功能框图 时序 标准时序 例子 环回静默模式测试 寄存器代码 HAL版本 介绍 一种功能丰富的车用总线标…

【ffmpeg命令入门】重新编码媒体流、设置码率、设置帧速率

文章目录 前言ffmpeg的描述重新编码媒体流重新编码媒体流的命令ffmpeg支持的媒体流 设置视频码率视频码率是什么设置视频的码率 设置文件帧数率帧数率是什么ffmpeg设置帧数率 总结 前言 在数字媒体处理领域&#xff0c;ffmpeg是一款非常强大的工具&#xff0c;它可以用来进行媒…

自动化产线 搭配数据采集监控平台 创新与突破

自动化产线在现在的各行各业中应用广泛&#xff0c;已经是现在的生产趋势&#xff0c;不同的自动化生产设备充斥在各行各业中&#xff0c;自动化的设备会产生很多的数据&#xff0c;这些数据如何更科学化的管理&#xff0c;更优质的利用&#xff0c;就需要数据采集监控平台来完…

解决Ubuntu 20.04下外接显示屏无信号问题【多次尝试无坑完整版!!!】

解决Ubuntu 20.04下外接显示屏无信号问题【多次尝试无坑完整版&#xff01;&#xff01;&#xff01;】 一、引言 作为一名开发者&#xff0c;我经常在Windows和Ubuntu之间切换&#xff0c;以满足不同的开发需求。最近&#xff0c;我在使用惠普暗影精灵9&#xff08;搭载RTX 4…

HLS加密技术:保障流媒体内容安全的利器

随着网络视频内容的爆炸性增长&#xff0c;如何有效保护视频内容的版权和安全成为了一个亟待解决的问题。HLS&#xff08;HTTP Live Streaming&#xff09;加密技术作为一种先进的流媒体加密手段&#xff0c;凭借其高效性和安全性&#xff0c;在直播、点播等场景中得到了广泛应…

隐性行为克隆——机器人的复杂行为模仿学习的新表述

介绍 论文地址&#xff1a;https://arxiv.org/pdf/2109.00137.pdf 源码地址&#xff1a;https://github.com/opendilab/DI-engine.git 近年来&#xff0c;人们对机器人学习进行了大量研究&#xff0c;并取得了许多成果。其中&#xff0c;模仿学习法尤其受到关注。这是一种从人…

JavaEE初阶 - IO、存储、硬盘、文件系统相关常识 (二)

&#x1f387;&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳&#xff0c;欢迎大佬指点&#xff01; 人生格言: 当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友…

appium2.0 执行脚本遇到的问题

遇到的问题&#xff1a; appium 上的日志信息&#xff1a; 配置信息 方法一 之前用1.0的时候 地址默认加的 /wd/hub 在appium2.0上&#xff0c; 服务器默认路径是 / 如果要用/wd/hub 需要通过启动服务时设置基本路径 appium --base-path/wd/hub 这样就能正常执行了 方法二…

HarmonyOS NEXT学习——@BuilderParam装饰器

初步理解&#xff0c;相当于VUE的插槽slot Builder function overBuilder() {}Component struct Child {label: string ChildBuilder customBuilder() {}Builder customChangeThisBuilder() {}BuilderParam customBuilderParam: () > void this.customBuilder; // 使用自定…

【TDA4板端部署】基于 Pytorch 训练并部署 ONNX 模型在 TDA4

1 将torch模型转onnx模型 Ti转换工具只支持以下格式&#xff1a; Caffe - 0.17 (caffe-jacinto in gitHub) Tensorflow - 1.12 ONNX - 1.3.0 (opset 9 and 11) TFLite - Tensorflow 2.0-Alpha 基于 Tensorflow、Pytorch、Caffe 等训练框架&#xff0c;训练模型&#xff1a;选择…

Hadoop3:HDFS存储优化之小文件归档

一、情景说明 我们知道&#xff0c;NameNode存储一个文件元数据&#xff0c;默认是150byte大小的内存空间。 那么&#xff0c;如果出现很多的小文件&#xff0c;就会导致NameNode的内存占用。 但注意&#xff0c;存储小文件所需要的磁盘容量和数据块的大小无关。 例如&#x…

【5G Sub-6GHz模块】专为IoT/eMBB应用而设计的RG520NNA、RG520FEB、RG530FNA、RG500LEU 5G模组

推出全新的5G系列模组&#xff1a; RG520NNADB-M28-SGASA RG520NNADA-M20-SGASA RG520FEBDE-M28-TA0AA RG530FNAEA-M28-SGASA RG530FNAEA-M28-TA0AA RG500LEUAA-M28-TA0AA ——明佳达 1、5G RG520N 系列——专为IoT/eMBB应用而设计的LGA封装模块 RG520N 系列是一款专为 IoT…

Kafka Producer发送消息流程之Sender发送线程和在途请求缓存区

文章目录 1. Sender发送数据1. 发送数据的详细过程&#xff1a;2. 关键参数配置 2. 在途请求缓存区 1. Sender发送数据 Sender线程负责将已经在RecordAccumulator中准备好的消息批次发送到Kafka集群。虽然消息在RecordAccumulator中是按照分区组织的&#xff0c;但Sender线程在…

百日筑基第二十三天-23种设计模式-创建型总汇

百日筑基第二十三天-23种设计模式-创建型总汇 前言 设计模式可以说是对于七大设计原则的实现。 总体来说设计模式分为三大类&#xff1a; 创建型模式&#xff0c;共五种&#xff1a;单例模式、简单工厂模式、抽象工厂模式、建造者模式、原型模式。结构型模式&#xff0c;共…

【JavaEE】synchronized原理详解

本文使用的是JDK1.8 目录 引言 Java对象在JVM的结构 对象头 Mark Word Monitor Owner EntryList WaitSet 加锁过程 锁消除 偏向锁 偏向锁使用 重偏向 撤销偏向 轻量级锁 重量级锁 自旋优化 引言 对于synchronized原理讲解之前&#xff0c;我们需要知道Java对象…

如何通过DBC文件看懂CAN通信矩阵

实现汽车CAN通信开发&#xff0c;必不可少要用到DBC文件和CAN通信矩阵。 CAN通信矩阵是指用于描述 CAN 网络中各个节点之间通信关系的表格或矩阵。它通常记录了每个节点能够发送和接收的消息标识符&#xff08;ID&#xff09;以及与其他节点之间的通信权限。 通信矩阵在 CAN 网…

Redis中数据分片与分片策略

概述 数据分片是一种将数据分割并存储在多个节点上的技术&#xff0c;可以有效提高系统的扩展性和性能。在Redis中&#xff0c;数据分片主要用于解决单个实例存储容量和性能瓶颈的问题。通过将数据分散存储到多个Redis节点中&#xff0c;可以将负载均衡到不同的服务器上&#…

防火墙之双机热备篇

为什么要在防火墙上配置双机热备技术呢&#xff1f; 相信大家都知道&#xff0c;为了提高可靠性&#xff0c;避免单点故障 肯定有聪明的小伙伴会想到那为什么不直接多配置两台防火墙&#xff0c;然后再将他们进行线路冗余&#xff0c;不就完成备份了吗&#xff1f; 答案是不…

UDP客户端、服务端及简易聊天室实现 —— Java

UDP 协议&#xff08;用户数据包协议&#xff09; UDP 是无连接通信协议&#xff0c;即在数据传输时&#xff0c;数据的发送端和接收端不建立逻辑连接&#xff0c;简单来说&#xff0c;当客户端向接收端发送数据时&#xff0c;客户端不会确认接收端是否存在&#xff0c;就会发出…

【深度学习教程】

文章目录 pytorch官方教程知识蒸馏&#xff1a;https://pytorch.org/tutorials/beginner/knowledge_distillation_tutorial.html 李宏毅-机器学习/深度学习https://speech.ee.ntu.edu.tw/~hylee/ml/2021-spring.phphttps://speech.ee.ntu.edu.tw/~hylee/ml/2022-spring.phphttp…