Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring IoC 容器扩展

Spring IoC 容器扩展

作者头像
李鸿坤
发布于 2020-07-18 10:40:37
发布于 2020-07-18 10:40:37
57900
代码可运行
举报
文章被收录于专栏:泛泛聊后端泛泛聊后端
运行总次数:0
代码可运行

托管给Spring IoC 容器的Bean虽然不知道容器的存在,但是容器也提供了完整的扩展点,让使用者动态干预bean的定义和实例化,以及生命周期相关的钩子。

生命周期

Bean实例化和销毁的时候,容器提供了默认的Hook,它们分别是InitializingBean和DisposableBean。实现后,容器将在bean实例化和销毁的时候进行调用。如果不实现这两个接口,同样可以使用该功能,那就是在配置对应的init-method和destroy-method。JSR-250定义了两个注解@PostConstruct and @PreDestroy同样是可以实现这样的功能。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.lihongkun.labs.spring.container.lifecycle;
import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;
public class LifeCycleBean implements InitializingBean, DisposableBean {
    private String propertyValue;
    public void setPropertyValue(String propertyValue) {        this.propertyValue = propertyValue;        System.out.println("[lifecycle event] setter inject");    }
    public LifeCycleBean(){        System.out.println("[lifecycle event] constructor");    }
    @PostConstruct    public void postConstruct(){        System.out.println("[lifecycle event] PostConstruct");    }
    @PreDestroy    public void preDestroy(){        System.out.println("[lifecycle event] PreDestroy");    }
    public void initMethod(){        System.out.println("[lifecycle event] initMethod");    }
    public void destroyMethod(){        System.out.println("[lifecycle event] destroyMethod");    }
    @Override    public void destroy() throws Exception {        System.out.println("[lifecycle event] destroy");    }
    @Override    public void afterPropertiesSet() throws Exception {        System.out.println("[lifecycle event] afterPropertiesSet");    }}

bean的配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:context="http://www.springframework.org/schema/context"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans        https://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/context        https://www.springframework.org/schema/context/spring-context.xsd">    <context:component-scan base-package="org.example"/>
    <bean id="lifeCycleBean"          init-method="initMethod"          destroy-method="destroyMethod"          class="com.lihongkun.labs.spring.container.lifecycle.LifeCycleBean" >        <property name="propertyValue" value="hello" />    </bean></beans>

执行后的结果是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[lifecycle event] constructor[lifecycle event] setter inject[lifecycle event] PostConstruct[lifecycle event] afterPropertiesSet[lifecycle event] initMethod[lifecycle event] PreDestroy[lifecycle event] destroy[lifecycle event] destroyMethod

可以看出执行顺序是 :构造函数 => 属性注入 => PostConstruct => InitializingBean => init-method配置 => PreDestroy => DisposableBean => destroy-method配置。

InitializingBean 和 DisposableBean 的实现方式是和Spring容器耦合的。推荐的是JSR-250的注解,跟容器无关,切换其他容器的时候也是有对应的功能。如果不能使用的话,次优选择是init-method配置和destroy-method配置,保持类的干净,也是不耦合于容器。

容器扩展点

除了单个bean本身的事件,Spring容器提供了BeanPostProcessor和BeanFactoryPostProcessor两个容器级别的扩展点。它们被大量用在和Spring结合的一些基础框架上。

BeanPostProcessor

BeanPostProcessor 作用在实例化后的bean上,允许使用者在容器实例化bean的后,对其进行修改。它提供了两个方法,传入bean和beanName,返回处理后的bean。用法示例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;
public class HelloBeanPostProcessor implements BeanPostProcessor {    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        System.out.println("[lifecycle event] postProcessBeforeInitialization");        return bean;    }
    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        System.out.println("[lifecycle event] postProcessAfterInitialization");        return bean;    }}

通常应用于两种场景,对实现了某个接口的bean进行填充或者该接口相关的操作。Spring容器使用这个扩展点提供了一些特性。如postProcessBeforeInitialization实现了ApplicationContext相关的Aware机制。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ApplicationContextAwareProcessor implements BeanPostProcessor {
  private final ConfigurableApplicationContext applicationContext;
  private final StringValueResolver embeddedValueResolver;

  /**   * Create a new ApplicationContextAwareProcessor for the given context.   */  public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {    this.applicationContext = applicationContext;    this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());  }

  @Override  @Nullable  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((PrivilegedAction<Object>) () -> {        invokeAwareInterfaces(bean);        return null;      }, acc);    }    else {      invokeAwareInterfaces(bean);    }
    return bean;  }
  private void invokeAwareInterfaces(Object bean) {    if (bean instanceof Aware) {      if (bean instanceof EnvironmentAware) {        ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());      }      if (bean instanceof EmbeddedValueResolverAware) {        ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);      }      if (bean instanceof ResourceLoaderAware) {        ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);      }      if (bean instanceof ApplicationEventPublisherAware) {        ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);      }      if (bean instanceof MessageSourceAware) {        ((MessageSourceAware) bean).setMessageSource(this.applicationContext);      }      if (bean instanceof ApplicationContextAware) {        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);      }    }  }
  @Override  public Object postProcessAfterInitialization(Object bean, String beanName) {    return bean;  }
}

上述代码即是Spring容器使用了BeanPostProcessor实现了Aware机制里面的EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware。

另外一种场景是需要对实例化后的Bean进行代理包装,postProcessAfterInitialization很容易想到可以直接把bean的实现给替换了,实际上Spring的AOP机制也是用此扩展来实现的。

BeanFactoryPostProcessor

BeanFactoryPostProcessor主要使用在修改容器的bean definition上面,它的阶段在更前面的环节,可以达到动态修改bean配置的能力。它只有一个postProcessBeanFactory方法,使用示例如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class HelloBeanFactoryPostProcessor implements BeanFactoryPostProcessor {    @Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {        System.out.println("[lifecycle event] postProcessBeanFactory");    }}

典型的应用即Spring容器中@Value("${property}")的实现。它是通过PropertyPlaceholderConfigurer类实现,继承自PropertyResourceConfigurer实现了BeanFactoryPostProcessor。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {    try {      // 合并本地属性和外部指定的属性文件资源中的属性       Properties mergedProps = mergeProperties();
      // Convert the merged properties, if necessary.      // 将属性的值做转换(仅在必要的时候做)      convertProperties(mergedProps);
      // Let the subclass process the properties.      // 对容器中的每个bean定义进行处理,也就是替换每个bean定义中的属性中的占位符       processProperties(beanFactory, mergedProps);    }    catch (IOException ex) {      throw new BeanInitializationException("Could not load properties", ex);    }  }

小结

Bean生命周期方法和容器级别的扩展点可以做资源初始化和销毁、动态修改bean对象以及动态修改bean定义。它们以一定的顺序作用在bean上。以下结果是示例中所输出的顺序。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[lifecycle event] postProcessBeanFactory[lifecycle event] constructor[lifecycle event] setter inject[lifecycle event] postProcessBeforeInitialization[lifecycle event] PostConstruct[lifecycle event] afterPropertiesSet[lifecycle event] initMethod[lifecycle event] postProcessAfterInitialization[lifecycle event] PreDestroy[lifecycle event] destroy[lifecycle event] destroyMethod
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 泛泛聊后端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
三万字盘点Spring/Boot的那些常用扩展点
Spring对于每个Java后端程序员来说肯定不陌生,日常开发和面试必备的。本文就来盘点Spring/SpringBoot常见的扩展点,同时也来看看常见的开源框架是如何基于这些扩展点跟Spring/SpringBoot整合的。
三友的java日记
2022/07/27
1.9K3
三万字盘点Spring/Boot的那些常用扩展点
Spring5 - Bean的初始化和销毁的4种方式
概述 针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法 针对原型bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的
小小工匠
2021/08/17
5690
Spring Bean 生命周期
Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,掌握这些可以加深对 Spring 的理解。
云扬四海
2019/06/05
5150
Spring Bean 生命周期
Spring入门:The IoC Container,实践篇(上)
Spring 框架的 IoC 容器(Inversion of Control,Ioc)是 Spring 框架中最基础、最重要的部分。Ioc 也被称为依赖注入(Dependency Injection,DI),是一种将组件依赖项的创建和管理外部化的技术。
WEBJ2EE
2019/09/17
9140
Spring入门:The IoC Container,实践篇(上)
Spring 复盘(三) | Bean 的生命周期
在传统的 Java 应用中,bean 的生命周期很简单,使用 Java 关键字 new 进行Bean 的实例化,然后该 Bean 就能够使用了。一旦 bean 不再被使用,则由 Java 自动进行垃圾回收,简直不要太简单。
JavaFish
2019/10/17
5110
Spring 复盘(三) | Bean 的生命周期
Spring高手之路6——Bean生命周期的扩展点:BeanPostProcessor
在前一篇讲解生命周期的时候就可以讲解后置处理器了,但是内容比较多,还是分开来讲解。
砖业洋__
2023/06/27
1K0
Spring高手之路6——Bean生命周期的扩展点:BeanPostProcessor
【Spring】Spring常用注解(中)
为了伟大的房产事业
2024/03/15
700
15个Spring扩展点,一般人知道的不超过5个!
Spring的核心思想就是容器,当容器refresh的时候,外部看上去风平浪静,其实内部则是一片惊涛骇浪,汪洋一片。
田维常
2022/11/25
2.4K0
15个Spring扩展点,一般人知道的不超过5个!
Spring 学习二、Bean生命周期相关注解
如果Bean的作用域是prototype 销毁方法会被Spring容器调用,但是如果是多例方法销毁方法就不会被调用
梅花
2020/09/28
8430
【Spring注解驱动开发】BeanPostProcessor在Spring底层是如何使用的?看完这篇我懂了!!
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
6930
【Spring注解驱动开发】BeanPostProcessor在Spring底层是如何使用的?看完这篇我懂了!!
Spring源码初探-IOC(5)-ApplicationContext功能扩展及其扩展点
前面几篇关于Spring的文章简单阐述了使用BeanFactory作为容器时bean的初始化过程。然而在实际使用中,我们并不会直接接触和编码BeanFactory,我们通常会使用另外一个功能更强、更完善的容器ApplicationContext。本文粗略讲述了ApplicationContext对于BeanFactory的功能扩展,并将重点放在了Spring在容器启动和初始化过程中提供的扩展点和事件发布上。扩展点让我们能够“插手和干预”Bean的初始化,通过容器发布的事件得以了解容器的一些内部过程。
LNAmp
2018/09/05
4840
Spring源码初探-IOC(5)-ApplicationContext功能扩展及其扩展点
大厂高频面试题Spring Bean生命周期最详解
Spring作为当前Java最流行、最强大的轻量级框架。Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题。程序员应该都知道Spring的基础容器是ApplicationContext。应很多粉丝的强烈建议,本文我来分析分析 ApplicationContext中Bean的生命周期。ApplicationContext是顶层容器接口BeanFactory的实现类,因此,我们了解了ApplicationContext的生命周期逻辑,也基本上了解了其他类型容器的生命周期逻辑。
Tom弹架构
2021/12/21
1.4K0
大厂高频面试题Spring Bean生命周期最详解
Spring源码学习笔记(8)——Bean的生命周期
Bean的声明周期是指Bean从创建、初始化到销毁的整个过程。在Spring中,Bean的生命周期都是交给IoC容器管理的。Bean的主要生命周期主要有四个阶段:
张申傲
2020/09/03
2.2K0
浅析spring——IOC 之 分析 bean 的生命周期
在分析 Spring Bean 实例化过程中提到 Spring 并不是一启动容器就开启 bean 的实例化进程,只有当客户端通过显示或者隐式的方式调用 BeanFactory 的 getBean() 方法来请求某个实例对象的时候,它才会触发相应 bean 的实例化进程,当然也可以选择直接使用 ApplicationContext 容器,因为该容器启动的时候会立刻调用注册到该容器所有 bean 定义的实例化方法。当然对于 BeanFactory 容器而言并不是所有的 getBean() 方法都会触发实例化进程,比如 signleton 类型的 bean,该类型的 bean 只会在第一次调用 getBean() 的时候才会触发,而后续的调用则会直接返回容器缓存中的实例对象。
苏先生
2019/04/28
6340
浅析spring——IOC 之 分析 bean 的生命周期
【String注解驱动开发】针对bean的生命周期,我们究竟能做哪些工作?
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
2630
Spring中Bean的生命周期
大家好,我是 默语,别名默语博主,擅长的技术领域包括Java、运维和人工智能。我的技术背景扎实,涵盖了从后端开发到前端框架的各个方面,特别是在Java 性能优化、多线程编程、算法优化等领域有深厚造诣。
默 语
2024/11/25
1160
Spring中Bean的生命周期
【原创】2w 字搞懂 Spring Bean 的一生
当我们不用Spring进行开发时,我们需要在代码中设置对象的依赖关系。当我们用了Spring之后,由Spring来管理这种依赖关系,当我们想使用对象时,直接从Spring容器中获取即可
Java识堂
2021/06/01
7810
【原创】2w 字搞懂 Spring Bean 的一生
万能的BeanPostProcessor是如何让spring无限扩展的?
很多朋友一提到spring,首先想到的肯定是IOC(控制反转)和 AOP (面向切面编程),没错,这两个是spring的核心功能。但是什么技术让spring拥有如此强大的扩展能力,
苏三说技术
2020/10/15
2.3K0
万能的BeanPostProcessor是如何让spring无限扩展的?
springbean的生命周期详细_fragment生命周期详解
Spring是我们每天都在使用的框架,Bean是被Spring管理的Java对象,是Spring框架最重要的部分之一,那么让我们一起了解一下Spring中Bean的生命周期是怎样的吧
全栈程序员站长
2022/10/02
4180
springbean的生命周期详细_fragment生命周期详解
Spring 中 Bean 的生命周期
所谓 Bean 的生命周期,就是一个 Bean 从创建到销毁,所经历的各种方法调用。大致包含下面几个方法(不是全部)
水货程序员
2018/11/13
4.4K0
推荐阅读
相关推荐
三万字盘点Spring/Boot的那些常用扩展点
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验