Spring 的IOC和bean详解

简介: Spring 的IOC和bean详解

*核心概念:

  • IOC(Inversion of Control)控制反转:
    目的:为了降低程序间的耦合度
    含义:把程序内主动new创造对象的过程交给外部程序去做,创建对象的过程中控制权由程序部转到了*外部*去实现。
    Spring对Ioc思想进行了实现:其提供了IOC容器来充当IOC思想的“外部”,IOC负责创建和管理对象,被创建和管理的对象在IOC中称为Bean
  • DI(Dependence Injection) 依赖注入:
    含义:在容器中建立bean之间的依赖关系。
  • 效果:使用对象是不仅可以直接从容器中取,还能获取到bean绑定的所有依赖关系。

1:IOC入门案例:

  1. pom.xml 配置文件中导入依赖
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.2.10.RELEASE</version>
</dependency>
  1. resourse文件夹中建立Spring配置文件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">
        <!--1:导入spring的坐标spring-context,对应版本为5.2.10.RELEASE-->
        <!--2:配置bean-->
        <!--bean:配置bean-->
        <!--id:给bean起的别名-->
        <!--class:给bean定义类型-->
    <bean id="bookDao" class="com.ysj.dao.impl.BookDaoImpl">
    </bean>
    <bean id="bookService" class="com.ysj.service.impl.BookServiceImpl">
    </bean>
</beans>
  1. 在测试类中:
//3:加载配置文件,获取IOC容器对象
   ApplicationContext ext = new ClassPathXmlApplicationContext("applicationContext.xml");
            //4:获取bean
     //  BookDao bookDao = (BookDao) ext.getBean("bookDao");
     // bookDao.save();;
        BookService bookService = (BookService) ext.getBean("bookService");
        bookService.save();
  1. 入门案例中,此时在业务层实现中,仍存在new创建对象,耦合度相对来说仍然较高,接下来就到DI(Dependence Injection) 登场了。

2:DI(Dependence Injection)入门案例:

//7:删除new
private BookDao bookDao;
public void save() {
    System.out.println("book service save ...");
    bookDao.save();
}
//8:设置setter方法:容器创建对象会调用setter方法
public void setBookDao(BookDao bookDao) {
    this.bookDao = bookDao;
}

<bean id="bookService" class="com.ysj.service.impl.BookServiceImpl">
    <!-- 配置server与dao的关系(dao对象在server中创建,所以在server中配置)-->
    <!--  property:配置当前bean的属性,即对应类中的属性-->
    <!--  name:当前bean所对应的类中的具体属性-->
    <!--  ref:表示参照哪个bean进行配置-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

3:bean

3:bean的基础配置

3.1:name属性:给bean起别名,多个别名间用空格隔开

<bean id="bookDao" name="dao ss ss1"  class="com.ysj.dao.impl.BookDaoImpl">

3.2:bean默认是单例模式

<!--  scope:选择bean是否为单例模式
    prototype:多例
    singleton:单例-->
<bean id="bookDao" name="dao ss ss1" scope="prototype"
      class="com.ysj.dao.impl.BookDaoImpl">

3.3🏖bean默认是单例模式的原因

如果默认不是单例,那么创造的bean对象将会无穷无尽,增加了Spring的负担
  ##适合交给容器进行管理的bean
  1:表现层对象
  2:业务层对象
  3:数据层对象
  4:工具类对象
  ##不适合交给容器进行管理的bean
  封装实体类的域对象

3.4:常见报错

//原因:没有命名为‘ss2’的bean
//方法;检查bean容器别名和自己书写哪里不一致
NoSuchBeanDefinitionException: No bean named 'ss2' available

4:bean的实例化的三种方式

4.1:构造方法(常用)

##提供可访问的构造方法:无参(bean容器创建对象调用无参构造方法)
    ##如果没有无参构造方法将报‘BeanCreationException’,‘java.lang.NoSuchMethodException’异常

4.2:Spring报错处理方法

#从后往前看

4.3:静态工厂(了解)

//静态工厂创建对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");
        return new OrderDaoImpl();
    }
}
<!--    方式二:使用静态工厂实例化bean,记得配置工厂造对象的具体方法-->
<bean id="orderDao" class="com.ysj.factory.OrderDaoFactory" factory-method="getOrderDao"/>

4.4:实例工厂

4.4.1:实例工厂实例化(了解)
  • 第一个bean仅仅是为了配合使用,创造对象,除此之外无其他意义
  • factory-method:如果这样配置,方法名不固定,每次配置bean都要配置
<!--    方式三:使用实例工厂实例化bean-->
   <bean id="userFactory" class="com.ysj.factory.UserDaoFactory"/>
   <!--factory-bean:配置工厂类的bean-->
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
4.4.2:FactoryBean(实用)
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    //代替原始实例工厂中创建对象的方法,bean中不必再配置factory-method,统一使用该方法创建对象
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    public Class<?> getObjectType() {
        return UserDao.class;
    }
    //true:创建对象是单例
    //false:创建对象非单例
    public boolean isSingleton() {
        return false;
    }
}
<!--方式四:使用FactoryBean实例化bean-->
<bean id="userDao" class="com.ysj.factory.UserDaoFactoryBean"/>

5:bean的生命周期

5.1:bean的初始化和销毁方法的配置

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    //表示bean初始化对应的操作
    public void init(){
        System.out.println("init...");
    }
    //表示bean销毁前对应的操作
    public void destory(){
        System.out.println("destroy...");
    }
}
<!--init-method:设置bean初始化生命周期回调函数-->
<!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象-->
<bean id="bookDao" class="com.ysj.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

配置完后运行程序,会发现destroy方法没有运行,这时你大叫:“Why?”

其实是因为:我们这些程序运行在虚拟机上,当IOC容器加载完配置后,bean也初始化了,接着运行程序,

然而当程序运行完后,虚拟机退出了,俺类destroy并没有机会执行,呜呜呜呜~~

public static void main( String[] args ) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
}

那么,如何让俺滴销毁方法执行呢?

有如下两个方法:

5.2:让销毁执行起来

注意把在加载IOC容器时定义ClassPathXmlApplicationContext对象

5.2.1:手动close(太暴力了,直接就停了)

用这个要注意使用的位置

public static void main( String[] args ) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
    //关闭容器
    ctx.close();
}
5.2.3:注册关闭钩子函数

虚拟机会在退出之前调用此函数,进而关闭容器

public static void main( String[] args ) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookDao bookDao = (BookDao) ctx.getBean("bookDao");
    bookDao.save();
    //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
    ctx.registerShutdownHook();
}

5.2:接口控制(了解)

按照Spring官方给的接口和规范进行配置

实现InitializingBean, DisposableBean接口

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;
    //在资源加载完后运行,但是在调用方法之前
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
    public void setBookDao(BookDao bookDao) {
        System.out.println("set .....");
        this.bookDao = bookDao;
    }
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }
}

5.3:生命周期历程

  • 初始化容器
  1. 创建对象(内存分配,类似于new,在内存中分配了空间)
  2. 执行构造方法(对象创建完成)
  3. 执行属性注入(set操作)
  4. 执行bean的初始化方法
  • 使用bean
    执行业务层
  • 关闭/销毁容器
    执行bean的销毁方法

5.4:小记

所有bean在IOC容器加载完配置后就被初始化了

相关文章
|
23天前
|
XML 安全 Java
|
1天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
6天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
29 6
|
7天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
51 3
|
21天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
41 2
|
1月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
21天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
30 1
|
2月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
82 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
1月前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。