共计 3224 个字符,预计需要花费 9 分钟才能阅读完成。
1.spring 简介
2.spring 容器流程梳理
3. 总结
1.spring 简介
spring 我置信大家都不生疏,只有你是一位 JAVA 开发人员,必定会应用它,然而咱们日常的应用中,很多时候只须要写业务逻辑,应用他人曾经封装好的技术,对其原理却无所不知。在此系列的博客中,笔者心愿尽可能地总结 spring 源码,让咱们不再只会应用它,让读者懂其原理。
所谓:有道无术,术尚可求,有术无道,止于术 。
框架的应用可能就是‘术’,而框架的底层实现原理,就是‘道’。有了‘道’之后,‘术’是能够依据本人的须要造出来的。就像晓得了数学公式是如何推导的,天然不必记住公式,还能对公式进行魔改 ,甚至创造公式。然而如果只有‘术’,就像只晓得了公式的形态,并不知道其起源,略微变一下咱们就认不出来了。
无论是学什么货色,笔者认为,积攒‘道’是十分重要的,且不可急功近利,否则就是欲速则不达。
2.spring 容器流程梳理
咱们在应用 spring 的时候,应用最多的就是AOP 和 IOC。
IOC:管制反转
理念:让他人为咱们服务!
假如我当初须要一个对象,个别状况下咱们都是须要本人 new 进去,然而有了 IOC 之后,咱们将一些对象的控制权给了 spring 容器,当咱们想要的时候,spring 就会本人把对象送来!
看到这里咱们可能比拟迷糊,还是不晓得 ioc 的具体应用,咱们来举个例子好了:
假如咱们有一个 UserServiceImpl, 是 IUserService 的实现类,然而咱们每次应用的时候,都须要:
IUserService userService = new UserServiceImpl();
因为很多中央都要用到这个对象,所以咱们要写很多很多个 new UserServiceImpl();
如果此时,IUserService 更改了需要,须要把所有 IUserService 的实现类 UserserviceImpl 全副改成 UserserviceImpl2(),那代码更改量是十分恐怖的。然而如果有了 IOC,咱们就能够和实现类解耦了。次要更改 IOC 容器外面的实现类,当咱们用到这个接口的实现类的时候,让它给咱们送来就行了(只须要批改一个中央)。
AOP:面向切面编程
咱们都晓得,在咱们编码的时候,事务管制,权限管制等代码逻辑,会像一把刀一样,横在咱们业务逻辑两头,咱们将这部分代码称之为,横切业务逻辑代码。
那么将这部分代码对立独立进来,将横切逻辑也业务逻辑拆散,并进行对立治理,这就是 AOP。
有了 AOP 和 IOC 的概念之后,接下来咱们来梳理一下,spring 的总体执行流程:
一开始,咱们学习 spring 框架,都是 从配置文件 开始的,咱们在 spring 配置文件中写一个 bean,而后咱们再从容器中读出来。
xml 配置文件:
<bean id="a" class="slf.A">
</bean>
// 将 xml 加载到容器中
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器中获取 bean
A a = (A) classPathXmlApplicationContext.getBean(A.class);
通过上述代码,咱们大抵能够剖析出,咱们应用 spring 的时候,大略是这样一个执行逻辑:
咱们大略能够总结出这个逻辑,然而 spring 外面却远远不止这么多操作,咱们先来对下面这张图进行一个裁减,退出一个概念BeanDefinition!
BeanDefinition:
它是配置 bean 元信息的一个接口,蕴含:
1)领有属性存储的性能, 比方类信息,比方加载模式(懒加载等等)
2)领有资源获取的能力,也就是读取配置资源的能力
3) 对 Bean 对象的形容能力
因为有的 bean 不是马上被实例化的(lazy-load),而后也可能有的 bean 蕴含了其它 bean 的信息,也可能有的 bean 的属性值须要读取别的文件(${jdbc.username}),所以咱们须要 beanDefinition。
那么,bean 信息除了从 xml 中来,还能够从注解,json,yml,json 等中央来,而后咱们还能够对此图进行一个裁减。
其实 IOC 容器外面,并不仅仅只有反射,这么简略,因而咱们对 IOC 容器也进行一个裁减。
咱们先引入一个概念,beanFactoryPostProcessor:
BeanFactoryPostProcessor 接口,能够对BeanDefinition 元数据进行操作。比方配置文件中的 ${jdbc.username},咱们能够应用 BeanFactoryPostProcessor 将它的值从文件中读取并赋值。
可见 BeanFactoryPostProcessor 能够批改 BeanDefinition 外面的属性值。
而后就是初始化,
在 spring 中,容器将对象的初始化和实例化分成了两步操作:
别离是 初始化和实例化:
如图所示:
初始化,顾名思义,就是咱们平时所说的,在堆内存开拓一块空间
实例化比较复杂,分成了很多步,流程图如所示,咱们将它并入下面那个大图,再进行解说:
填充属性:
具体能够参考 populateBean 办法,大略就是拆卸一些对象,比方对象 A 外面有对象 B,就将 B 从容器中取出来并装进入,这个办法后续会具体进行解说。
执行 aware 接口办法:
Aware 接口的性能就是,一个类只有实现这个类接口的相干子类,则能够拿到相应的货色。
那么具体能够拿到什么呢?咱们能够看一下这个类有哪些实现接口:
比如说 ApplicationContextAware,咱们实现了这个接口,就能够从获取 ApplicationContext 这个对象:
public class AwareDemo implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}
BeanPostProcessor:Before:
接下来执行 beanPostProcessor 前置办法,实现了这个接口的 bean,咱们要执行它的前置办法
public class BeanPostProcessorDemo implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return null;}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return null;}
}
init-method:
如果 bean 的文件配置中有 init 标签,咱们就要执行它对应的办法:
<bean id="a" class="slf.A" init-method="init">
<property name="b" ref="b"/>
</bean>
BeanPostProcessor:After:
后置办法,能够参考下面。
3. 总结
明天咱们总结了 Bean 容器的大体的执行流程,也只是粗略地概括了一下,大抵能够用一张图来进行概括:
另外值得一提的是,beanFactoryPostProcessor 和 beanPostProcessor 是有区别的,区别如图所示: