spring学习
spring自己写了一些小例子
git@github.com:gre2/wuleispring01.git
git@github.com:gre2/wuleispring02.git
git@github.com:gre2/wuleispring03.git ***
Aware接口
实现这些接口的bean被实例化后,可以取得一些相对的资源
BeanDefinitionParser接口
解析各种配置文件的类都实现了
BeanPostProcessor:修改bean实例信息(属性值)
BeanFactoryPostProcessor:修改bean定义信息(作用域)
reference:https://www.jianshu.com/p/81349bb9859d
<context:component-scan base-package="com.qiyi.task"/>
<context :node.getNamespaceURI() ==http://www.springframework.org/schema/context
BeanDefinitionReaderUtils:把所有的bean存储起来的
AnnotationConfigUtils:包扫描之后的bean处理,作用? *** BeanFactory:IOC的顶级接口,访问spring容器的根接口,负责bean的创建,访问。
FactoryBean:首先是一个bean,之后这个FactoryBean是可以返回bean的实例,通过实现该接口可以对bean进行一些额外的操作,(比如根据不同的配置类型返回)。
reference:https://www.jianshu.com/p/ae274e71ae9f
BeanFactory接口中有一个字符常量String FACTORY_BEAN_PREFIX = "&";
当我们去获取BeanFactory类型的bean时,如果beanName不加&则获取到对应bean的实例;如果beanName加上&,则获取到BeanFactory本身的实例。
Spring本身就提供了70多个FactoryBean的实现。他们隐藏了实例化一些复杂的细节,给上层应用带来了便利。
图解:蓝色:类与类;绿色实线:接口与接口;绿色虚线:类和接口
顶级接口分析:BeanFactory
,SingletonBeanRegistry
,AliasRegistry
reference:https://www.jianshu.com/p/e50a848932e0
refresh方法
obtainFreshBeanFactory()方法
loadBeanDefinitions方法在web.xml里面获取classpath*:applicationContext.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
通过ResourceLoader得到Resource对象,找到配置文件的完全限定类名,进行加载
根据Resource对象得到流对象,loadBean
根据文件路径的流对象和Resource对象,返回一个Document对象
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root)初始化BeanDefinition
重点关注下BeanDefinitionParserDelegate:里面定义了bean文件所有用到的标签
this.delegate = createDelegate(getReaderContext(), root, parent);
createDelegate方法定义了一些xml文件里面最基本的属性值
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
两个后置处理器,处理element对象的,交给子类去做,主要是parseBeanDefinitions
解析xml中的标签文件,所有解析出来的数据都给DefaultListableBeanFactory的属性赋值了
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
/** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);
解析
BeanDefinitionParse的实现类NamespaceHandlerSupport类
findParserForElement(element, parserContext).parse(element, parserContext);
执行此方法,为了除了bean之后的标签找到自己的parse
包扫描ComponentScanBeanDefinitionParser
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
此方法首先找到 base-package,之后针对element构造一个ClassPathBeanDefinitionScanner对象,解析了额外很多属性(ComponentScanBeanDefinitionParser)
两个后置处理器,对beanDefinition进行处理,registerBeanDefinition方法把bean注册到DefaultListableBeanFactory属性里面
给包扫描的类,注册处理器
所有的bean都被扔到了beanmap对象里面 | (初始化遍历ioc对象的时候才会判断注解,之后实例化,之后自动装配) |
不错的文章:https://www.jianshu.com/p/01d8c57949a6
prepareBeanFactory方法
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
ApplicationContextAwareProcessor实现了BeanPostProcessor接口
在BEAN初始化之前,调用ApplicationContextAwareProcessor的postProcessBeforeInitialization,处理所有的Aware接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
忽略各种Aware接口的注册,因为ApplicationContextAwareProcessor把所有Aware接口都实现了
// 设置几个自动装配的特殊规则 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this);
给DefaultListableBeanFactory中resolvableDependencies赋值
/** Map from dependency type to corresponding autowired value */
private final Map<Class<?>, Object> resolvableDependencies = new HashMap<Class<?>, Object>(16);
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new
ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
如果beanFactory中包含为loadTimeWeaver的Bean,则添加BeanPostProcessor实现:LoadTimeWeaverAwareProcessor,它是用来处理AspectJ类加载期(静态代理)织入LTW(Load Time Weaving)的。
注入environment、systemProperties、systemEnvironment三个Bean
postProcessBeanFactory方法
beanFactory后置处理,是一个模板方法,交由不同的ApplicationContext实现自己处理逻辑,做一些特有的操作。
invokeBeanFactoryPostProcessors方法
查找到容器中注册的BeanFactoryPostProcessors连同直接添加的BeanFactoryPostProcessors进行排序,排序的依据的@Order注解,然后依次调用。
首先最开始解析ConfigurationClassPostProcessor(在容器初始化时注册到容器中的),使用ConfigurationClassParser来解析ConfigurationClass中的配置
registerBeanPostProcessors()方法
注册BeanPostProcessor,从Spring容器中找出的实现了BeanPostProcessor接口的Bean,并设置到BeanFactory中,之后bean被实例化的时候会调用这些BeanPostProcessor。
onRefresh()方法
这是一个模板方法,交由不同的子类实现处理自己的逻辑。比如web程序的容器AnnotationConfigEmbeddedWebApplicationContext中会调用createEmbeddedServletContainer方法去创建内置的Servlet容器。
finishBeanFactoryInitialization方法
初始化非延迟加载的单例Bean, 实例化BeanFactory中已经被注册但是未实例化的所有实例
invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的类,在这个时候都会被初始化。实例化的过程各种BeanPostProcessor开始起作用。
Configuration类解析
Spring中对Configuration类的解析是通过ConfigurationClassPostProcessor进行的,这个类是BeanFactoryPostProcessor的实现,在容器刷新方法中invokeBeanFactoryPostProcessors(beanFactory)这个方法调用所有的BeanFactoryPostProcessor,同时也就启动了Configuration类解析的。
实例化bean
preInstantiateSingletons方法,类DefaultListableBeanFactory
- getBean
- doGetBean
- createBean(beanName, mbd, args);
- bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
后置处理器开始运作org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
。。。。。。
循环依赖
spring的循环依赖的理论依据是基于java的引用传递,当我们获取对象的引用时,对象的field或者属性是可以延后设置的。
spring的单例对象初始化分为三步
- createBeanInstance实例化,调用对象的构造方法进行实例化对象
- populateBean填充属性,bean的依赖属性进行填充
- InitalizeBean初始化,调用spring xml中init方法
循环依赖主要发生在第一步,第二步,也就是构造器循环依赖和field循环依赖。
spring为了解决循环依赖,使用了三级缓存
- singletonFactories : 单例对象工厂的cache (三级缓存)
- earlySingletonObjects :提前暴光的单例对象的Cache (二级缓存)
- singletonObjects:单例对象的cache(一级缓存)
我们在创建bean的时候,首先想到的是从cache中获取这个单例的bean,这个缓存就是singletonObjects。主要调用方法就就是:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
上面代码有两个重要的参数
- isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建中,也就是没有初始化完成(比如A的构造器依赖了B对象所以得先去创建B对象, 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。
- allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象
分析getSingleton()的整个过程,Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则:
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
从三级缓存singletonFactories中移除,并放入二级缓存earlySingletonObjects中。
这里就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
这样做有什么好处呢?让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。
知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。
spring IOC+AOP
spring事务原理
通过AOP动态代理实现,使用上通常要先在配置文件中开启事务,然后通过xml文件或者注解配置要执行注解的类方法,然后再调用对应类实例方法时,spring会自动生成代理,在调用前设置事务操作,调用方法后进行事务的回滚和提交
spring的事务管理只是方便了写代码,完事还是由spring把事务的相关命令提交到数据库的。
spring生命周期
- 找scan
- 实例化Instantiation==createBeanInstance
- 属性赋值populate==populateBean,顺便解决循环依赖
- Aware接口
- 初始化Intialization==initializeBean,实现afterProperties方法
- beanPostProcessor(before[第一步之后],after)
- 销毁Destruction==ConfigurableApplicationContext#close()
影响多个Bean
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
影响单个Bean
-
Aware
-
Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
-
Aware Group2
-
- EnvironmentAware
- EmbeddedValueResolverAware
- ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
-
-
-
生命周期
-
InitializingBean
-
DisposableBean
-
-
BeanPostProcessor 注册时机与执行顺序
-
注册时机
我们知道BeanPostProcessor也会注册为Bean,那么Spring是如何保证BeanPostProcessor在我们的业务Bean之前初始化完成呢?
Spring是先执行registerBeanPostProcessors()进行BeanPostProcessors的注册,然后再执行finishBeanFactoryInitialization初始化我们的单例非懒加载的Bean。
-
执行顺序
- PriorityOrdered是一等公民,首先被执行,PriorityOrdered公民之间通过接口返回值排序
- Ordered是二等公民,然后执行,Ordered公民之间通过接口返回值排序
-
spring启动流程
- tomcat读取web.xml,找到servlet-class(DispatcherServlet)和init-param(配置文件位置)
- DispatcherServlet继承HttpServServlet,重写init(ServletConfig config)方法
- 加载web.xml中的配置文件
- 解析配置文件中的内容,扫描出所有相关的类
- 根据扫描的类,构造IOC容器(beanName,BeanDefinition)
- 遍历IOC,根据属性依赖,完成每个类的属性注入
- 处理AOP对象,扫描注解或者是bean定义,记录AOP对象,利用动态代理生成代理对象,存储在IOC容器中
- 根据requestMapping构建List
(Handler包含requestMapping的路径,bean的实现类,方法,方法的参数值) - 重写doGet和doPost方法,用请求的HttpServletRequest的uri和List
进行匹配,req.getParameterMap()拿到请求参数,之后结合List 构造参数值的数组。 - 反射执行方法,拿到返回值
设计模式
- 工厂设计模式 : Spring使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象。 - 代理设计模式 : Spring AOP 功能的实现。
- 单例设计模式 : Spring 中的 Bean 默认都是单例的。
- 模板方法模式 : Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。 - 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
- 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
。