spring-IoC容器

1. 注入方式

  1. 构造方法注入
    • 对象构造完,马上可以使用
    • 参数过长维护复杂,无法继承,无默认值
  2. setter方法注入
    • 方法可以命名,可以继承,可以有默认值
    • 无法构造完成后,立马使用
    • 可以解决 scope = singleton 的bean 的循环依赖
      • 提前暴露一个单例工厂方法,从而使其他bean能引用到该bean
        • addSingletionFactory
  3. 接口注入
    • 基本不用,强制实现不必要的接口

2. 两种类型的容器

BeanFactory 和 ApplicationContext 继承关系
  • BeanFactory 。基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延
    迟初始化策略(lazy-load)。
  • ApplicationContext 。 ApplicationContext 在 BeanFactory 的基础上构建,是相对比较高
    级的容器实现,除了拥有 BeanFactory 的所有支持, ApplicationContext 还提供了其他高级特性,比如事件发布、国际化信息支持等 ,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于 BeanFactory 来
    说, ApplicationContext 要求更多的系统资源,同时,因为在启动时就完成所有初始化,容
    器启动时间较之 BeanFactory 也会长一些。在那些系统资源充足,并且要求更多功能的场景中,
    ApplicationContext 类型的容器是比较合适的选择。

3. BeanFactory 的对象注册与依赖绑定方式

直接编码

BeanFactory 、 BeanDefinitionRegistry 以及 DefaultListableBeanFactory 的关系
  • BeanFactory 定义获取bean及bean的各种属性,各个 BeanFactory 的具体实现类负责具体Bean的注册以及管理工作
  • BeanDefinition 每个bean 都有一个BeanDefinition 对应,保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象
    类、构造方法参数以及其他属性等
  • BeanDefinitionRegistry 定义对BeanDefinition的各种增删改操作

外部配置文件方式

  • Properties文件格式
  • XML文件格式
  • 如果需要可以引入自己的文件格式

注解方式

  • 版本要求:Spring 2.5以及Java 5
    或者更高版本的情况之下

4. bean 的 scope (面试:spring bean 支持哪几种scope/作用域 )

<bean id="mockObject2" class="...MockBusinessObject"
scope="prototype"/>

scope 取值

  • singleton

    • 对象实例数量: 一个 所有对该对象的引用将共享这个实例
    • 生命周期: 从容器启动,第一请求而初始化以后,将一直存活到容器退出
  • prototype

    • 对象实例数量:多个 容器在接到该类型对象的请求的时候,会每次都重新生成一个新的对象实例给请求方
    • 生命周期: 对象的实例化以及属性设置等工作由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不再拥有当前返回对象的引用,请求方需要自己负责当前返回对象的后继生命周期的管理工作,包括该对象的销毁
  • request

    • 对象实例数量: 多个 每个HTTP请求创建一个全新的 RequestProcessor 对象供当前请求使用
    • 生命周期: 当请求结束后,该对象实例的生命周期即告结束
<bean id="requestProcessor" class="...RequestProcessor"
scope="request"/>
  • session
    • 对象实例数量: 多个 每个独立的session创建属于它们自己的全新的 UserPreferences 对象实例
    • 生命周期: session的生命周期
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

  • global session
    • 对象实例数量:
    • 生命周期: portlet的Web应用程序中才有意义,它映射到portlet的global范围的
      session, 如果在普通的基于servlet的Web应用中使用了这个类型的scope,容器会将其作为普通的session
      类型的scope对待
<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>
  • 自定义 scope ,可以根据自己的需要或者应用的场景,来添加自定义的scope类型

5. BeanFactoryPostProcessor

  • 作用: 允许我们在容器实
    例化相应对象之前,对注册到容器的 BeanDefinition 所保存的信息做相应的修改。,让我们对最终的 BeanDefinition 做一些额外的操作,比如修
    改其中bean定义的某些属性,为bean定义增加其他信息等 例如 我们使用占位符配置数据库相关信息,然后通过配置文件 配置实际的值。

6. bean的生命周期

graph TB
实例化bean对象-->设置对象属性
设置对象属性-->检查Aware相关接口并设置相关依赖
检查Aware相关接口并设置相关依赖-->beanPostProcessor前置处理
beanPostProcessor前置处理-->检查是否是InitializingBean以决定是否调用afterPropertiesSet
检查是否是InitializingBean以决定是否调用afterPropertiesSet-->检查是否配置有自定义init-method
检查是否配置有自定义init-method-->beanPostProcessor后置处理
beanPostProcessor后置处理-->注册必要的Destruction相关回调接口
注册必要的Destruction相关回调接口-->使用中
使用中-->是否实现DisPosableBean接口
是否实现DisPosableBean接口-->是否配置有自定义的destory方法

6.1 实例化bean对象,设置对象属性

  • 容器在内部实现的时候,采用“策略模式(Strategy Pattern)”来决定采用何种方式初始化bean实例。
    通常,可以通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类
  • 容器根据BeanDefintion 取得实例化信息,结合CglibSubclassingInstantiationStrategy策略以及不同的bean定义类型,就可以返回实例化完成的对象实例
    • 根据beandefinition 有没有lookup-override或者replace-override属性 判断是否用 cglib策略
  • 返回 BeanWrapper 对构造完成的对象实例进行包裹,返回相应的 BeanWrapper 实例
  • 通过BeanWrapper设置对象属性,免去直接使用Java反射API,java反射很多异常要处理

6.2 检查Aware相关接口并设置相关依赖

  • 当对象实例化完成并且相关属性以及依赖设置完成之后,Spring容器会检查当前对象实例是否实
    现了一系列的以 Aware 命名结尾的接口定义。如果是,则将这些 Aware 接口定义中规定的依赖注入给当前对象实例。
    • org.springframework.beans.factory.BeanNameAware 。如果Spring容器检测到当前对象实
      例实现了该接口,会将该对象实例的bean定义对应的 beanName 设置到当前对象实例。
    • org.springframework.beans.factory.BeanClassLoaderAware 。如果容器检测到当前对
      象实例实现了该接口,会将 对应加载当前 bean的Classloader注入当前对象实例。默认会使用
      加载org.springframework.util.ClassUtils类的Classloader。
    • org.springframework.beans.factory.BeanFactoryAware 。在介绍方法注入的时候,我们
      提到过使用该接口以便每次获取prototype类型bean的不同实例。如果对象声明实现了
      BeanFactoryAware 接口, BeanFactory 容器会将自身设置到当前对象实例。这样,当前对象
      实例就拥有了一个 BeanFactory 容器的引用,并且可以对这个容器内允许访问的对象按照需要
      进行访问。
    • ApplicationContext 很多 Aware 接口通过BeanPostProcessor 实现 如下ApplicationContextAwareProcessor的postProcessBeforeInitialization方法
package org.springframework.context.support;
class ApplicationContextAwareProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;
        if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    ApplicationContextAwareProcessor.this.invokeAwareInterfaces(bean);
                    return null;
                }
            }, acc);
        } else {
            this.invokeAwareInterfaces(bean);
        }

        return bean;
    }
}

6.3 beanPostProcessor

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;

    Object postProcessAfterInitialization (Object var1, String var2) throws BeansException;
}
  • postProcessBeforeInitialization 前置处理
  • postProcessAfterInitialization 后置处理
  • 可以自定义beanPostProcessor 处理
    public class PasswordDecodePostProcessor implements BeanPostProcessor {
    public Object postProcessAfterInitialization(Object object, String beanName)
    throws BeansException {
    return object;
    }
    public Object postProcessBeforeInitialization(Object object, String beanName)
    throws BeansException {
    if(object instanceof 我们想要处理的bean.class)
    {
     // 设置属性,加密解密等。
    }
    return object;
    }

}


6.4 InitializingBean,init-method

package org.springframework.beans.factory;
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
  • InitializingBean
    • 作用: 在对象实例化过程调用过“ BeanPostProcessor 的前置处理”
      之后,会接着检测当前对象是否实现了 InitializingBean 接口,如果是,则会调用其 afterPropertiesSet() 方法进一步调整对象实例的状态。
    • 场景: 在有些情况下,某个业务对象实例化完成后,还
      不能处于可以使用状态。这个时候就可以让该业务对象实现该接口,并在方法 afterPropertiesSet()
      中完成对该业务对象的后续处理 如图片验证码拦截器 在实例化之后,通过afterPropertiesSet 从配置中读取要拦截的路径
  • init-method
    • 作用: 自定义初始化操作可以以任何方式命名,还可以通
      过最顶层的 <beans> 的 default-init-method 统一指定。
    • 场景: InitializingBean 一样
  • 对比:InitializingBean 业务对象实现这个接口,有侵入性 init-method 就没有这个问题

6.5 注册必要的Destruction(一次性)相关回调接口

  • bean 使用前还有注册一些相关回调接口

6.6 DisposableBean,destroy-method

package org.springframework.beans.factory;

public interface DisposableBean {
    void destroy() throws Exception;
}
  • 作用: 为该实例注册一个用于对象销毁的回调(Callback),以便在这些singleton类型的对象实例销毁之
    前,执行销毁逻辑。只有该对象实例不再被使用的时候,
    才会执行相关的自定义销毁逻辑,此时通常也就是Spring容器关闭的时候
  • 执行对象的自定义销毁方法
    • BeanFactory destroySingletons()
    • ApplicationContext registerShutdownHook() 使用了addShutdownHook()
//m中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作。
Runtime.getRuntime().addShutdownHook(Thread hook)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容