Spring之IOC核心模块详解

Spring IOC简述

IOC称为控制反转,也有一种说法叫DI(依赖注入)。IOC也是spring最核心的模块,Spring的所有工作几乎都围绕着IOC展开。

什么是控制反转呢?简单的说,控制反转就是把我们要做的事情交给别人来做,就像是招了个小弟专门为我们做事情,我们需要做好的东西时直接去找小弟拿。

这里要做的事情就是new 一个对象。我们不再自己去new对象然后使用,而是spring容器帮我们去创建对象然后我们要用的时候直接去拿就行了。spring帮我们

生成对象就是控制反转,而我们要用对象从spring取对象就是依赖注入。

一切的开始要从spring容器的加载说起

我认为一切的开端要从spring 容器开始说起,所有工作都是围绕着Spring容器展开的。

这里只描述两种最常见的加载spring配置文件的方式,其余方式不做描述。

Spring容器是再spring配置文件被加载的一刻生成的。有两种常见加载方式,分别为使用BeanFactroy加载和使用AppilicationContext记载。

BeanFactory

BeanFactory加载spring配置文件又可以称为延迟加载,当BeanFactroy加载完配置文件后,bean并没有生成,而是当第一次使用bean的使用bean才创建。

Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Warehouse warehouse = beanFactory.getBean("warehouse",Warehouse.class);

ApplicationContext

而Applicationcontext加载方式是立即加载方式,BeanFactory有的功能它都有,而它有的功能BeanFactroy不一定有,所以是目前最主流的加载方式。

立即加载的意思就是当配置文件加载,spring容器创建的时候,我们配置好的bean就都创建了,这些bean与容器同生共死。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Warehouse warehouse = applicationContext.getBean("warehouse",Warehouse.class);

容器加载完后就得谈谈bean的创建了

bean有三种创建方式:

默认无参构造函数创建、静态工厂创建、实例工厂创建

默认无参创建方式

也是最常用的创建方式。我们定义一个实体类时默认有一个无参构造函数,可以不用创建。

//实体类public class User {
    private String name;
    private int age;
    //get set...
}

//bean创建<bean id="user" class="springIOCTest.User"/>

但是当我们定义的实体类有带参构造函数时就得显式的为其创建一个无参构造函数,否则bean创建失败

public class User {
    private String name;
    private int age;

    public User() {

    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // get set...
}

静态工厂创建bean

首先的先定义一个静态工厂类

public class StaticFactroy {
    private User user;
    public static User getUser() {
        return new User();
    }
}

在创建bean的时候类路径选择静态工厂类路径,指定factory-method

<bean id="user" class="springIOCTest.StaticFactroy" factory-method="getUser"/>

实例工厂创建bean

定义一个普通工厂类

public class InstanceFactory {
    private User user;
    public User getUser() {
        return new User();
    }
}

在创建bean的时候先创建工厂bean,再根据工厂bean创建我们需要的bean

<bean id="instanceFactroy" class="springIOCTest.InstanceFactory"/>
<bean id="user" factory-bean="instanceFactroy" factory-method="getUser"/>

虽然我们知道了如何创建一个bean,但是我们每个bean里面可能有很多属性,需要我们去注入。

接下来谈谈bean的注入方式

每当我们new一个对象的时候,经常需要给它里面的属性设值或者传递引用,spring也可以帮我们完成这项工作

比如我们要为上面的User类的name属性和age属性注入值。那么有两种方式注入:属性注入和构造函数注入

首先做下准备工作,为User类加个实体属性:

public class User {
    private String name;
    private int age;
    private UserSon mySon;
    // get set...
}

属性注入

属性注入就是我们平常new 一个对象后setxxx

<bean id="mySon" class="springIOCTest.UserSon"/>
<bean id="user" class="springIOCTest.User">
   <property name="name" value="张三"/>
   <property name="age" value="18"/>
   <property name="mySon" ref="mySon"/>
</bean>

可以看到属性中包含实体类的时候必须先创建一个该类的bean,然后通过ref的方式注入

 构造函数注入

public class User {
    private String name;
    private int age;
    private UserSon mySon;
    public User(String name, int age, UserSon mySon) {
        this.name = name;
        this.age = age;
        this.mySon = mySon;
    }
    // get set...
}
<bean id="mySon" class="springIOCTest.UserSon"/>
    <bean id="user" class="springIOCTest.User">
    <constructor-arg index="0" name="name" value="张三"/>
    <constructor-arg index="1" name="age" value="18"/>
    <constructor-arg index="2" name="mySon" ref="mySon"/>
</bean>

构造函数注入的前提时提供对应的构造函数,但是使用构造函数容易产生一个问题,那就是循环依赖问题

循环依赖问题

当使用构造函数注入的时候可能会出现一下一种情况

public class UserSon {
    private User father;

    public UserSon(User father) {
        this.father = father;
    }
    //get set..
}

User实体类需要注入UserSon实例,而UserSon实体类也需要注入User实例,那么在生成bean的时候会出现以下情况

<bean id="mySon" class="springIOCTest.UserSon">
    <constructor-arg index="0" name="father" ref="user"/>
</bean>
<bean id="user" class="springIOCTest.User">
   <constructor-arg index="0" name="name" value="张三"/>
   <constructor-arg index="1" name="age" value="18"/>
   <constructor-arg index="2" name="mySon" ref="mySon"/>
</bean>

这样就形成了死胡同,类时死锁,这时候就会报错。

解决办法很简单,改为属性注入方式即可。

因此,使用构造函数注入的时候可能会产生问题,又比较麻烦,所以实际场景中使用属性注入是比较常见的

到这里我们就讲完了如何完整的创建一个bean了,接下来就来谈谈bean的生命周期吧

bean的生命周期

未完待续。。。

原文地址:https://www.cnblogs.com/czsy/p/10843163.html

时间: 2024-10-07 06:00:16

Spring之IOC核心模块详解的相关文章

Spring Boot源码中模块详解

Spring Boot源码中模块详解 一.源码 spring boot2.1版本源码地址:https://github.com/spring-projects/spring-boot/tree/2.1.x 二.模块 Spring Boot 包含许多模块,以下是一些简单的概述: 1,spring-boot 为Spring Boot其他部分功能提供主要的lib包,其中包含:(1)SpringApplication类提供了静态便利的方法使编写独立的SpringApplication更加容易.它唯一的任

Spring IOC源码详解之容器依赖注入

Spring IOC源码详解之容器依赖注入 上一篇博客中介绍了IOC容器的初始化,通过源码分析大致了解了IOC容器初始化的一些知识,先简单回顾下上篇的内容 载入bean定义文件的过程,这个过程是通过BeanDefinitionReader来完成的,其中通过 loadBeanDefinition()来对定义文件进行解析和根据Spring定义的bean规则进行处理 - 事实上和Spring定义的bean规则相关的处理是在BeanDefinitionParserDelegate中完成的,完成这个处理需

Spring IOC源码详解之容器初始化

Spring IOC源码详解之容器初始化 上篇介绍了Spring IOC的大致体系类图,先来看一段简短的代码,使用IOC比较典型的代码 ClassPathResource res = new ClassPathResource("beans.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDe

Redis实战和核心原理详解(5)使用Spring Session和Redis解决分布式Session跨域共享问题

Redis实战和核心原理详解(6)使用Spring Session和Redis解决分布式Session跨域共享问题 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用的均衡算法有IP_Hash.轮训.根据权重.随机等.不管对于哪一种负载均衡算法,由于Nginx对不同的请求分发到某一个Tomcat,Tomcat在运行的时候分别是不同的容器里,因此会出现session不同步或者丢失的问题. 实际上实现Session共享的方案很多,其中一种常用的就是使用Tomcat.Jetty等服务器提

SpringBoot启动机制(starter机制)核心原理详解

作者:MyBug 一.前言 使用过springboot的同学应该已经知道,springboot通过默认配置了很多框架的使用方式帮我们大大简化了项目初始搭建以及开发过程.本文的目的就是一步步分析springboot的启动过程,这次主要是分析springboot特性自动装配.那么首先带领大家回顾一下以往我们的web项目是如何搭建的,通常我们要搭建一个基于Spring的Web应用,我们需要做以下一些工作:pom文件中引入相关jar包,包括spring.springmvc.redis.mybaits.l

Spring中的jar包详解

下面给大家说说spring众多jar包的特点吧,无论对于初学spring的新手,还是spring高手,这篇文章都会给大家带来知识上的收获,如果你已经十分熟悉本文内容就当做一次温故知新吧.spring.jar 是包含有完整发布的单个jar包,spring.jar中除了spring-mock.jar里所包含的内容外其他所有jar包的内容,因为只有在研发环境下才会用到spring-mock.jar来进行辅助测试,正式应用系统中是用不得这些类的. 除了spring.jar文件,Spring还包括有其他1

Spring Boot的启动器Starter详解

Spring Boot的启动器Starter详解 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs Spring Boot应用启动器基本的一共有44种,具体如下: 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2)spring-boot-starter-actuator 帮助监控和管理应用. 3)spring-boot-starter-amqp 通

第二十天 TCP 及socket通信原理、http协议及web服务、httpd核心配置详解

一.TCP及socket通信原理详解 二.http协议及web服务原理(一) 三.http协议及web服务原理(二) 四.httpd核心配置详解 1.tcp.udp是一种传输协议,实现进程地址标记,套接字是一个虚拟设备,用来表明主机上的某个进程      众所周知:0-1023:管理员才有权限使用,永久地分配给某应用使用(由IANA分配)      注册端口:1024-41951:只有一部分被注册,分配原则上非特别严格.      动态端口或私有端口:41952-65535:由内核分配临时端口,

超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享

原创不易,转载请注明出处:超轻量级DI容器框架Google Guice与Spring框架的区别教程详解及其demo代码片段分享 代码下载地址:http://www.zuidaima.com/share/1759689106541568.htm 依赖注入,DI(Dependency Injection),它的作用自然不必多说,提及DI容器,例如spring,picoContainer,EJB容器等等,近日,google诞生了更轻巧的DI容器--Guice! 废话不多讲了,先看看Guice是如何实现