Customizing the Nature of a Bean,最早筹备跳过这部分内容,然而感觉这部分内容是Spring Bean生命周期中的一个重要局部,跳过了可能会影响通往NB之路,所以还是要认真学习一下。

Spring通过三种类型的接口实现对Bean行为或状态的扭转或定制:

  1. 生命周期回调
  2. ApplicationContextAware and BeanNameAware
  3. 其余Aware接口

生命周期回调

有两种类型的回调:初始化回调、临终回调。对不起我不应该管这个DisposableBean接口的destroy()办法叫临终回调,不过的确比拟形象。

Spring提供了多种不同抉择来实现申明周期回调:

  1. 通过InitializingBean接口或DisposableBean接口实现
  2. 通过配置init-method实现
  3. 应用JSR-250 @PostConstruct和@PreDestroy注解
  4. 通过BeanPostProcessor接口
  5. 通过Lifecycle接口

初始化回调

实现InitializingBean的afterPropertiesSet()办法,afterPropertiesSet()办法在咱们上一篇文章剖析Bean创立过程的9步工作法的第6步中会被调用到:

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)            throws Throwable {        boolean isInitializingBean = (bean instanceof InitializingBean);        if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {            if (logger.isTraceEnabled()) {                logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");            }            if (System.getSecurityManager() != null) {                try {                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {                        ((InitializingBean) bean).afterPropertiesSet();                        return null;                    }, getAccessControlContext());                }                catch (PrivilegedActionException pae) {                    throw pae.getException();                }            }            else {                ((InitializingBean) bean).afterPropertiesSet();            }        }        if (mbd != null && bean.getClass() != NullBean.class) {            String initMethodName = mbd.getInitMethodName();            if (StringUtils.hasLength(initMethodName) &&                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&                    !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {                invokeCustomInitMethod(beanName, bean, mbd);            }        }    }

从下面源码能够看到,除InitializingBean接口之外,还能够通过init-method的形式进行初始化,不过,极其状况下:两者同时应用,并且init-method也配置为afterPropertiesSet()办法,那么InitializingBean接口的afterPropertiesSet()办法会被回调、init-method办法不会。

Destruction 回调

与初始化办法回调相似,以下形式供选择:

  1. 实现接口DisposableBean的destroy()办法
  2. 定义destroy-method办法

默认初始化和Destruction 回调

定义在<beans> 属性上的初始化以及销毁回调,能够对所有bean失效。这种状况下默认所有bean都对立应用初始化和销毁回调办法,因而能够简化配置。

<beans default-init-method="init">    <bean id="xxx"     </bean>    ...</beans>

即便设置了默认的初始化及销毁回调,仍然能够通过bean标签的init-method和destory-method来笼罩默认办法。

组合应用生命周期回调机制

Spring2.5之后,你能够组合应用以下办法实现生命周期回调:

  1. InitializingBean / DisposableBean 接口
  2. 配置init() / destroy() 办法
  3. 采纳JSR250 @PostConstruct 和 @PreDestroy 注解

如果不同的生命周期回调机制以雷同的办法名作用在同一个bean上,则该办法只会被回调一次。咱们在后面章节中曾经看到过Spring初始化回调办法中的无关afterPropertiesSet办法的例子了。

如果不同的回调机制、以不同的办法名作用在同一个bean上,则依照如下程序执行回调:

  1. @PostConstruct注解标注的办法
  2. InitializingBean接口的afterPropertiesSet() 办法
  3. 配置的init() 办法

销毁回调办法的程序同上。

启动及关机回调

有时候咱们可能须要在系统启动(或者Spring IoC容器启动)时执行特定的资源申请操作,在零碎shutdown前执行资源开释操作。

Lifecycle接口能够满足以上需要,start()办法负责启动回调、stop()办法执行关机回调。

ApplicationContextAware and BeanNameAware

ApplicationContextAware接口提供了一个机会,让你从一般的Spring Bean中能够取得到创立他的ApplicationContext。

BeanNameAware接口通过setBeanName办法,为bean提供了一种能力:晓得本人在Spring Ioc容器中的名字。

集体认为BeanNameAware接口用处无限,因为一般来讲bean不须要通过BeanNameAware接口的形式、而是通过其余形式晓得本人在Spring IoC中的名字(或者有什么非凡场景须要,须要的时候你能立即想到这种形式即可)。

ApplicationContextAware,一种用处是为以后bean获取Spring IoC容器中的其余Bean提供了不便,然而Spring官网并不倡议这么应用:

One use would be the programmatic retrieval of other beans. Sometimes this capability is useful. However, in general, you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to beans as properties.

另外一种用处是通过这种形式,利用ApplicationContext去获取Spring容器的文件资源、公布Application事件等等。这些个性咱们后续会深入研究。

ApplicationContextAware接口的形式获取ApplicationContext其实非常简单,你的bean实现ApplicationContextAware接口,而后实现setApplicationContext办法,Spring IoC容器就会在postProcessBeforeInitialization阶段回调setApplicationContext办法,乖乖地把ApplicationContext给你送进去。

另外你还能够通过@Autowired形式获取到ApplicationContext,这种形式更加简略不便、灵便,所有都遵循@Autowired注解的准则。

为什么通过@Autowired能够注入ApplicationContext对象?。

倒着查,很快就能找到答案。先去看DefaultlistableBeanFactory的findAutowireCandidates办法,这个办法负责查找主动拆卸的对象:

protected Map<String, Object> findAutowireCandidates(            @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {        //1. 依照类型匹配,包含父类        String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(                this, requiredType, true, descriptor.isEager());        Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);        //2.解决resolvableDependencies,比方ResourceLoader、ApplicationEventPublisher、ApplicationContext等        for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {            Class<?> autowiringType = classObjectEntry.getKey();            if (autowiringType.isAssignableFrom(requiredType)) {                Object autowiringValue = classObjectEntry.getValue();                autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);                if (requiredType.isInstance(autowiringValue)) {                    result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);                    break;                }            }        }       ....省略n行代码

发现会从resolvableDependencies中匹配对象,而后再来看看resolvableDependencies中到底放了啥。

找到AbstactApplicationContext的prepareBeanFactory办法,Spring IoC初始化过程中会调用,发现有如下几行代码:

        // BeanFactory interface not registered as resolvable type in a plain factory.        // MessageSource registered (and found for autowiring) as a bean.        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);        beanFactory.registerResolvableDependency(ResourceLoader.class, this);        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

最初一行registerResolvableDependency办法,参数是ApplicationContext本人。

而后咱们看一下registerResolvableDependency办法:

    @Override    public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {        Assert.notNull(dependencyType, "Dependency type must not be null");        if (autowiredValue != null) {            if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {                throw new IllegalArgumentException("Value [" + autowiredValue +                        "] does not implement specified dependency type [" + dependencyType.getName() + "]");            }            this.resolvableDependencies.put(dependencyType, autowiredValue);        }    }

水落石出!

上一篇 Spring FrameWork从入门到NB - 单例Bean生命周期