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容器加载完配置后就被初始化了

相关文章
|
7月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
509 26
|
9月前
|
XML 安全 Java
|
4月前
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
|
9月前
|
XML Java 数据格式
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
193 69
|
6月前
|
Java 容器 Spring
什么是Spring IOC 和DI ?
IOC : 控制翻转 , 它把传统上由程序代码直接操控的对象的调用权交给容 器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转 移,从程序代码本身转移到了外部容器。 DI : 依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中。
|
9月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
9月前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
142 21
|
9月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
181 12
|
9月前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
228 12
|
9月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
261 6