专栏首页chenchenchenSpring IOC原理

Spring IOC原理

  • 回顾以前对象依赖
  • Spring依赖注入
  • IOC控制反转

回顾以前对象依赖

传统的实现,需要自己new对象,然后给对象属性赋值,一旦有改动,特别麻烦。

class  UserService{
    UserDao userDao = new UserDao();
}

后来,使用DaoFactory,通过字符串创建对应的对象。

    private UserDao userDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.UserDaoImpl", UserDao.class);
    

public class DaoFactory {

    private static final DaoFactory factory = new DaoFactory();
    private DaoFactory(){}

    public static DaoFactory getInstance(){
        return factory;
    }

    public <T> T createDao(String className,Class<T> clazz){
        try{
            T t = (T) Class.forName(className).newInstance();
            return t;
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

再后来,我们在DaoFactory中读取配置文件,根据配置文件来创建对象

    UserDao dao = DaoFactory.getInstance().createUserDao();
    
    
public class DaoFactory {

    private  UserDao userdao = null;

    private DaoFactory(){
        try{
            InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
            Properties prop = new Properties();
            prop.load(in);

            String daoClassName = prop.getProperty("userdao");
            userdao = (UserDao)Class.forName(daoClassName).newInstance();

        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static final DaoFactory instance = new DaoFactory();

    public static DaoFactory getInstance(){
        return instance;
    }


    public UserDao createUserDao(){
        return userdao;
    }

}

Spring依赖注入

对象之间的依赖关系,其实就是给对象上的属性赋值!因为对象上有其他对象的变量,因此存在了依赖。

Spring提供了好几种的方式来给属性赋值

  • 构造函数注入,实现强制依赖。
  • 属性注入setter()方法,实现可选依赖。
  • 自动装配(xml/注解)。
  • 工厂方法接口注入,遗留方法。

构造函数给属性赋值

在serice中加入一个构造函数,参数就是userDao

public class UserService {

    private UserDao userDao; 

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}

applicationContext.xml配置文件

    <!--创建userDao对象-->
    <bean id="userDao" class="UserDao"/>

    <!--创建userService对象-->
    <bean id="userService" class="UserService">
        <!--要想在userService层中能够引用到userDao,就必须先创建userDao对象-->
        <constructor-arg index="0" name="userDao" type="UserDao" ref="userDao"></constructor-arg>
    </bean>

通过set方法给属性注入值

在service层通过set方法来把userDao注入到UserService中

public class UserService {

    private UserDao userDao; 

    public void setUserDao(String userId,String userName) {
    	UserDao userDao = new UserDao();
    	userDao.setId(userId);
    	userDao.setName(userName);
        this.userDao = userDao;
    }
}

applicationContext.xml配置文件:通过property节点来给属性赋值,引用类型使用ref属性,基本类型使用value属性。

    <!--创建userDao对象-->
    <bean id="userDao" class="UserDao"/>

    <!--创建userService对象-->
    <bean id="userService" class="UserService">
        <property name="userDao" ref="userDao"/>
    </bean>

内部Bean

先创建userService,发现userService需要userDao的属性,再创建userDao。缺点是如果Bean要多次被使用的话,就要多次配置。

applicationContext.xml配置文件:property节点内置bean节点

    <!--
        1.创建userService,看到有userDao这个属性
        2.而userDao这个属性又是一个对象
        3.在property属性下又内置了一个bean
        4.创建userDao
    -->
    <bean id="userService" class="UserService">
        <property name="userDao">
            <bean id="userDao" class="UserDao"/>
        </property>
    </bean>

p 名称空间注入属性值

applicationContext.xml配置文件:使用p名称空间

    <bean id="userDao" class="UserDao"/>

    <!--不用写property节点了,直接使用p名称空间-->
    <bean id="userService" class="UserService" p:userDao-ref="userDao"/>

自动装配

自动装载默认是不打开的,修改applicationContext.xml配置文件使其生效。

byName:通过参数名自动装配,装配和该bean的属性具有相同名字的bean。

    <bean id="userDao" class="UserDao"/>

    <!--
        1.通过名字来自动装配
        2.发现userService中有个叫userDao的属性
        3.看看IOC容器中没有叫userDao的对象
        4.如果有,就装配进去
    -->
    <bean id="userService" class="UserService" autowire="byName"/>

byType:通过参数类型自动装配,装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。

    <bean id="userDao" class="UserDao"/>

    <!--
        1.通过名字来自动装配
        2.发现userService中有个叫userDao的属性
        3.看看IOC容器UserDao类型的对象
        4.如果有,就装配进去
    -->
    <bean id="userService" class="UserService" autowire="byType"/>

@Resource默认通过反射按名称装配,找不到才按类型装配。 使用name属性指定byName策略,使用type属性指定byType策略。

@Autowired注解来实现自动装配。 默认按类型装配。结合@Qualifier(“name”)按照名称装配。required属性为false时允许null值。

  • 写在属性上,先根据属性的类型(byType)去Spring容器找对应类型的bean,找到多个再根据属性的名字确定,再通过反射的方式赋值给这个属性。
  • 写在setter方法上,会根据setter方法的参数类型去找bean, 找到多个再根据属性的名字筛选,再调用set方法进行赋值。
@Component
public class UserService {

    @Autowired
    private UserDao userDao ;

//    @Autowired
//    public void setUserDao(UserDao userDao) {
//        this.userDao = userDao;
//    }
}

IOC控制反转

**Spring使用依赖注入来实现对象之间的依赖关系 ** DI dependency injection。

Spring将对象的创建交给外部容器完成称为控制反转 IOC Inversion of Control。

这个外部容器就是IOC容器

使用IOC的优点:

  1. 实现代码之间的解耦,提高程序的灵活性和可维护性。
  2. IOC容器支持加载服务时的饿汉式初始化和懒加载。
  3. 对象不用自己组装,拿来就用。
  4. 享受单例的好处,效率高,不浪费空间。
  5. 统一配置,便于修改。
  6. 便于单元测试,方便切换mock组件。
  7. 便于进行AOP操作,对于使用者是透明的。

缺点:对象生成因为是使用反射编程,在效率上有损耗

IOC容器的原理

IOC容器是个Bean工厂,管理我们所有的对象以及依赖关系。

  • 通过Java的反射技术获取类的所有信息(成员变量、类名等)
  • 通过配置文件(xml)或者注解来描述类与类之间的关系
  • 最后构建出对应的对象和依赖关系

Spring IOC容器实现对象的创建和依赖的步骤:

  1. 根据Bean配置信息在容器内部创建Bean定义注册表
  2. 根据注册表加载、实例化bean、建立Bean与Bean之间的依赖关系
  3. 将这些准备就绪的Bean放到Map缓存池中,等待应用程序调用,getBean获得实例

IOC容器装配Bean方法

IOC容器是工厂模式的一个实现,提供了控制反转功能,用来把应用的配置和依赖从真正的应用代码中分离。可简单分成两种:

  • BeanFactory
    • 这是最基础、面向Spring的
  • ApplicationContext
    • 建立在 BeanFactory 基础之上,提供抽象的面向应用的服务。
      • MessageSource,提供国际化的消息服务,扩展类 MessageResource 接口
      • 资源访问,如 URL 和文件
      • 事件传播
      • 载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,比如应用的 web 层。

区别:

  • BeanFactory:是延迟加载,如果 Bean 的某一个属性没有注入,BeanFactory 加载后,直至第一次使用调用 getBean 方法才会抛出异常
  • ApplicationContext:则在初始化自身时检验,这样有利于检查所依赖属性是否注入;所以通常情况下使用 ApplicationContext。

参考:

Spring入门这一篇就够了:https://mp.weixin.qq.com/s/gGzgLaiTzpGemPw_h_r-Hw

Spring【依赖注入】就是这么简单:https://mp.weixin.qq.com/s/7eAnJw10VHdt6N5ZteTMhg

Spring IOC知识点一网打尽:https://mp.weixin.qq.com/s/TYftOpe6J1Y4EDNDxKKqXg

Spring思维导图(ioc篇):https://segmentfault.com/a/1190000017348726

Spring的IOC,属性注入,bean的理解:https://blog.csdn.net/weixin_41737632/article/details/109615913

SpringIOC和AOP原理 设计模式:https://www.jianshu.com/p/40d0a6ad21d2

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 白话Spring的IoC原理

    1. IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。...

    用户1263954
  • Spring IOC原理补充(循环依赖、Bean作用域等)

    通过之前的几篇文章将Spring基于XML配置的IOC原理分析完成,但其中还有一些比较重要的细节没有分析总结,比如循环依赖的解决、作用域的实现原理、BeanPo...

    夜勿语
  • Spring 介绍和ioc原理

    用户5927264
  • spring原理案例-基本项目搭建 03 创建工程运行测试 spring ioc原理实例示例

    使用 Java EE - Eclipse 新建一 Dynamic Web Project

    noteless
  • 一文带你深入剖析Spring IOC 实现原理

    IOC是“Inversion of Control”的缩写,翻译过来就是“控制反转”。

    Java程序猿
  • 深圳Java培训:Spring框架之IOC原理

    Spring框架是我们进行企业级开发的最常用框架,本章我们将了解Spring框架,并学习Spring的IOC特性以及IOC的实现原理:注解和反射。

    深圳java培训技术
  • Spring IOC和DI原理讲解并制作LazyCoder版的Spring (二)

    最近,给项目组成员培训了Spring 控制反转和依赖注入的原理,并自己做了个Lazy Coder版的Spring,现在给大家分享下,相互学习,有说得不对的欢迎指...

    甲蛙全栈
  • Spring IOC和DI原理讲解并制作LazyCoder版的Spring (一)

    最近,给项目组成员培训了Spring 控制反转和依赖注入的原理,并自己做了个Lazy Coder版的Spring,现在给大家分享下,相互学习,有说得不对的欢迎指...

    甲蛙全栈
  • 阿里三面:说说你对Spring ioc启动原理的理解!

    来看一下传统的干活方式:在对象单一职责原则的基础上,一个对象很少有不依赖其他对象而完成自己的工作,所以这个时候就会出现对象之间的依赖。而体现在我们的开发中,就是...

    Java程序猿
  • Spring,IOC理解

    **假设一个场景:**目前有三个角色,买水果的人(用户),卖水果的人(业务层),水果(持久化层)

    用户8785253
  • Spring核心——IOC处理器扩展 原

    Spring一直标注自己是一个非侵入式框架。非侵入式设计的概念并不新鲜,目标就是降低使用者和框架代码的耦合,毕竟框架的开发者和使用者几乎肯定不是同一个团队。Sp...

    随风溜达的向日葵
  • 【死磕 Spring】----- IOC 之深入理解 Spring IoC

    在一开始学习 Spring 的时候,我们就接触 IoC 了,作为 Spring 第一个最核心的概念,我们在解读它源码之前一定需要对其有深入的认识,本篇为【死磕 ...

    用户1655470
  • 三条路线告诉你如何掌握Spring IoC容器的核心原理

    前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主...

    Java后端技术
  • Spring5–01–Spring5框架概述

    Java架构师必看
  • Spring(2)——Spring IoC 详解

    Spring IoC 概述 IoC:Inverse of Control(控制反转) 读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,就是将原本在程...

    我没有三颗心脏
  • Spring 中的 IoC 容器

    对于 Java 后端开发而言,Spring 框架的重要性不言而喻。而 Spring 中最核心的无非就是 IoC 和 AOP。

    WriteOnRead
  • Spring IOC的理解

    Sping IoC is Inversion of Control. 控制反转.

    CoffeeLand
  • spring IOC 概念理解

    一、Spring的IoC(Inversion of Control)。 这是Spring中得有特点的一部份。IoC又被翻译成“控制反转”,也不知道是...

    全栈程序员站长
  • Spring学习笔记2_IOC与DI

    本章目录 Spring学习笔记2_IOC与DI 1.Spring的jar包下载 2.Spring开发环境搭建 3.IOC快速入门 4.DI 1.Spring...

    Java学习

扫码关注云+社区

领取腾讯云代金券