springIOC容器依赖注入的原理解析
- 工厂模式:供外部使用的FactoryBean 和内部使用的ObjectFactory 通过其getObject获取到的才是想要的对象。
- 门面模式:抽离出个门面类,将一系列底层操作整合成一个操作。
-
模版模式:围绕抽象类,实现通用逻辑,定义模版结构,部分逻辑由子类实现 :复用代码,反向控制。
模版方法(方法的组合)、具体方法(自带方法)、钩子方法(视情况实现的方法)、抽象方法(必须由子类实现的方法) - 策略模式:
- 委派模式:
- 责任链模式:后置处理器
- 事件监听器模式: 容器初始化各阶段都有各种事件发布,由所注册的监听器进行处理
- 单例模式:getObjectFromFactoryBean 容器本身是单例的 枚举方式, Bean默认也是单例的,在doGetBean()方法从三级缓存中获取Bean实例时也用到了双重校验锁。
一、 Spring
抓住主心骨进行学习:
-
解析配置
-
定位与注册对象
-
注入对象
全局掌握核心接口和类
-
解决了关键的问题:将对象之间的关系转而配置来管理
-
依赖注入–依赖关系在Spring的IoC容器中管理
通过把对象包装在Bean中达到管理对象和进行额外操作的目的
1.Bean和BeanDefination
- Bean的本质是java对象,只是这个对象的生命周期由容器来管理
- 不需要为了创建Bean而在原来的java类上添加任何额外的限制
- 对java对象的控制体现在配置上
根据配置,生成用来描述Bean的BeanDefination,常用属性:
- 作用范围scope(@Scope) singleton session prototype globalsession request
- 懒加载lazy-init(@Lazy):决定Bean实例是否延迟加载
- 首选primary(@Primary):设置为true的Bean会是优先的实现类
-
factory-bean和factory-method(@Configuration @Bean)
使用factory-bean中的factory-method进行创建bean,如果只有factory-method通过class的factory-method设置的方法
容器初始化主要做的事情(主要脉络)
- 解析配置
- 定位与注册对象
BeanDefinition家族:
BeanDefinition全介绍
spring源码分析之BeanDefinition相关
Bean的继承关系是在BeanDefinition里设置Parentname属性体现的。
- AttributeAccessor 接口提供相关属性attribute的设置和读取操作设置属性可以通过xml的设置
- BeanMetadataElement接口获取一个包含元数据元素的配置源对象
- AttributeAccessorSupport抽象类 实现了AttributeAccessor接口 使用Map来提供属性的访问和操作
- BeanMetadataAttributeAccessor类继承AttributeAccessorSupport实现BeanMetadataElement 新增的功能是访问BeanMetadataAttribute类型的属性。
Spring中Bean的继承属性是通过BeanDefinition中的parent属性进行标识的,可以获取到父Bean的配置,后续在Bean的创建时会有个合并Bean方法,就是来处理parent属性的。
2.Spring容器
BeanFactory 是所有容器的根接口
补充:BeanFactory和FactoryBean的区别: FactoryBean不是容器,实现FactoryBean接口的Bean可以自定义Bean的创建方法。
//对FactoryBean的转义定义,提供获取FactoryBean的方式,
// 如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
//如果需要得到工厂本身,需要转义String FACTORY_BEAN_PREFIX = “&”;
简单容器:
DefaultListableBeanFactory是第一个可以实际使用的BeanFactory 内部有一个 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
复杂容器(通常也叫上下文):
术语
组件扫描:自动发现应用容器中需要创建的Bean。
自动装配:自动满足Bean之间的依赖。
复杂容器
ApplicationContext:public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver
EnvironmentCapable: 只有一个方法getEnviroment();获取一些启动变量
ListableBeanFactory:以列表形式操作Bean,如获取Bean的个数
HierarchicalBeanFactory:支持Bean的分级
MessageSource:国际化相关接口
ResourcePatternResolver:加载配置相关接口
ApplicationEventPublisher:具备事件发送的能力
传统基于XML配置的容器
FileSystemXmlApplicationContext:从文件系统中加载配置
ClassPathXmlApplicationContext:从classpath加载配置
XmlWebApplicationContext:用于Web应用程序的容器
目前比较流行的容器
AnnotationConfigServletWebServerApplicationContext
AnnotationConfigReactiveWebServerApplicationContext
AnnotationConfigApplicationContext
注解和xml配置方式的容器是不一样的,主要学习容器的共性 refresh()方法是主流容器都实现的方法,
refresh()大致功能 用到了模版模式,是一个非常典型的模版方法。
- 容器初始化、配置解析
- BeanFactoryPostProcessor和BeanPostProcessor的注册和激活
- 国际化配置
……
ps:AbstractApplicationContext
3.资源加载
弄清Resource、ResourceLoader和容器之间的微妙关系。
Resource:能实现加载配置 如从类路径,文件等 只支持读操作。
ServletContextResource:
ClassPathResource:用来访问类加载路径里的资源,例如可自动搜索WEB-INF/classes目录下的配置文件。
FileSystemResource: 访问系统文件资源
强大的资源加载方式
ResourceLoader: 根据传入的资源地址,自动识别classpath: file: 风格 按需返回特定的Resource getResource(String location) getClassLoader() 用到了策略模式
ResourcePatternResolver: 加持了getResource方法,Resource[] getResources(String locationPattern) throws IOException; 可以返回多个Resource.
ApplicationContext实现了ResourcePatternResolver接口,
AbstractApplicationContext继承了DefaultResourceLoader,且内部有个函数可以返回PathMatchingResourcePatternResolver,在构造函数时进行调用,赋值给成员变量。 这是任何ApplicationContext的实现都支持统一资源加载的原因.
/** ResourcePatternResolver used by this context. */ /** 此上下文使用的 ResourcePatternResolver 资源模式解析器 */ private ResourcePatternResolver resourcePatternResolver; /**
* Create a new AbstractApplicationContext with no parent.
* 创建一个没有父元素的新的AbstractApplicationContext
*/ public AbstractApplicationContext() { this.resourcePatternResolver = getResourcePatternResolver(); } /**
* 返回此 ResourcePatternResolver资源模式解析器,
* 用于将多个资源的位置按照模式解析到资源实例中。
* 默认是org.springframework.core.io.support.PathMatchingResourcePatternResolver。
* 支持ant风格的位置模式。
* 可以在子类中重写,用于扩展解析策略,例如在web环境中。在需要解决位置模式时不要调用此函数。
* 相反,调用上下文的getResources方法,它将委托给ResourcePatternResolver。
* @return 此应用上下文的 ResourcePatternResolver 资源模式解析器
* @see #getResources
* @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
*/ protected ResourcePatternResolver getResourcePatternResolver() { return new PathMatchingResourcePatternResolver(this); } //--------------------------------------------------------------------- // ResourcePatternResolver 接口的实现 //--------------------------------------------------------------------- @Override public Resource[] getResources(String locationPattern) throws IOException { return this.resourcePatternResolver.getResources(locationPattern); }
BeanDefinitionReader 主要方法 loadBeanDefinitions
利器ResourceLoader的使用者 BeanDefinitionReader
- 读取BeanDefinition
-
BeanDefinitionRegistry 可以根据配置文件将BeanDefinition注册到容器里
-
BeanDefinitionRegistry getRegistry() 将BeanDefinition注册到BeanDefinition的注册表中
getBeanNameGenerator() 为匿名的 bean生成id
BeanDefinitionReader学习过程中的关键词
location、BeanDefinitionReader
Resource 、BeanDefinitionRegistry
Resourceloader、DefaultListableBeanFactory
4.BeanDefinition的注册
本质就是将配置的bean解析成beandefinition并将其注册到defaultListableBeanFactory容器的beanDefinitionMap中。
xml配置的资源定位、加载、解析、注册全链路解析
5.小结:
xml方式 BeanDefinition的注册是在refresh方法进行。
注解方式会分为三种BeanDefinition进行处理, 内置BeanDefinition 容器构造函数时进行处理、@Configuration 容器构造函数中调用register方法构造 剩下的在refresh()容器级别后置处理器处理的
二、详解SpringIoC容器的初始化 【打通refresh方法的全链路】
容器初始化主要做的事情(主线脉络)
即AbstractApplicationContext.refresh()
前沿知识:
1.后置处理器PostProcessor
本身也是一种需要注册到容器里的Bean
- 其里面的方法会在特定的时机被容器调用
- 实现不改变容器或者Bean核心逻辑的情况下对Bean进行扩展
- 对Bean进行包装,影响其行为、修改Bean的内容等
大类分为容器类别的后置处理器以及Bean级别的后置处理器
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
BeanPostProcessor
前两个属于容器级别、后一个属于Bean级别
可以做一些骚操作,通过后置处理器将第三方框架的类加载到spring 容器中,进而利用相应的功能,目前mybatis就是这么做的。
BeanPostProcessor不能对@Configuration的类进行增强。
2.Aware及其子接口
一般Bean不需要获取容器的状态,如果要从Bean里获取到的容器实例并对其进行操作,就需要Aware。这里需要ApplicationContextAware
不同类型的Aware可以召唤不同的神兽 。
3.事件监听器模式
回调函数
往组件注册自定义的方法以便组件在特定场景下调用
监听器将监听感兴趣的事件,一旦事件发生,便做出响应
- 事件源 event source
- 事件监听器 event listener
- 事件对象 event object
Spring的事件驱动模型
事件驱动模型的三大组成部分
事件:ApplicationEvent抽象类 继承EventObject
事件监听器: ApplicationListener
事件发布器(事件源):ApplicationEventPublisher以及ApplicationEventMulticaster
ApplicationEventPublisher:只有发布事件的能力。
ApplicationEventMulticaster:提供管理listener的方法和发布事件的方法。
像Bean和容器只想发布事件不想维护listener。所以进行了分割。
ApplicationEventMulticaster功能是完备的,给ApplicationEventPublisher作为代理去使用。就像ApplicationContext使用 DefaultListableBeanFactory一样。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; /**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/ public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } /**
* Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
* @param beanFactory the DefaultListableBeanFactory instance to use for this context
* @see #registerBeanDefinition
* @see #refresh
*/ public GenericApplicationContext(DefaultListableBeanFactory beanFactory) { Assert.notNull(beanFactory, "BeanFactory must not be null"); this.beanFactory = beanFactory; }
4.手撕spring容器的刷新逻辑。
5.小结:
三、SpringIoC容器的依赖注入(攻坚Bean实例的创建)
1.
getBean - doGetBean- createBean - doCreateBean
这里是以@Autowire注入为例讲解 学习路线以@Autowire的解析和自动装配进行
doGetBean可以根据scope进行创建,这里以Singleton为例。
2.doGetBean
从缓存获取Bean
一级缓存 singletonObjects 最终形态的单例实例
二级缓存 earlySingletonObjects 不完备的实例
三级缓存 singletonFactories 这里不存储的不是最终Bean实例,通过他的getObject()方法获取bean实例
主要是为了解决循环依赖的问题。
实例只能存在某一级缓存里, 一级缓存singletonObjects为ConcurrentHashMap 其余为HashMap
3.强攻Bean的创建_CreateBean方法
如果在Bean实例化前的后置处理 就创建了Bean就直接返回了。
处理方法覆盖:看是否Bean配置了lookup和replace method属性并做相关的标记。
4.doCreadteBean
处理@Autowired和@Value标签: 其实是通过后置处理器 如AutowiredAnnotationBeanPostProcessor会把bean其中被@Autowired修饰的数据封装为InjectionMetadara ,其中InjectedElement就是一个个被@Autowired修饰的
private final Class<?> targetClass; // 当post-processor处理bean时,会解析bean Class的所有属性, // 在解析时会判断属性上是否标有@Value或者@Autowired注解, // 有就解析这个属性值,将解析后结果放入这里 // 保存了被注入元素的全量集合(包括Spirng处理的或者外部处理的) private final Collection<InjectedElement> injectedElements; //和injectedElements一样,不过只保存了由Spring容器默认进行处理的属性或者方法 @Nullable private volatile Set<InjectedElement> checkedElements;
是否允许提前暴露:
//向容器中缓存单例模式的Bean对象,以防循环引用
//判断是否是早期引用的bean,如果是,则允许其提前暴露引用
//这里判断的逻辑主要有三个:
//1.是否为单例
/2.是否允许循环引用
//3.是否是在创建中的bean
5.循环依赖与三级缓存
问题 BeanDefinitionRegistry 和BeanFactory 都存放beandefinition吗?
DefaultListableBeanFactory本身就实现了BeanDefinitionRegistry接口。所以我们使用的IoC容器本身就是BeanDefinitionRegistry的实现类。
BeanPostProcessor责任链模式,各种实现BeanPostProcessor的实现类为Bean提供各种精细化的控制
本文地址:https://blog.csdn.net/weixin_44998135/article/details/108254743
上一篇: 数字图像处理
下一篇: Java开发中static关键字使用