Spring容器初探

SpringFactory容器

factory相关接口关系

ApplicationContext.png

BeanFactory接口组织架构

factory接口 实现功能
BeanFactory 定义了基本IOC容器的规范,包含像getBean()这样的IOC容器的基本方法
HierarchicalBeanFactory 增加了getParentBeanFactory()的接口功能,使BeanFactory具备了双亲IOC接口的关联功能
ConfigurableBeanFactory 主要定义了对BeanFactory的配置功能,比如通过setParentBeanFactory()设置双亲IOC容器,通过addBeanPostProcessor()配置Bean后置处理器,等等。
AutowireCapableFactory 这个工厂接口继承自BeanFacotory,它扩展了自动装配的功能,根据类定义BeanDefinition装配Bean、执行前、后处理器等
ListableBeanFactory 可以列出工厂可以生产的所有实例。当然,工厂并没有直接提供返回所有实例的方法
MessageSource 提供国际化的消息访问
ResourceLoader 资源加载的功能
ApplicationContext 核心接口
ApplicationEventPublisher 功能就是发布事件,也就是把某个事件告诉的所有与这个事件相关的监听器
ConfigurableApplicationContext 提供设置活动和默认配置文件以及操作底层属性源的工具
WebApplicationContext 提供了Web环境的支持
ThemeSource 主题资源

BeanFactory和ApplicationContext的区别

ClassPathXmlApplicationContext.png

BeanFactory是spring中比较原始的Factory,如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口是由BeanFactory接口派生而来,因而具有BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:
1.MessageSource, 提供国际化的消息访问
2.资源访问,如URL和文件
3.事件传播
4.载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

bean加载过程

指定配置信息

有三种途径来进行bean的配置:
1.xml文件的方式配置,由ClassPathXmlApplicationContext加载配置文件
2.基于注解
3.Config类加注解的方式

BeanFactory容器启动

bean的启动过程就是AbstractApplicationContext类中的refresh()方法的执行

// Prepare this context for refreshing
   prepareRefresh();
    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);
    try {
        // Allows post-processing of the bean factory in context subclasses.
        postProcessBeanFactory(beanFactory);
        // Invoke factory processors registered as beans in the context.
        invokeBeanFactoryPostProcessors(beanFactory);
        // Register bean processors that intercept bean creation.
        registerBeanPostProcessors(beanFactory);
        // Initialize message source for this context.
        initMessageSource();
        // Initialize event multicaster for this context.
        initApplicationEventMulticaster();
        // Initialize other special beans in specific context subclasses.
        onRefresh();
        // Check for listener beans and register them.
        registerListeners();
        // Instantiate all remaining (non-lazy-init) singletons.
        finishBeanFactoryInitialization(beanFactory);
        // Last step: publish corresponding event.
        finishRefresh();
    }

BeanDefination加载注册

AbstractXmlApplicationContext.loadBeanDefinitions()方法将任务交给reader来读取,最终走到AbstractBeanDefinitionParser.parse()方法.

//将bdf包装成bdfh对象
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
//将holder放入到BeanDefinitionRegistry对象中
registerBeanDefinition(holder, parserContext.getRegistry());
-----
//最终将holder中的bdf放入到DefaultListableBeanFactory的map中
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

到此bdf添加到DefaultListableBeanFactory类中的beanDefinitionMap中.

prepareBeanFactory准备

主要完成一下操作:
1.设置ClassLoader类加载器到BeanFactory
2.BeanFactory添加BeanPostProcess,在初始化之前给目标bean设置各种aware对应的实例
3.设置BeanFactory忽略掉特殊的依赖,例如bean依赖aware接口实现类在自动装配的时候直接忽略aware目标实现类,spring会通过特殊的方式处理这些依赖.
4.为特殊的几个bean赋值,例如bean依赖BeanFactory类,则直接将对应的类实例对象赋值.
至此已经完成了对一些特殊bean的处理.

初始化所有的 singleton beans

经过一系列的周折最后到达AbstractAutowireCapableBeanFactory创建bean:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException{
    
    //1.说明不是 FactoryBean,这里实例化 Bean
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    //
    //2.这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值
    populateBean(beanName, mbd, instanceWrapper);
    //3.进行实例化
    exposedObject = initializeBean(beanName, exposedObject, mbd);

}

对于创建bean有多种策略,简单的策略则是利用java的反射功能

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

}
---
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    return BeanUtils.instantiateClass(constructorToUse);
}
---
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
    Assert.notNull(ctor, "Constructor must not be null");
        
    ReflectionUtils.makeAccessible(ctor);
    return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                    KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
    }
}

特殊的FactoryBean处理过程

FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程。BeanFactory是Spring容器中的一个基本类也是很重要的一个类,在BeanFactory中可以创建和管理Spring容器中的Bean,它对于Bean的创建有一个统一的流程.包含三个重要的特性:是否单例、Bean类型、Bean实例.

bean的生命周期

WechatIMG55073.jpeg

1、实例化一个Bean
2、按照Spring上下文对实例化的Bean进行配置,也就是IOC注入
3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,传递的参数就是Spring配置文件中Bean的id值
4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(BeanFactory),传递的是Spring工厂自身
5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文
6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法
BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术
7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法
9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

BeanFactoryPostProcessor与BeanPostProcessor区别

1.BeanFactoryPostProcessor
实现该接口,可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息.
2.BeanPostProcessor
可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑.
这里的初始化方法有两种:
1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
2)在bean定义的时候,通过init-method设置的方法
spring中,有内置的一些BeanPostProcessor实现类:

  • org.springframework.context.annotation.CommonAnnotationBeanPostProcessor:支持@Resource注解的注入
  • org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor:支持@Required注解的注入
  • org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor:支持@Autowired注解的注入
  • org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor:支持@PersistenceUnit和@PersistenceContext注解的注入
  • org.springframework.context.support.ApplicationContextAwareProcessor:用来为bean注入ApplicationContext等容器对象
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容