说到这个spring,首先要搞清楚没有spring之前我们是什么样子的哈
a、很多设计模式需要自己去整合
b、所有的封装、继承、多态、增强、依赖、模块管理等等工作都需要自己制定统一的规则
c、所有的创建对象、配置依赖关系、资源的重复利用都需要我们手动去搞
我滴个天,看着都累、这的做多少重复的工作。人是懒惰的,不想重复造轮子呀,所以Spring出现了,Java程序员的春天真的来了,解放了
细节来了,spring做了什么?让 Java Bean能够实现无缝对接、闭上眼睛幻想一下,有没有这么一个东西、我们的所有bean 初始化就都准备好了,只是存在一个地方、用的时候就自动来了~正所谓召之即来。想想都香、简直是人工智能。
幸运的是,spring就做到了。这个得益于spring的IOC容器,ioc小名bean工厂,在具体点就是一个(Map容器–ps:实际存在 ConcurrentHashMap)、缓存bean 的地方。这么搞得优点显而易见,时刻在内存中放着、用的时候不需要临时创建,速度那是杠杠的~
用抽象点的语言描述:
1、IOC(Inversion of Control)控制反转:所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知 道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。
简单点说就是容器帮我们创建bean,并理清楚bean与bean之前的关系,最后存起来供我们使用。如何创建?如何存?通过啥规则顺序加载?
总结:ioc 全局上下文缓存的信息 IOC容器何时创建bean、各个bean的关系、怎么存储bean
spring容器是整个spring框架的核心,通常我们说的spring容器就是bean工厂
bean工厂负责创建和初始化bean、装配bean
见识一下bean长啥样子?
ApplicationContext(XmlWebApplicationContext :-Root WebApplicationContext startup)
serializationde==org.springframework.web.context.WebApplicationContext:
-—beanFactory
--beanDefinitionMap(ConcurrentHashMap ===key:value)
ApplicationContext,这是在BeanFactory基础之上,面向使用Spring框架的开发者。提供了一系列的功能!
1、"key:restTemplate" -> "Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=restTemplateConfig; factoryMethodName=restTemplate; initMethodName=null; destroyMethodName=(inferred); defined in com.esgcc.fsp.config.RestTemplateConfig"
流程细化:定位 加载 注册 自动依赖注入
流程图看着很复杂,简单概括一下
1、定位:加载配置文件,找到 .class的存放位置
2、加载:根据路径 找到class文件、packname+filename 存List
3、注册:class.forname() 反射class, 拿到注解、创建对象bean,存入map -
4、依赖注入:遍历map,反射每个class的字段,有@auto 注解 就赋值
以上是对spring的一个简单的概括,真正的spring肯定在这个理念上加强了好多。
1、BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory 可以理解为含有 bean 集合的工厂类。BeanFactory 包含了种 bean 的定义,以便在接 收到客户端请求时将对应的 bean 实例化。 BeanFactory 还能在实例化对象的时生成协作类之间的关系。此举将 bean 自身与 bean 客户端的配置 中解放出来。BeanFactory还包含了bean生命周期的控制,调用客户端的初始化方法(initialization Methods)和销毁方法(destruction Methods)。 从表面上看,application context 如同 bean factory 一样具有 bean 定义、bean 关联关系的设置, 根据请求分发 bean 的功能。但 application context 在此基础上还提供了其他的功能。
1.提供了支持国际化的文本消息
2.统一的资源文件读取方式
3.已在监听器中注册的 bean 的事件
spring源码是啥?
1、定位:资源配置 import、classpath、url
2、加载:解析配置文件,把bean包装成 beanDefintion对象
3、注册:把已经初始化的beanDefintion对象放入IOC-map容器
资源定位
此处可通过xml,定位 class
//根据 Xml 配置文件创建 Resource 资源对象,该对象中包含了 BeanDefinition 的信息
ClassPathResource resource =new ClassPathResource("application-context.xml");
//创建 DefaultListableBeanFactory
DefaultListableBeanFactory factory =new DefaultListableBeanFactory();
//创建 XmlBeanDefinitionReader 读取器,用于载入 BeanDefinition。之所以需要 BeanFactory 作为参数,是因为会
将读取的信息回调配置给 factory
XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);
//XmlBeanDefinitionReader 执行载入 BeanDefinition 的方法,最后会完成 Bean 的载入和注册。完成后 Bean 就成功
的放置到 IOC 容器当中,以后我们就可以从中取得 Bean 来使用
reader.loadBeanDefinitions(resource);
实际调用入口 refresh()
接下来展开诸多细节,
AbstractApplicationContext 的 refresh 函数载入 Bean 定义过程
refresh()方法的作用是:在创建 IOC 容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在 refresh 之后使用的是新建立起来的 IOC 容器。refresh 的作用类似于对 IOC 容器的重启,
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
prepareRefresh();
//告诉子类启动 refreshBeanFactory()方法,Bean 定义资源文件的载入从子类的 refreshBeanFactory()方法启动
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//为 BeanFactory 配置容器特性,例如类加载器、事件处理器等
prepareBeanFactory(beanFactory);
try {
//为容器的某些子类指定特殊的 BeanPost 事件处理器
postProcessBeanFactory(beanFactory);
//调用所有注册的 BeanFactoryPostProcessor 的 Bean
invokeBeanFactoryPostProcessors(beanFactory);
//为 BeanFactory 注册 BeanPost 事件处理器.BeanPostProcessor 是 Bean 后置处理器,用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);
//初始化信息源,和国际化相关.
initMessageSource();
//初始化容器事件传播器.
initApplicationEventMulticaster();
//调用子类的某些特殊 Bean 初始化方法
onRefresh();
//为事件传播器注册事件监听器.
registerListeners();
//初始化所有剩余的单例 Bean.
finishBeanFactoryInitialization(beanFactory);
//初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
} catch (BeansException ex) {
//销毁以创建的单态 Bean
destroyBeans();
//取消 refresh 操作,重置容器的同步标识.
cancelRefresh(ex);
throw ex;
}
}
装配bean的过程中会出现一个问题:A依赖B,装配A的时候B的实例还没有创建,怎么办?
spring解决这个问题的办法是:先创建B对象,装配好bean,然后把B注入A,继续完成A的装配.
假设:当 Bean_A 依赖着 Bean_B,而这个 Bean_A 在加载的时候,其配置的 ref = “Bean_B” 在解析的时候只是一个占位符,被放入了 Bean_A 的属性集合中,当调用 getBean 时,需要真正 Bean_B 注入到 Bean_A 内部时,就需要从容器中获取这个 Bean_B,因此产生了递归。
为什么不是在加载的时候,就直接注入呢?
因为加载的顺序不同,很可能 Bean_A 依赖的 Bean_B 还没有加载好,也就无法从容器中获取,你不能要求用户把 Bean 的加载顺序排列好,这是不人道的
Spring 的IoC。将其分为了 2 个步骤:
加载所有的 Bean 配置成 BeanDefinition 到容器中,如果 Bean 有依赖关系,则使用占位符暂时代替。然后,在调用 getBean 的时候,进行真正的依赖注入,即如果碰到了属性是 ref 的(占位符),那么就从容器里获取这个 Bean,然后注入到实例中 —— 称之为依赖注入。
那么spring Aop如何实现的呢,其实是对对象进行包装~使其成为代理对象、这是一个可以invoke的对象
猜想一下,1、对普通bean包装 2、wrapper存到map中 3、切点可配置
getbean()