java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring IOC

Spring IOC功能详解

作者:?abc!

在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制,本文给大家介绍Spring IOC的相关知识,感兴趣的朋友一起看看吧

概述

为什么叫控制反转

Spring Bean是什么:Spring里面的bean就类似是定义的一个组件,而这个组件的作用就是实现某个功能的,这里所定义的bean就相当于给了你一个更为简便的方法来调用这个组件去实现你要完成的功能

Spring框架管理这些Bean的创建工作,即由用户管理Bean转变为框架管理Bean,这个就叫控制反转 - Inversion of Control (IoC)

控制反转是通过依赖注入实现的,IoC是设计思想,DI是实现方式

IOC不是什么技术,是一种设计思想

在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制

Spring 中的 bean 的作用域

基础概念

singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype : 每次请求都会创建一个新的 bean 实例。

Spring并不管理作用域为prototype的bean的整个生命周期,使用者必须自己销毁 这个bean并释放资源。

下述作用域只有在web环境下才有用

对比

作用域说明典型应用场景
singleton默认作用域,容器内唯一实例无状态Service、工具类
prototype每次注入创建新实例有状态Bean、含可变状态的组件
request每个HTTP请求创建新实例Web请求上下文相关对象
session每个用户会话创建新实例用户购物车、登录信息
application整个Web应用生命周期单例全局配置

有状态和无状态的bean

基本概念

在 Spring 框架中,有状态 Bean 和 无状态 Bean 是两种重要的对象设计模式,它们的核心区别在于 是否保存可变状态,直接影响线程安全性和作用域管理

有状态 Bean 注意事项

无状态 Bean 最佳实践

建议

对比

特征有状态 Bean无状态 Bean
实例变量/状态存储包含可变的成员变量(会随操作改变)无成员变量,或只有不可变常量
线程安全需自行保证线程安全(如加锁、隔离)天然线程安全(无共享状态)
作用域通常用 prototype 作用域(每次注入新实例)通常用 singleton 作用域(全局共享)
复用性不同请求需不同实例(需频繁创建实例)、资源消耗较高全局共享单个实例、高性能(单例复用)
典型场景用户会话、购物车、事务上下文工具类、Service层业务逻辑

Ioc 配置的三种方式

总体上目前的主流方式是: 注解 + Java 配置

xml 配置

将bean的信息配置.xml文件里,通过Spring加载文件为我们创建bean。

<?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">
    <!-- services -->
    <bean id="userService" class="com.service.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>
    <!-- more bean definitions for services go here -->
</beans>

Java 配置

将类的创建交给我们配置的JavcConfig类来完成,Spring只负责维护和管理,采用纯Java创建方式。其本质上就是把在XML上的配置声明转移到Java配置类中

@Configuration
public class BeansConfig {
    /**
     * @return user dao
     */
    @Bean("userDao")
    public UserDaoImpl userDao() {
        return new UserDaoImpl();
    }
    /**
     * @return user service
     */
    @Bean("userService")
    public UserServiceImpl userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao());
        return userService;
    }
}

注解配置

通过在类上加注解的方式,来声明一个类交给Spring管理,Spring会自动扫描带有@Component,@Controller,@Service,@Repository这四个注解的类,然后帮我们创建并管理,前提是需要先配置Spring的注解扫描器。

依赖注入的三种方式

常用的注入方式主要有三种:构造方法注入(Construct注入),setter注入,基于注解的注入(接口注入)

setter方式

通过对应变量的setXXX()方法以及在方法上面使用注解,来完成依赖注入。
Setter方法注入是通过在类中提供setter方法来注入依赖项的。Spring容器会调用这些setter方法来设置依赖项的值。这种方式更加灵活,因为可以在对象创建后的任何时候注入依赖项。

比如:在 Spring 4.3 及以后的版本中,setter 上面的 @Autowired 注解是可以不写的。

private Helper helper;
@Autowired
public void setHelper(Helper helper) {
    this.helper = helper;
}

优点:

缺点:

构造方法注入

将各个必需的依赖全部放在带有注解构造方法的参数中,并在构造方法中完成对应变量的初始化,这种方式,就是基于构造方法的注入。
比如:在 Spring 4.3 及以后的版本中,如果这个类只有一个构造方法,那么这个构造方法上面也可以不写 @Autowired 注解。

private final Svc svc;
@Autowired
public HelpService(@Qualifier("svcB") Svc svc) {
    this.svc = svc;
}

优点:

缺点:

基于注解(字段)的注入

示例

public class MyService {
    @Autowired
    private MyRepository repository;
}

优点:

缺点:根据Spring官方的建议,推荐使用构造器注入和Setter注入,而尽量避免使用字段注入。字段注入被认为是一种不太理想的方式,因为它具有以下缺点:

推荐@Resource而不是@Autowired注解

IOC设计体系

流程图

IOC初始化流程

Bean实例化(生命周期,循环依赖等)

最终的将Bean的定义即BeanDefinition放到beanDefinitionMap中,本质上是一个ConcurrentHashMap<String, Object>;
并且BeanDefinition接口中包含了这个类的Class信息以及是否是单例等;

解决循环依赖问题

Spring如何解决循环依赖问题

Spring只是解决了单例模式下属性依赖的循环问题:Spring为了解决单例的循环依赖问题,使用了三级缓存。

三级缓存详细:见这篇

Spring为什么不能解决多例的循环依赖:多实例Bean是每次调用一次getBean都会执行一次构造方法并且给属性赋值,根本没有三级缓存,因此不能解决循环依赖

Spring为什么不能解决prototype作用域循环依赖:spring不会缓存prototype作用域的bean,而spring中循环依赖的解决正是通过缓存来实现的

生成代理对象产生的循环依赖,解决方法很多,主要有:

使用@DependsOn产生的循环依赖:这类循环依赖问题要找到@DependsOn注解循环依赖的地方,迫使它不循环依赖就可以解决问题。

Spring中Bean的生命周期

Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期

Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:(结合上图,需要有如下顶层思维)

到此这篇关于Spring IOC详解的文章就介绍到这了,更多相关Spring IOC详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文