关于spring:熟练掌握spring框架第一篇

前言

熟练掌握这个词置信很多同行在写简历的时候都用到过。熟练掌握这四个字是依据每个人程度不一样,了解也不一样。比方一个刚毕业的大学生,他可能也会在简历外面写熟练掌握spring框架,但实际上他并没有看过spring源码,也没有太多实际。可能只是看了几本书,应用spring框架写了一个毕业设计,而后就说本人熟练掌握spring框架了。再比方一个有二三年工作教训的求职者,也在简历外面说本人熟练掌握spring框架,他的理由是他看过spring 的一些关键性代码了,也在理论工作中应用spring开发了工程项目。甚至本人依据一些业务须要,写了几个不错的针对spring框架的扩大。再比方一个工作了四五年的程序员,他在本人简历上写熟练掌握spring框架。因为他把spring和spring boot源码大部分都看过,工作中解决了不少波及原理性的问题。对spring框架的整个架构图,根本了然于胸。另外总结出了十分多的spring相干的最佳实际。再比方一个工作了七八年的程序员,他们对spring的了解可能又不太一样。其实我想说的是,程度和教训决定了一个人的见解。每个人都应该虚心学习丰盛和坚固本人的常识体系,拓宽常识的广度,增强常识的深度。这样才会在无限的工夫外面,成长成参天大树。好了,废话不多说,明天的主题是熟练掌握spring框架。那么我就从n个问题着手。说一下工作了n年的我对熟练掌握的见解吧。

BeanFactory和FactoryBean的区别

首先说下BeanFactory他是springIOC容器的顶层接口。负责管理和生产Bean。他的默认实现是:DefaultListableBeanFactory。在spring boot我的项目启动时,执行createApplicationContext()后返回的实例类型是AnnotationConfigApplicationContext,能够看下该类的层次结构图。发现他也是BeanFactory接口的实现类。代码是在ApplicationContext的抽象类AbstractApplicationContext中,能够看出所有BeanFactory的实现还是调用了GenericApplicationContext的成员DefaultListableBeanFactory beanFactory 的具体实现。所以Bean治理的外围代码天然就是DefaultListableBeanFactory

查看它的类层次结构图发现,这个类次要表演两个角色,第一个就是bean工厂,第二个就是BeanDefinition的注册核心。bean工厂提供了对单例bean注册核心(DefaultSingletonBeanRegistry),FactoryBean注册核心(FactoryBeanRegistrySupport)的反对。首先咱们看下他是如何实现bean工厂的。

注册单例bean

应用@Component注解定义一个UserService

断点设置在DefaultSingletonBeanRegistry单例bean注册核心的addSingleton中。

看下调用栈:

  1. 产生在refreshContext阶段
  2. 对单例模式bean进行初始化
  3. 通过getBean触发实例化userService ,getBean进而调用doGetBean

doGetBean办法能够略微开展下

它调用了DefaultSingletonBeanRegistrygetSingleton 其中第二个参数就是ObjectFactory,创立bean的工厂ObjectFactory 理论调用的是AbstractAutowireCapableBeanFactorycreateBean办法,进而调用它的doCreateBean,接着调用createBeanInstance办法,进而调用instantiateBean办法,应用SimpleInstantiationStrategy 策略类(理论应用的java反射技术动静创建对象)创立实例。

获取单例bean

还是方才那个例子。在ApplicationRunner的run办法调用getBean办法。

doGetBean办法里会首先检查单利缓存外面是否有,如果有的话,间接返回。

BeanDefinition注册

咱们再来看下BeanDefinition注册核心是如何实现的。
咱们依然是在DefaultListableBeanFactoryregisterBeanDefinition设置断点,看下调用栈。

  1. 同样产生在refreshContext阶段
  2. 执行所有的BeanFactoryPostProcessor
  3. 执行所有的BeanDefinitionRegistryPostProcessor,此处默认就一个名为:ConfigurationClassPostProcessor
  4. 此办法次要工作就是首先调用ConfigurationClassUtils.checkConfigurationClassCandidate找到所有ConfigurationClass的候选人,而后应用ConfigurationClassParser解析每个ConfigurationClass
  5. 如果是ComponentScansConfigurationClass,就调用ClassPathBeanDefinitionScannerdoScan进行扫描。
  6. 将扫描的BeanDefinition 增加到DefaultListableBeanFactorybeanDefinitionMap里。至此实现BeanDefinition的注册。

FactoryBean

说了这么多,置信读者对spring框架的BeanFactory有了一个比拟全面的理解了。上面聊聊FactoryBeanFactoryBean是spring 容器里的一种非凡的bean

该接口的实现以BeanFactory为工厂。假如某个Bean实现了该接口,它用作生产对象的工厂。而不是像一般的Bean那样间接裸露本人。通常应用getObject办法裸露beanFactoryBean反对单例和原型,并且能够能够按需提早或者在启动的时候创建对象。这个接口在spring框架外部大量应用,比方AOP org.springframework.aop.framework.ProxyFactoryBean jpaorg.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean,然而在理论业务代码外面并不常见。

起源java doc

上面就以JpaRepositoryFactoryBean具体介绍下FactoryBean是如何工作的。

读者能够翻看下之前的一篇文章【JpaRepositoryBean创立流程剖析】此处对于repository bean的初始化就不具体介绍了。咱们还是在ApplicationRunner的run办法里调用ApplicationContextgetBean获取一个UserRepository,如果是第一次获取,流程是这样的。

  1. 调用BeanFactorygetBean办法。
  2. 理论逻辑在AbstractBeanFactorydoGetBean办法里。
  3. 依据beanName userRepositorySingletonBeanRegistry里找到相应的JpaRepositoryFactoryBean
  4. 而后依据在FactoryBeanRegistry 的缓存里(factoryBeanObjectCache)依据beanName查找userRepository,因为是第一次,所以找不到。
  5. 调用FactoryBeanRegistrySupportgetObjectFromFactoryBean办法。该办法有个同步代码块,目标是保障并发状况下,创立的对象依然是单例的。
  6. 同步代码块里回去调用JpaRepositoryFactoryBeangetObject办法获取之前就曾经创立好的repository,而后退出到factoryBeanObjectCache中去并返回相应的bean

小结

通过源码学习,咱们发现BeanFactoryFactoryBean是两个齐全不同的概念,然而他们的代码又是严密关联的。FactoryBeanBeanFactory里的一种非凡bean,因为他自身也是一个工厂,能够生产本人的Bean ,有个非凡的中央须要咱们留神一下。如果传入的beanName是以&为前缀的话。会调用BeanFactoryUtilstransformedBeanName办法,去掉前缀,而后在Singleton注册核心获取相应的bean。如果找不到的话会有很长的一段代码进行解决。这里就不做深入探讨了,感兴趣的读者能够钻研下。

BeanPostProcessor和BeanFactoryPostProcessor

两个类都以PostProcessor结尾,中文名为后置处理器,意思就在Bean创立或者BeanFactory创立之后进行的操作。spring外围代码外面PostProcessor随处可见。

首先咱们来看下BeanFactoryPostProcessor,来张UML图。这个图很简略,BeanFactoryPostProcessor定义了一个办法。参数就是刚刚创立的bean工厂。而BeanDefinitionRegistryPostProcessor定义的办法,参数就是刚刚创立好的BeanDefinition注册核心。

咱们以一个最具备代表性的类ConfigurationClassPostProcessor 看下它是何时调用的,它做了什么。咱们将断点设置在它的postProcessBeanFactorypostProcessBeanDefinitionRegistry办法里。发现产生在spring启动的refreshContext阶段,此时Bean工厂曾经创立了。先调用所有的BeanDefinitionRegistryPostProcessor再调用所有BeanFactoryPostProcessor。详见PostProcessorRegistrationDelegateinvokeBeanFactoryPostProcessorsConfigurationClassPostProcessor两次都会被调到。

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        int registryId = System.identityHashCode(registry);
        if (this.registriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                    "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
        }
        if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                    "postProcessBeanFactory already called on this post-processor against " + registry);
        }
        this.registriesPostProcessed.add(registryId);
    //外围逻辑在processConfigBeanDefinition()办法中,用来解决BeanDefinition的注册
        processConfigBeanDefinitions(registry);
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        int factoryId = System.identityHashCode(beanFactory);
        if (this.factoriesPostProcessed.contains(factoryId)) {
            throw new IllegalStateException(
                    "postProcessBeanFactory already called on this post-processor against " + beanFactory);
        }
        this.factoriesPostProcessed.add(factoryId);
        if (!this.registriesPostProcessed.contains(factoryId)) {
            // BeanDefinitionRegistryPostProcessor hook apparently not supported...
            // Simply call processConfigurationClasses lazily at this point then.
            processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }

    // 对加了@Configuration注解的配置类进行Cglib加强代理
        enhanceConfigurationClasses(beanFactory);
    // 增加一个BeanPostProcessor后置处理器
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

ConfigurationClassPostProcessor无疑是spring中最重要也是最简单的后置处理器了,此处就不具体开展了。再来看下BeanPostProcessor的UML图。

这两个办法调用的中央都是在AbstractAutowireCapableBeanFactoryinitializeBean中。

看个简略的例子吧,下面学习ConfigurationClassPostProcessor时,咱们发现它增加了一个bean后置处理器ImportAwareBeanPostProcessor,上面是它的postProcessBeforeInitialization办法

//如果bean实现了ImportAware接口,就调用一下它的setImportMetadata办法,通过这种形式,能够在程序中拿到注解的元数据。
public Object postProcessBeforeInitialization(Object bean, String beanName) {
            if (bean instanceof ImportAware) {
                ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
                AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
                if (importingClass != null) {
                    ((ImportAware) bean).setImportMetadata(importingClass);
                }
            }
            return bean;
}

下面是spring内置的一个处理器。理论工作中,咱们也会常常自定义后置处理器。一个常见的场景就是对某些类进行动静加强。

未完待续,更多内容请关注【熟练掌握spring框架】第二篇

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理