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
57901
代码可运行
举报
文章被收录于专栏:泛泛聊后端泛泛聊后端
运行总次数:1
代码可运行

托管给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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
构建你的第一个零知识 snark 电路(Circom2)
https://blog.iden3.io/first-zk-proof.html
Tiny熊
2022/11/07
1.5K0
构建你的第一个零知识 snark 电路(Circom2)
密码学[4]:电路 R1CS QAP
设 \sum 是任意集合,\sum^* 是所有的长度有限的字符串 <x_1, .., x_n> ,其中 x_j 取自 \sum ,空字符串 <> ∈ \sum^* 。语言 L 是 \sum^* 的子集。在这种情况下,\sum 是语言 L 的子母表,\sum 中的元素是字母,L 中的元素是单词。如果有规则指定 \sum^* 中的字符串是否属于语言,该规则就被称为语法。如果 L_1 和 L_2 是基于同一个字母表的两个形式语言,且包含了相同的单词集,则称 L_1 和 L_2 是等价的。
谛听
2023/10/28
8410
用零知识证明解决投票安全
我们经常会遇到需要给别人投票的情况,比如有些公司会组织员工给领导做反向打分,但是往往员工都不敢“真心实意”的打分,为什么呢?归根结底是害怕所谓的匿名不是真匿名,万一领导拿到了投票数据给你穿个小鞋你就别混了。
qudamahcui
2018/12/15
2.1K0
一文弄懂 零知识证明中的 Ciruit、Witness、 Proof、 Commitment
在区块链和密码学领域,特别是在零知识证明(Zero-Knowledge Proofs, ZKP)的上下文中,Circuit(电路)、Witness(见证)、Proof(证明)和 Commitment(承诺)都是关键的概念。零知识证明(Zero-Knowledge Proofs, ZKP)技术是一个允许一方(证明者)向另一方(验证者)证明其知道某个信息,而无需透露任何关于该信息的具体内容的强大工具。这种技术不仅增强了隐私保护,还为区块链交易的安全性和透明性提供了支持。
天地一小儒
2024/04/20
1.1K1
区块链隐私保护技术解析——零知识证明
区块链技术最初给我们第一印象是其拥有匿名性,不可篡改性,一致性,分布式等特点。其中匿名性随着对区块链的进一步分析和一些信息情报的收集,一般区块链公链的匿名性都是较弱的。我们熟悉的比特币,以太坊等区块链的匿名性都是较弱的,可以实现交易追踪和地址的聚类,我们在区块链追踪这边也做了一些基础的工作,实现区块链的威胁情报与监管。但是可以通过密码学技术进一步增强区块链的匿名性,其中主流的方法有两种,一种是采用混币的方式其中最具代表性的公链技术是门罗币,这个技术我们在上一篇《区块链隐私保护技术解析——之门罗币(monero)》中进行了详细的分析;另一种技术是采用零知识证明的方式实现强匿名性具有代表性的公链技术是大零币ZEC(Zerocash)。
绿盟科技研究通讯
2022/03/11
2.8K0
区块链隐私保护技术解析——零知识证明
零知识证明学习资源汇总
Github 地址:https://github.com/sec-bit/learning-zkp/blob/master/zkp-resource-list.md
爬虫
2019/11/15
1.5K0
零知识证明;Halo2原理;举例说明算术电路、转换为约束系统、多项式承诺举例形式和数值;PLANK算术化;
零知识证明(Zero-Knowledge Proof,简称ZKP)是一种密码学工具,允许互不信任的通信双方之间证明某个命题的有效性,同时不泄露任何额外信息。这种技术最初由莎菲·戈德瓦塞尔、S.Micali及C.Rackoff在20世纪80年代初提出,其核心在于证明者能够在不向验证者提供任何有用信息的情况下,使验证者相信某个论断是正确的。
zhangjiqun
2024/08/14
3380
零知识证明是零信任吗
如果只是为了回答标题问题,两个字就可以:不是。但还是想顺便说说,零知识证明(ZKP)究竟是什么。
网络安全观
2021/02/24
1.1K0
详解零知识证明的四大基础技术,如何与以太坊发生反应
雷锋网按:原文标题为《zkSNARKs in a nutshell》,作者是以太坊智能合约语言Solidity的发明人Christian Reitwiessner。译者杨文涛,授权转载自作者知乎专栏。 摘要: zkSNARKs(zero-knowledge succint non-interactive arguments of knowledge)的成功实现让我们印象深刻,因为你可以在不执行,甚至在不知道执行具体内容的情况下确定某个计算的结果是否正确——而你唯一知道的信息就是它正确地完成了。但是不幸的是,
企鹅号小编
2018/01/22
1.6K0
详解零知识证明的四大基础技术,如何与以太坊发生反应
去中心化数字身份DID简介——四、用户属性的零知识证明
在上一篇文章中,我们介绍了用户具有多个身份属性时,选择性的把其中的一个属性暴露出来,而不会造成其他信息的暴露。更进一步的情况,某些时候我们只需要验证用户的年龄达到多少岁,或者小于多少岁,但是并不关心用户的具体年龄和出生日期,比如在购买烟酒时,商家需要验证用户的年龄大于18岁。除了年龄,住址、民族等都可能会有对某个断言进行验证的情况。比如某旅游景点,对本市所有居民免费,所以居民只需要证明自己身份证上的住址在某市,而不需要暴露具体的居住地址。这些只给出证明的答案,而不暴露其他任何身份信息的情况,都是零知识证明的范畴。
深蓝studyzy
2022/09/19
1.5K0
去中心化数字身份DID简介——四、用户属性的零知识证明
蚂蚁区块链第7课 零知识证明隐私保护原理和蚂蚁BAAS接口调用实现
本文试图普及隐私保护和零知识证明的相关技术知识,尝试使用更简单的描述来理解复杂的数学算法和技术原理。同时,也提供了蚂蚁区块链已经实现的隐私保护的接口函数说明。 本文涉及的专业知识有零知识证明,zk-SNARKs和 BulletProofs(防弹证明),佩德森承诺等。
辉哥
2019/04/01
1.9K0
蚂蚁区块链第7课 零知识证明隐私保护原理和蚂蚁BAAS接口调用实现
理解Groth16,一些细节上的说明
V 神曾经写过一篇非常好的介绍 R1CS 与 QAP 问题的文章[2]。但是,对于不熟悉密码学[3]的,或者说如何使用密码学的思想来解决问题的票友们来说,文章中的一些逻辑上的跨度还是大了一些。尤其是在 R1CS 转换成多项式的地方,初次接触的人可能会一脸懵逼,不明白为什么要这么做。下面我就从我的理解来谈一谈,从 R1CS 到 QAP 这一过程。
Tiny熊
2022/05/25
1.2K0
理解Groth16,一些细节上的说明
Hyperledger Fabric中的零知识证明
Fabric 1.3中的新增的idemixer(Identity Mixer)以前不大懂zero-knowledge proof(零知识证明),原本觉得PKI基础的MSP是比较常用和稳健的方式,新加个验证方式是不是有点增加复杂性。
Zeal
2020/11/11
1.7K0
Hyperledger Fabric中的零知识证明
Remix IDE 发布了 VSCode 插件
Remix 项目--包括 Remix IDE 及其相关库,发布了 VSCode 的 Remix 插件的测试版本。现在可以在 VSCode 的插件市场上搜索:Remix
Tiny熊
2021/05/11
2.7K0
Remix IDE 发布了 VSCode 插件
每周以太坊进展2022/6/18
(编者注:本翻译不代表登链社区的立场,也不代表我们(有能力并且已经)核实所有的事实并把他的观点分离开来。)
Tiny熊
2022/11/07
3210
以太坊主网部署终极指南
我们都喜欢以太坊,所以你已经创建了一些出色的智能合约。它们通过单元测试和测试网进行了密集的测试。现在终于到了上主网的时候了。但这是一个棘手的事情...
Tiny熊
2021/05/11
2K0
以太坊主网部署终极指南
在区块链浏览器上验证Solidity源码(standard-input-json)
Convert/Escapes an object to a JSON string 将solidity[2]源码转换为JSON字符串
Tiny熊
2022/02/18
1.3K0
在区块链浏览器上验证Solidity源码(standard-input-json)
密码学[5]:Groth16
zero-knowledge protocol:是一组数学规则,根据这些规则,在给定 instance 后,prover 可以向 verifier 证明自己知道该 instance 的 witness 而不揭露 witness 任何信息。
谛听
2023/10/30
6611
二层网络上的以太坊智能合约: Optimistic Rollup
这篇文章概述了optimistic rollup:一种使用OVM[4]在二层网网络上启用智能合约的结构。该构造大量借鉴了plasma和zkRollup设计,并以Vitalik所描述的 shadow chains[5] 为基础 。此结构类似于Plasma[6],但放弃了一些扩展性,以便在二层网络中运行完全通用的智能合约(例如Solidity),同时还享有和一层网络相同的安全性。optimistic rollup的可扩展性与一层网络数据可用带宽成正比,一层网络可以包括Eth1,Eth2, 甚至Bitcoin现金或以太坊经典[7],optimistic rollup都可以在二层网络上提供类EVM的链。
Tiny熊
2020/08/04
1.4K0
二层网络上的以太坊智能合约: Optimistic Rollup
[译] 用 Truffle 插件自动在Etherscan上验证合约代码
Etherscan是以太坊上最受欢迎的浏览器。它的一大功能是验证智能合约的源代码[5]。使用户可以在使用合约之前通过源码了解合约的功能。从而增加用户对合约的信任,也因此使开发者受益。
Tiny熊
2020/08/04
2K0
[译] 用 Truffle 插件自动在Etherscan上验证合约代码
推荐阅读
相关推荐
构建你的第一个零知识 snark 电路(Circom2)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验