Spring IOC
1.1spring概述及IOC概念
-
spring特点
-
开源的免费的框架
-
轻量级的、非侵入式的框架
-
提供了控制反转、面向切面编程的功能
-
支持事务处理、支持大多数框架的整合
-
配置十分繁琐
-
-
spring七大模块
-
图例
![]()
-
详解
-
核心容器(Spring Core):核心容器提供Spring框架的基本功能即依赖注入
-
应用上下文(Spring Context):一个配置文件,用于向Spring框架提供上下文信息,包括国际化、邮件处理等企业级功能
-
面向切面编程(Spring AOP):提供面向切面编程的功能
-
JDBC和DAO模块(Spring DAO):提供了模块化编写DAO层代码的功能
-
对象实体映射(Spring ORM):提供了整合ORM框架实现对象实体相互映射的功能
-
Web模块(Spring Web):提供了基于应用上下文的web上下文
-
MVC模块(Spring Web MVC):提供了基于Spring实现的MVC框架
-
-
-
IOC相关概念
-
控制反转(IOC),主动创建依赖对象的控制权被反转了,依赖对象不再主动创建,从而降低程序耦合度,增强代码复用性
-
依赖注入(DI),控制反转的一种实现方式,控制权被交于IOC容器,依赖的对象将会被IOC容器以注入的方式添加到需要的地方,一般spring可以通过属性、构造方法或工厂方法的参数来确定依赖
-
set注入:通过set方法的参数来确定依赖,基于set方法,优点是按需注入,可以解决循环依赖问题,但对应属性不能以final修饰,例子如下
-
构造器注入:通过构造方法的参数确定依赖,基于构造方法,优点是减少了对spring的依赖,确保了注入的对象不为空且完成了初始化,同时对于属性会被加上final修饰,并且出现循环依赖时还会抛异常,但构造器的参数可能过长,例子如下
-
field注入(不推荐):通过属性来确定依赖,基于反射,优点是简洁明了,缺点是对spring依赖过高,无法解决循环依赖也不会抛异常,并且对应属性也不能用final修饰,例子如下
-
-
IOC容器,用于管理bean并提供依赖注入的功能,容器会通过读取configuration元数据获取有关objects实例化、配置和汇编的指令,spring中主要提供了具备完整依赖注入功能的BeanFactory与BeanFactory的超集ApplicationContext这两种容器,相较而言,ApplicationContext还会提供一些类似于国际化等的企业级功能,并且其单例bean默认非懒加载
-
Configuration元数据:是对objects创建、管理的一些描述,如该object是否为bean、是singleton还prototype、其属性是否需要注入,应该注入何种对象等,元数据可以为XML、Java注解、Java代码
-
XML,不安全、查找类不方便、可读性差、配置不简洁、修改配置不用重编译、非侵入、自由度低、可注入非自己创建的类
-
Java注解,安全、方便、可读性很好、配置十分简洁、修改配置要重编译、侵入、自由度高、不可注入非自己创建的类
-
Java配置,安全、不方便、可读性一般、配置比较简洁、修改配置要重编译、非侵入、自由度非常高、可以注入非自己创建的类
-
-
使用实例
//bean类
-
-
bean,是对象,IOC容器基于我们提供给它的configuration来实例化、组装和管理这些对象,常见的元数据及对应信息如下
-
beanDefinition:一个用于存储bean相关信息的对象,如bean的类名、scope、属性、构造函数的,Spring容器启动时会通过beanDefinitionReader去获取各个bean相关属性和配置信息并将它们存放在对应的beanDefinition中,然后将这些beanDefinition存放在map中,之后根据beanDefinition中的类名、构造函数、构造函数参数,使用反射就可以创建对应的bean了,非懒加载的bean会在此时直接创建并存放在另一个map便于之后直接获取使用
-
FactoryBean:工程bean,也由Spring容器管理,可以生产和修饰一些bean,若对AOP中对应类加以修饰形成所需的bean
-
bean生命周期图
![]()
-
-
Spring循环依赖解决方式
-
前提:
-
Spring实例化bean会分三步,分别为调用构造方法实例化,通过set方法填充属性,通过init方法对bean初始化
-
bean存放于三级缓存中,一级缓存,用于存放完全初始化好的bean,二级缓存尚未填充属性的bean,三级存放正在实例化的bean,Spring会从一级到三级去尝试获取到对应bean
-
-
循环依赖解决过程如下
-
A创建过程中需要 B,于是A将自己放到三级缓里面,去实例化B
-
B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了,则将其作为自己的注入属性
-
然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A
-
B 顺利初始化完毕,将自己放到一级缓存里面,此时B里面的A依然是创建中状态
-
-
然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面
-
-
-
自动装配常见值及解释
-
no,默认值,即不进行自动装配,需要通过注解如@Autowire来主动指明该属性、方法需要主动装配
-
byName,按照beanName进行自动装配,使用setter注入
-
byType,按照beanClass进行自动装配,使用setter注入
-
constructor,类似于byType,不过通过构造器注入
-
-
1.2IOC中常用注解
-
声明bean的相关注解
-
作用于类上的注解
-
@Component,通用注解,当不知道这个类属于哪一层的时候可以通过该注解来标明为bean,这些bean的默认名称为第一个字母小写的类名,类型就是注解作用类的类型
-
@Controller,组合了@Component的注解,用于声明控制层的类为bean
-
@RestController,组合了@Controller和@ResponseBody的注解,同样用于声明控制层的类为bean,并指明该类返回的是数据而非视图,数据默认是json格式
-
@Service,组合了@Component的注解,用于声明服务层的类为bean
-
@Repository,组合里@Component的注解,用于声明数据访问层的类为bean
-
-
作用域方法上的注解
-
@Bean,用于指明对应方法的返回值为一个bean,需要配合@Configuration使用,该bean的名称默认为方法的名称,类型为方法的返回类型,其详尽信息如下
-
-
-
修饰bean的相关注解
-
@Scope,用于指明bean的作用域,常见作用域如下
-
singleton,默认值,单例,全局有且仅有一个实例
-
prototype,原型,每次获取Bean的时候都会创建一个新的实例
-
request,针对每一次http请求都会产生一个新的bean,同时该bean只在此次http请求内有效
-
session,针对每一次无bean的http请求都会产生一个新的bean,同时该bean只在此个session中有效
事实上90%以上的业务使用singleton即可,这也就是为什么Spring用singleton作为默认值,不过由于singleton保证了全局只有一个实例,使得如果实例中有非静态变量时,会因共享资源的竞争而导致线程安全问题,当然因为是单例所以不用频繁GC,同时也会节省内存,使得总体性能会有所提升,@Scope实现如下
-
-
@Primary,指明该bean为首选bean,当有多个符合要求的bean时会首先选择该个bean
-
@Qualify,可在注解中写入名称来详细指明注入的bean,如@Qualify("firstBean")就是指明注入一个名称为firstBean的bean
-
@Profile,组合了@Condition的注解,指明bean的方法或bean在什么情况下起作用,如@Profile("test")需要在spring.profiles.active = test时才有效,对于Springboot可以直接在application.profiles中设置,也可以通过容器的getEnvironment().setActiveProfiles("test")方法设置
-
-
配置类的相关注解
-
@Configuration,指明该类为bean并将其设置为配置类,配置类中可以有多个返回bean的方法,这些方法需要用@Bean注释
-
@Import,用于导入其他多个配置类到一个配置类中,如@Import({Config.clsss,BasicConfig.clss})就是将Config和BasicConfig两个配置类导入到当前配置类中
-
@PropertyResource,用于导入相应的资源文件,可以配合@Value来获取对应的资源信息,其属性为文件的路径,需要加上classpath:来指明是类路径,如@PropertyResource("classpath:test.properties"),在maven项目中就是导入resources目录下的test.properties文件
-
@ComponentScan,用于指明扫描的范围,地址是以类路径起始的,如@ComponentScan("basic")就是在maven项目中扫描Java包下的basic包中的所有文件,默认扫描该类所在包及其子包中的所有类
-
-
注入bean和属性的相关注解
-
@Autowired,用于装配bean,默认按类型装配,详情如下
-
@Resource,JDK1.6支持的注解,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名为名称来按照名称查找,如果注解写在setter方法上默认取属性名作为名称来查找装配,当找不到与名称匹配的bean时才按照类型进行装配,不过只要指定了name属性则只会按照名称进行装配
-
@Value,用于注入资源信息,如MySQL相关配置等,在使用前需要通过@Properties先导入对应的资源文件,使用格式为@Value("${properties文件中对应key值}"),通过它注入属性不需要set方法
-



浙公网安备 33010602011771号