javaEE-Spring IOCDI
目录
1、什么是Spring:
2.什么是IoC:
3. 什么是控制反转呢?
4.IoC容器具备以下优点:
5.DI是什么:
依赖注⼊方法:
三种注入方法的优缺点:
@Autowired注解注入存在的问题:
@Autowired和@Resource的区别:
6.IoC和DI的使用:
7.Bean的存储:
8.Bean的命名:
9.ApplicationContext VS BeanFactory
10.Bean的扫描路径:
10.Spring, Spring Boot 和Spring MVC的关系以及区别:
11.
12.Spring框架中的Bean是否是线程安全的:
1、什么是Spring:
Spring是一个开源框架,他让我们的开发更加简单. 他⽀持⼴泛的应⽤场景, 有着活跃⽽庞⼤的社区
,是包含了众多工具方法的IoC容器。
2.什么是IoC:
IoC: Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器.
IoC 是Spring的核⼼思想,在类上⾯添加 @RestController 和 @Controller 注解, 就是把这个对象交给Spring管理, Spring 框架启动时就会加载该类. 把对象交给Spring管理, 就是IoC思想.
3. 什么是控制反转呢?
获得依赖对象的过程被反转了。也就是说, 当需要某个对象时, 传统开发模式中需要⾃⼰通过 new 创建对象, 现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊ (Dependency Injection,DI)就可以了.
这个容器称为:IoC容器. Spring是⼀个IoC容器, 所以有时Spring 也称为Spring 容器.
4.IoC容器具备以下优点:
资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。
第⼀,资源集中管理,实现资源的可配置和易管理。IoC容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从IoC容器中去取就可以了
第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。我们在创建实例的时候不需要了解其中的细节。
Spring 就是⼀种IoC容器, 帮助我们来做了这些资源管理.
5.DI是什么:
DI: Dependency Injection(依赖注⼊)
容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。程序运⾏时需要某个资源,此时容器就为其提供这个资源。简单来说, 就是把对象取出来放到某个类的属性中.
从这点来看, 依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。可以说, DI 是IoC的⼀种实现.
依赖注⼊方法:
Spring也给我们提供了三种⽅式:
1. 属性注⼊(Field Injection):使用@Autowired实现
2. 构造⽅法注⼊(Constructor Injection):在类的构造⽅法中实现注⼊,搭配@Autowired注解
注意事项:如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法
3. Setter 注⼊(Setter Injection):和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解 。
三种注入方法的优缺点:
属性注入:
优点:代码简介,使用简单。
缺点:只能作用于 IoC容器,不能注入final修饰的类。
构造方法注入:
优点:可以注⼊final修饰的属性 ; 注⼊的对象不会被修改;依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法;通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的。
缺点: 注⼊多个对象时, 代码会⽐较繁琐
• Setter注⼊
优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
缺点: 不能注⼊⼀个Final修饰的属性;注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险
@Autowired注解注入存在的问题:
当同⼀类型存在多个bean时,仅通过类 类型注入时,会找到非唯一的Bean对象。
可以通过一下方法解决:
1. @Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现.
2. @Qualifier注解:通过该注解的value属性,指定当前要注入的Bean的名称;不能单独使用,要搭配@Autowired注解使用。
3.@Resource注解:按照Bean的名称注入,通过name属性指定要注入的Bean的名称。
@Autowired和@Resource的区别:
相同点:
1. @Resource和@Autowired都是做bean的注入时使用。
2.两者都可以写在字段和setter方法上;不同点:
1.@Autowired是Spring框架提供的注解;@Resource并不是Spring的注解,是JDK提供的注解,它的包是javax.annotation.Resource,需要导入;
2.@Autowired是按照类型注入的,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用;
@Resource是按照名称注入的,@Resource有两个重要的属性: name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
6.IoC和DI的使用:
Spring 容器 管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由Spring来负责对象的创建和销毁(实现作为容器的存和取的功能).
7.Bean的存储:
要把某个对象交给IOC容器管理,需要在类上添加⼀个注解: @Component ,⽽Spring框架为了更好的服务web应⽤程序, 提供了更丰富的注解:
1. 类注解:@Controller(控制器存储):控制层, 接收请求, 对请求进⾏处理, 并进⾏响应
@Service(服务存储):业务逻辑层, 处理具体的业务逻辑
@Repository(仓库存储):数据访问层,也称为持久层. 负责数据访问操作
@Configuration(配置存储):配置层. 处理项⽬中的⼀些配置信息
@Component(组件存储):该注解是一个元注解,这几个注解是该注解的衍生类。
2. ⽅法注解:@Bean.
分配这么多注解的作用:和应⽤分层是呼应的. 让程序员看到类注解之后,就能直接了解当前类的⽤途。
方法注解的使用场景:
1. 使⽤外部包⾥的类, 没办法添加类注解
2. ⼀个类, 需要多个对象, ⽐如多个数据源 。这种场景, 我们就需要使⽤⽅法注解 @Bean
(方法注解要配合类注解使用)
8.Bean的命名:
程序开发⼈员不需要为bean指定名称(BeanId), 如果没有显式的提供名称(BeanId),Spring容器将为该bean⽣成唯⼀的名称。命名约定使⽤Java标准约定作为实例字段名. 也就是说,bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写.
⽐如:
类名: UserController, Bean的名称为: userController
类名: AccountManager, Bean的名称为: accountManager
当有多个字符并且第⼀个和第⼆个字符都是⼤写时, 将保留原始的⼤⼩写。
⽐如
类名: UController, Bean的名称为: UController
类名: AManager, Bean的名称为: AManager
9.ApplicationContext VS BeanFactory
获取bean对象, 是ApplicationContext的⽗类BeanFactory提供的功能。
• 继承关系和功能⽅⾯来说:
Spring 容器有两个顶级的接⼝:BeanFactory 和ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能⼒,⽽ApplicationContext 属于 BeanFactory 的⼦类,还实现了多个别的接口,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持.
• 从性能⽅⾯来说:延迟加载
1. BeanFactroy 采用的是延迟加载形式来注入 Bean 的,即只有在使用到某个 Bean 时(调用getBean()),才对该 Bean 进行加载实例化。这样,我们就不能发现一些存在的 spring 的配置问题。而 ApplicationContext 则相反,它是在容器启动时,一次性创建了所有的 Bean。这样,在容器启动时,我们就可以发现 Spring 中存在的配置错误
10.Bean的扫描路径:
使⽤五⼤注解声明的bean,要想⽣效, 还需要配置扫描路径, 让Spring扫描到这些注解 也就是通过 @ComponentScan 来配置扫描路径。
在之前的使用中@ComponentScan 注解虽然没有显式配置,但也访问成功了,是因为该注解已经包含在了启动类声明注解@SpringBootApplication 中了,默认扫描的范围是SpringBoot启动类所在包及其⼦包,在配置类上添加 @ComponentScan 注解, 该注解默认会扫描该类所在的包下所有的配置类。
10.Spring, Spring Boot 和Spring MVC的关系以及区别:
Spring:Spring 是⼀个开发应⽤框架,特点是:轻量级、⼀站式、模块化,其⽬的是⽤于简化企业级应⽤程序开发.
Spring的主要功能: 管理对象,以及对象之间的依赖关系, ⾯向切⾯编程, 数据库事务管理, 数据访问, web框架⽀持等。但是Spring具备⾼度可开放性, 并不强制依赖Spring。
Spring MVC: Spring MVC是Spring的⼀个⼦框架, 按照MVC模式设计了⼀个 MVC框架(⼀些⽤Spring 解耦的组件), 主要⽤于开发WEB应⽤和⽹络接⼝,Spring MVC 是⼀个Web框架。
Spring Boot: Spring Boot是对Spring的⼀个封装, 为了简化Spring应⽤的开发⽽出现的,使⽤Spring Boot 可以更加快速的搭建框架, 降级开发成本, 让开发⼈员更加专注于Spring应⽤的开发,⽽⽆需过多关注XML的配置和⼀些底层的实现。
pring MVC和Spring Boot都属于Spring,Spring MVC 是基于Spring的⼀个 MVC 框架,⽽Spring Boot 是基于Spring的⼀套快速开发整合包.
11.
12.Spring框架中的Bean是否是线程安全的:
Spring 框架并没有对单例 Bean 进行任何多线程的封装处理。
关于单例 Bean 的线程安全和并发问题,需要开发者自行去搞定。单例的线程安全问题,并不是 Spring 应该去关心的。 Spring 应该做的是,提供根据配置,创建单例 Bean 或多例 Bean 的功能。但实际上,大部分的 Spring Bean 并没有可变的状态,所以在某种程度上说 Spring 的单例Bean 是线程安全的。如果你的 Bean 有多种状态的话,就需要自行保证线程安全。最浅显的解决办法,就是将多态 Bean 的作用域(Scope)由 Singleton 变更为 Prototype。
13.Spring如何解决循环依赖问题:
循环依赖:循环引用,就是两个或两个以上的bean对象互相持有对方,最终形成了闭环,如:A引用B,B引用C,C又引用A,就形成了循环引用。
处理整个流程大致如下:
1. 首先 A 完成初始化第一步并将自己提前曝光出来(通过 ObjectFactory 将自己提前曝光),在初始化的时候,发现自己依赖对象 B,此时就会去尝试 get(B),这个时候发现 B 还没有被创建出来;
2. 然后 B 就走创建流程,在 B 初始化的时候,同样发现自己依赖 C,C 也没有被创建出来;
3. 这个时候 C 又开始初始化进程,但是在初始化的过程中发现自己依赖 A,于是尝试 get(A)。这
个时候由于 A 已经添加至缓存中(一般都是添加至三级缓存 singletonFactories),通过ObjectFactory 提前曝光,所以可以通过 ObjectFactory#getObject() 方法来拿到 A 对象。 C 拿到 A 对象后顺利完成初始化,然后将自己添加到一级缓存中;
4. 回到 B, B 也可以拿到 C 对象,完成初始化, A 可以顺利拿到 B 完成初始化。到这里整个链路
就已经完成了初始化过程了。