25 September 2018

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()

企业微信截图_8eea9391-34cc-462c-91eb-c749ebd107d8.png

影响多个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使用工厂模式通过 BeanFactoryApplicationContext 创建 bean 对象。
  • 代理设计模式 : Spring AOP 功能的实现。
  • 单例设计模式 : Spring 中的 Bean 默认都是单例的。
  • 模板方法模式 : Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
  • 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
  • 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller


blog comments powered by Disqus