水滴石穿-深入理解Spring(一)
本文最后更新于:May 13, 2023 pm
积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得,圣心备焉。故不积跬步,无以至千里,不积小流无以成江海。齐骥一跃,不能十步,驽马十驾,功不在舍。面对悬崖峭壁,一百年也看不出一条裂缝来,但用斧凿,能进一寸进一寸,能进一尺进一尺,不断积累,飞跃必来,突破随之。
目录
什么是Spring
Spring 框架一般指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。Spring 是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性。核心功能主要是 IoC 和 AOP。
Spring的优缺点
优点
方便解耦,简化开发。
通过spring提供的IOC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免原编码所造成过度程序耦合;有了spring,用户不再为了单列模式类、属性文件解析等这些很底层的需求编写代码,可以专注于上层的应用。
AOP编程的支持
通过spring提供的AOP功能方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。spring的AOP支持允许将一些通用任务如安全,事务,日志等进行集中式管理,从而提供了更好的复用。
声明事务的支持
在spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明方式灵活地进行事务的管理,提高开发效率和质量。
方便程序的测试
可以用非容器依赖编程方式进行几乎所有的测试工作,在spring里,测试不在是昂贵的操作,而是随手课做的事情没列入spring对junit4支持,可以通过注解方便的测试spring程序。
方便集成各种框架
spring不排斥各种优秀的开源框架,相反,spring可以降低各种框架的使用难度,spring提供了对各种优秀框架(如Strust,Hibernate,Hessian,Quartz)等的直接支持。
降低javaEE API的使用难度
spring对很多难用的java EE API(如JDBC,javaMail,远程调用等)提供了一个薄薄的封装层,通过spring的简易封装,这些java EE API的使用难度大大降低。
缺点
从应用层面来说暂时没有缺点
因为简化开发,如果需要深入给底层去了解就非常困难(上层使用的越简单,底层的封装就越复杂)
源码的缺点:由于spring大并且全(要集成很多框架,提供非常多的扩展点)代码非常庞大,对于学习源码具有一定困难
Spring的Ioc容器
IoC(Inverse of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用。
- 控制 :指的是对象创建(实例化、管理)的权力
- 反转 :控制权交给外部环境(Spring 框架、IoC 容器)
Spring Ioc的实现机制
机制并非原理!
实现机制: 简单工厂 + 反射
- 简单工厂就是调用这个方法 BeanFactory.getBean(name);
- 反射就是在工厂模式getBean()方法中通过反射的方式来创建Bean。
反射会根据getBean(name), 传入的name来通过以下两种配置方式找到类全路径然后进行创建Bean对象。
通过spring.xml配置:
<bean id="userDao" class="com.test.***.userDao"/>
通过注解配置:
@Component("userDao")、@Service等
Ioc和DI的区别是什么
简单理解:Ioc是思想,DI是Ioc的具体实现。
IOC 是英文inversion of control的缩写,意思是控制反转。DI 是英文Dependency Injection的缩写,意思是依赖注入
依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
- Ioc 控制反转,指将对象的创建权,反转到Spring容器。
- DI 依赖注入,指Spring创建对象的过程中,将对象依赖属性通过配置进行注入。
- 依赖注入是beanFactory生产bean时为了解决bean之间的依赖的一种技术。
BeanFactory的作用
简单理解:就是用来生产Bean的。
- BeanFactory是Spring中核心的一个顶层接口。
- BeanFactory 一个最简单的Spring容器,给依赖注入(DI)提供了基础的支持。
BeanDefinition的作用
主要负责存储Bean的定义信息,决定Bean的生产方式。
1 |
|
其中,id、class、scope等等就是定义信息。
AbstractBeanDefinition部分源码:
1 |
|
自定义配置的Bean的定义信息会被加载到BeanDefinition,一个Bean就会创建一个BeanDefinition,多个则会创建多个BeanDefinition。
所有的Bean都会存在于BeanDefinitionMap中,key为Bean的名字,Value就是BeanDefinition。
1 |
|
最后就会交给BeanFactory来进行生产。
BeanFactory和ApplicationContext的区别
ApplicationContext是BeanFactory的子接口。都可以作为容器。
ApplicationContext中
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用(BeanPostProcessor、BeanFactoryPostProcessor为后置处理器),但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
BeanFactory和FactoryBean的区别
- BeanFactory是一个工厂,也是一个容器,是来管理和生产bean的。
- FactoryBean是一个bean,但是一个特殊的bean,也是由BeanFactory来管理的。
- FactoryBean里面的
getObject()
是用来获取FactoryBean产生的对象,相当于一个工厂方法,通过此方法可以产生任何对象。在BeanFactory
中使用&
来得到FactoryBean本身,用来区分通过容器获取FactoryBean产生的对象还是获取FactoryBean本身。如:context.getBean(“&userMapper”); - FactoryBean是一个接口,必须被一个bean实现,实现了此接口的bean将会发生”变异”。实现FactoryBean的bean通过重写
getObject()
方法来重新返回一个对象。如:一个bean为User,原本应该返回User对象,但是现在重写getObject()
方法并返回一个其他对象,那么这个bean就不再是原本user的bean了。
配置Bean的方式
通过配置文件:
<bean id="aop" class="com.tothefor.springAOP.aspectJAOP"></bean>
使用注解:@Component、@Service、@Controller、@Repository。(需要配置扫描包
<context:component-scan base-package="com.tothefor.dao"></context:component-scan>
)
JavaConfig配置类:@Bean(标注在方法上,方法返回的对象成为bean,通常和@Configuration一起使用)
@Import(3中方式)
Bean的作用域
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的,对单例设计模式的应用。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
- session : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
- global-session : 全局 session 作用域,仅仅在基于 portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
配置作用域
xml文件:
1 |
|
注解:
1 |
|
Spring中Bean是否是线程安全的
Spring 不保证 bean 的线程安全。默认 spring 容器中的 bean 是单例的。当单例中存在竞态条件,即有线程安全问题。如下:
1 |
|
解决安全问题:将成员变量的声明放到方法中即可;或者修改为多例(prototype)、声明为ThreadLocal。
实例化Bean的方式
- 构造器方式(反射)。
- 静态工厂方式。
1 |
|
creasTest即为静态方法。
- 实例工厂方式(@Bean)。
1 |
|
- FactoryBean方式。
本文作者: 墨水记忆
本文链接: https://tothefor.com/DragonOne/cb66fdea.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!