强!美团大牛纯手写的Spring IOC思维导图及源码笔记,收藏一波!

368 阅读6分钟

Hello,今天给各位童鞋们分享Spring IOC,赶紧拿出小本子记下来吧!

image.png

Spring IOC

什么是IOC

IOC是Inversion of Control的缩写,直译为控制反转。简单的说就是当我们需要一个对象时,不再由我们自己手动去创建,而是让框架代替我们去创建,把控制权交给框架,也就是控制反转。

IOC又可以叫DI(Dependency Injection),直译为依赖注入。将我们需要依赖的的对象由框架自动注入。

引入IOC最主要的目的就是为了实现对象间的解耦。

什么是Bean

在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是一个由Spring IOC容器实例化、组装和管理的对象。

虽说bean在Spring中指的是对象,但JavaBean却是一种类,两者非常容易混淆,所以我通常还是习惯于将由IoC容器管理的对象的类称为bean

第一个Spring程序

新建一个maven项目

image.png

  • 导入spring-context依赖

org.springframework

spring-context

5.2.8.RELEASE

  • 新建一个UserService类,内容如下

public class UserService {

public void test(){

    System.out.println("我是userService的test方法");

}

}

  • 新建一个配置文件夹resources,并在里面新建一个配置文件spring.xml(名字无所谓),内容如下

image.png

  • 新建一个启动类starter,内容如下:

public class Starter {

public static void main(String[] args) {

    // 创建Spring的上下文环境(Spring IOC 容器),并负责实例化,配置和组装Bean

    ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");

    // 创建bean,传入bean的id

    UserService userService = (UserService) ac.getBean("userService");

    userService.test();

}

}

  • 运行程序,可以查看到控制台输出我是userService的test方法。

通过这个简单的示例程序,我们可以看到,我们没有new一个UserService对象,但却拿到该对象,说明这个对象是由spring帮我们实例化的,这就是IOC。

加载配置文件

主要有两种方式,一种通过相对路径,一种通过绝对路径,但一般我们都使用相对路径。这两种方式都支持一次性写入多个配置文件。

相对路径:

ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");// 单个

ApplicationContext ac = new ClassPathXmlApplicationContext("spring01.xml", "spring02.xml");// 多个

绝对路径:

ApplicationContext ac = new FileSystemXmlApplicationContext("C:/.../.../src/main/resources/spring.xml");

虽然可以这样这两种方式都可以配置多个文件,但在需要配置多个文件时,我们通常会设置一个总的配置文件,在总配理文件中导入需要加载的配置文件。总配置文件如下

image.png

Bean的实例化

构造器实例化:就是我们上面的例子中的,默认是通过无参构造器进行实例化,比较常用,例如:

静态工厂实例化:通过工厂方法进行实例化,需要先写一个静态工厂,并配置factory-method,例如:

public class MyFactory {

/*定义对应的工厂方法,返回实例化对象*/

public static UserService createUserService(){

    return new UserService();

}

}

实例化工厂实例化:工厂方法为非静态的,且需要先将实例化工厂实例化为bean,并配置factory-method和factory-bean,例如:

public class MyFactory {

/*定义对应的工厂方法,返回实例化对象*/

public UserService createUserService(){

    return new UserService();

}

}

手动注入(手动装配)

即通过配置文件进行依赖注入,常用的set方法注入,构造器注入两种。首先我们定义一个UserDAO,其被UserService依赖,如下

public class UserDAO {

public void test(){

    System.out.println("我是UserDAO的test");

}

}

set方法注入

这种方法需要提供依赖的set方法,例如

image.png 配置文件通过需要property标签,对依赖进行手动注入,例如

image.png 若需要注入int或String等类型的依赖,可以将ref属性换成value属性,其他一样。

构造器注入

需要提供对应的带参构造器,例如

image.png

<!--name:构造器中的参数名,ref:对应的bean  -->

<constructor-arg name="userDAO" ref="userDAO"/>

自动注入(自动装配)

除了通过配置文件进行依赖注入外,我们还可以通过注解的方式进行依赖注入,即自动装配。

首先,我们需要修改配置文件,开启自动装配,如下

image.png 实现自动注入主要有两个注解:Resource和Autowired,将他们注解在需要注入的bean上即可,也可以注解在bean的set方法上。

Resource

  1. 默认会根据bean的id查找,属性名最好与bean标签id属性值相等
  2. 如果根据id未找到,则会根据类型(Class)查找
  3. 可以设置注解的name属性,name属性值必须与bean标签的id属性值保持一致
  4. 如果注入的是接口,且有多个实现类,则需要使用name属性指定id

image.png

Autowired

  1. 默认通过类型(Class类型)查找bean对象,与属性字段的名称无关
  2. 可以与Qualifie注解结合使用,通过value属性值查找bean对象,value属性值必须要设置,且值要与bean标签的id属性值对应

image.png

扫描器

实际的开发中,bean的数量非常多,采用手动配置bean的方式已无法满足生产需要,Spring这时候同样提供了扫描的方式,对扫描到的bean统一进行管理,简化开发配置,提高开发效率。

使用扫描器首先需要设置扫描范围,指定需要由容器统一管理的包,例如

image.png 然后,我们只需要在包中的类前加上对应的注解,即可自动扫描进容器,主要有以下四个注解

  1. Repository:用于DAO层
  2. Service:用于服务层
  3. Controller:用于控制层
  4. Component:用于任意类,如工具类等

@Repository

public class UserDAO {

public void test(){

    System.out.println("我是UserDAO的test");

}

}

Bean的作用域

主要分别为两种,单例作用域和原型作用域,默认是单例作用域。

单例(singleton)作用域:

image.png 其中,lazy-init是懒加载,当lazy-init为true时,当程序调用时才会去实例化该bean对象,默认为false

所有的bean对象都是单例,因为是默认配置,所以不需要写啥。

2.原型(prototype)作用域:当每次使用时,都会创建一个新的bean对象,不会缓存。需要配置scope="prototype",例如

Bean的生命周期

主要分为四个阶段:

定义:在配置文件中定义bean标签,设置对应的id等属性

创建:在Spring容器中,默认在启动时就会创建所有的bean对象,除非lazy-init="true"。若在创建时需要执行一些操作,可以在bean标签中设置init-method为初始化函数,例如:

使用:使用getBean获取bean对象进行使用

销毁:在bean中设置destroy-method为销毁函数,并通过AbstractApplicationContext对象,调用其close方法销毁bean(若不使用close方法,在项目结束时也不会销毁bean),例如

image.png 好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们