BeanPostProcessor和Ordered

news2024/9/21 0:40:44

1. 概述

BeanPostProcessor 和 Ordered 接口用于在Spring容器初始化Bean的过程中进行自定义处理,并控制处理顺序

2. BeanPostProcessor

BeanPostProcessor 接口允许你在Spring容器初始化Bean的前后对Bean进行自定义处理。它有两个方法:

  • postProcessBeforeInitialization(Object bean, String beanName):在Bean初始化之前调用。
  • postProcessAfterInitialization(Object bean, String beanName):在Bean初始化之后调用。
    • bean:容器正在创建的那个bean的引用;
    • beanName:容器正在创建的那个bean的名称;

2.1 bean的生命周期

在这里插入图片描述

描述如下:

  1. 首先由Spring容器创建bean实例;
  2. 为bean的属性注入值;
  3. 若bean实现了各类Aware接口,则调用相应的set方法,
    • 比如说,实现了BeanNameAware接口的bean,此时容器将调用bean的setBeanName方法,将bean的name作为参数;
    • 实现了ApplicationContextAware接口的bean,此时容器将执行bean的setApplicationContext方法,将bean所在的上下文对象作为参数……
  4. 若容器中包含实现了BeanPostProcessor接口的bean,则此时将调用这些bean的postProcessBeforeInitialization方法,将当前正在创建的bean的引用以及bean的name作为参数传入;
  5. 若bean实现了InitializingBean接口,此时将调用bean的afterPropertiesSet方法;
  6. 若bean指定了自定义的初始化方法,比如说通过配置文件的init-method选项,则此时将执行这个自定义初始化方法;
  7. 若容器中包含实现了BeanPostProcessor接口的bean,则此时将调用这些bean的postProcessAfterInitialization方法,将当前正在创建的bean的引用以及bean的name作为参数传入;
    • 可以在一个容器中注册多个不同的BeanPostProcessor的实现类对象,而bean在创建的过程中,将会轮流执行这些对象实现的before和after方法
    • 执行顺序通过BeanPostProcessor的实现类实现这个Ordered接口,并实现接口的getOrder方法
  8. 这个时候,bean就算是初始化完毕,可以被使用了,在容器销毁之前,这个对象将一直保存在容器中;
  9. bean实现了DisposableBean接口,则在容器销毁时,会调用bean的destroy方法;
  10. 如果bean定义了自定义的销毁方法,则在容器销毁时,会调用这个自定义的销毁方法;
  11. 容器销毁成功,bean也被回收

2.2 使用注意

2.2.1 BeanPostProcessor依赖的bean,不会执行BeanPostProcessor的方法

当我们在BeanPostProcessor的实现类中,依赖了其他的bean,
那么被依赖的bean被创建时,将不会执行它所在的BeanPostProcessor实现类实现的方法

比如我们修改PostBean的实现,如下所示:

  • 容器在创建User这个bean时,不会执行PostBean实现的两个方法,
  • 因为由于PostBean依赖于user,所以user需要在PostBean之前创建完成,
  • 这也就意味着在user创建时,PostBean还未初始化完成,所以不会调用它的方法
@Component
public class PostBean implements BeanPostProcessor, Ordered {
    // 让PostBean依赖User
    @Autowired
    private User user;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) 
        throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) 
        throws BeansException {
        return bean;
    }
}

2.2.2 BeanPostProcessor以及依赖的bean无法使用AOP

Spring的AOP代理就是作为BeanPostProcessor实现的

所以我们无法对BeanPostProcessor的实现类使用AOP织入通知,

也无法对BeanPostProcessor的实现类依赖的bean使用AOP织入通知。

2.3 将BeanPostProcessor注册到Spring容器中

2.3.1 @Component注解

使用@Component注解:在实现类上添加@Component注解,这样Spring会自动扫描并注册这个bean。

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    // 实现方法
}

2.3.2 使用@Bean配置BeanPostProcessor的限制

使用Java配置类:如果你使用的是Java配置类,可以在配置类中注册这个bean。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

示例如下:


/**
 * 此BeanPostProcessor的实现类,还实现了Ordered接口
 */
public class PostBean implements BeanPostProcessor, Ordered {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("before -- " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("after -- " + beanName);
        return bean;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

在配置类中,声明PostBean可以有以下几种方式

  1. 只有第一种和第二种方式,会让Spring容器将PostBean当作BeanPostProcessor处理
  2. 而第三种方式,则会被当作一个普通Bean处理,实现BeanPostProcessor的两个方法都不会被调用,
    • 因为在PostBean的继承体系中,Ordered和BeanPostProcessor是同级别的,
    • Spring无法识别出这个Ordered对象,也是一个BeanPostProcessor对象;
    • 但是使用PostBean却可以,因为PostBean类型就是BeanPostProcessor的子类型
    • 所以,在使用@Bean声明工厂方法返回BeanPostProcessor实现类对象时,返回值必须是BeanPostProcessor类型,或者更低级的类型
    @Configuration
    public class BeanConfig {
    
        // 方式1:PostBean
        @Bean
        public PostBean postBean() {
            return new PostBean();
        }
    
        // 方式2:返回值为BeanPostProcessor
        @Bean
        public BeanPostProcessor postBean() {
            return new PostBean();
        }
    
        // 方式3:返回值为Ordered
        @Bean
        public Ordered postBean() {
            return new PostBean();
        }
    }
    

2.3.3 spring.factories

创建 BeanPostProcessor 实现类:

首先,创建一个实现 BeanPostProcessor 接口的类。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyAutoConfiguration {

    @Bean
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

创建自动配置类:创建一个自动配置类,并在其中定义 BeanPostProcessor 的 @Bean 方法

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyAutoConfiguration {

    @Bean
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

创建 spring.factories 文件:在 src/main/resources/META-INF/ 目录下创建 spring.factories 文件,并在其中添加自动配置类的全限定名

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration

目录结构

src/main/java/
    com/example/
        MyBeanPostProcessor.java
        MyAutoConfiguration.java
src/main/resources/
    META-INF/
        spring.factories

2.3.4 Xml

在XML中注册这个bean。

<bean id="myBeanPostProcessor" class="com.example.MyBeanPostProcessor"/>

3. Order

Ordered 接口用于控制多个 BeanPostProcessor 的执行顺序。它有一个方法:

  • getOrder():返回一个整数值,表示处理器的顺序。值越小,优先级越高。

4. 多个 BeanPostProcessor 的顺序

如果有多个 BeanPostProcessor,可以通过实现 Ordered 接口来控制它们的执行顺序。值越小,优先级越高。

5. 举例

自定义Bean后处理器

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor, Ordered {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) {
            System.out.println("Before Initialization: " + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) {
            System.out.println("After Initialization: " + beanName);
        }
        return bean;
    }

    @Override
    public int getOrder() {
        return 1; // 优先级,值越小优先级越高
    }
}

服务类

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public void serve() {
        System.out.println("Service method executed");
    }
}

主类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

另一个自定义Bean后处理器

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

@Component
public class AnotherBeanPostProcessor implements BeanPostProcessor, Ordered {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) {
            System.out.println("Another Before Initialization: " + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) {
            System.out.println("Another After Initialization: " + beanName);
        }
        return bean;
    }

    @Override
    public int getOrder() {
        return 2; // 优先级,值越小优先级越高
    }
}

运行示例

Before Initialization: myService
Another Before Initialization: myService
After Initialization: myService
Another After Initialization: myService
Service method executed

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2079348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

zabbix对接Grafana

1.grafana安装 Download Grafana | Grafana Labs sudo yum install -y https://dl.grafana.com/oss/release/grafana-11.1.4-1.x86_64.rpm 2.zabbix插件安装 Grafana 默认并没有 zabbix 数据源的支持&#xff0c;只有安装了zabbix插件&#xff0c;才可以在grafana中添加zabbi…

峟思固定测斜仪的工作原理与应用

固定测斜仪作为一种精密的测量仪器&#xff0c;在地质工程、土木工程、矿山安全等领域中发挥着至关重要的作用。它通过测量土体或岩体内部的水平位移&#xff0c;为工程安全监测提供了可靠的数据支持。本文将详细介绍固定测斜仪的工作原理、结构组成以及其在实际应用中的表现。…

一文读懂 DDD领域驱动设计

DDD&#xff08;Domain-Driven Design&#xff0c;领域驱动设计&#xff09;是一种软件开发方法&#xff0c;它强调软件系统设计应该以问题领域为中心&#xff0c;而不是技术实现为主导。DDD通过一系列手段如统一语言、业务抽象、领域划分和领域建模等来控制软件复杂度&#xf…

快手小店自动回复机器人脚本

快手小店自动回复机器人是一种利用人工智能AI技术&#xff0c;能够根据用户的会话咨询内容自动回复的工具。这种机器人可以帮助快手小店主快速、高效地回复客户消息&#xff0c;提升店铺的客户服务质量和销售效率。 甜羊浏览器是一款基于Chromium内核开发的国产浏览器&#xff…

OpenAI API: How to count tokens before API request

题意&#xff1a;“OpenAI API&#xff1a;如何在 API 请求之前计算令牌数量” 问题背景&#xff1a; I would like to count the tokens of my OpenAI API request in R before sending it (version gpt-3.5-turbo). Since the OpenAI API has rate limits, this seems impor…

记录一次target引发的事故:一直提示数据库连接超时

你们好&#xff0c;我是金金金。 场景 启动项目&#xff0c;一直报数据库连接超时&#xff1a; The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. The error may exist in com/xuecheng/sy…

【分立元件】以太网变压器中心抽头有什么作用?

在以太网设备中,通过 PHY 接 RJ45 时,中间都会加一个网络变压器。 但查看不同产品的设计,有的变压器中心抽头接电源,有的又接电容到地。而且接电源时,电源值又可以不一样,3.3V,2.5V,1.8V都有。这个变压器的中心抽头作用到底是什么呢? 中心抽头作用 1. 通过提…

云渲染解决:笔记本渲染很伤电脑吗?如何保护你的电脑?

笔记本电脑是设计师、视频剪辑师和3D艺术家的重要工具&#xff0c;提供随时随地的创作能力。但渲染工作可能对笔记本造成损害。本文将分析渲染对笔记本的影响&#xff0c;并提供减少损伤的策略&#xff0c;帮助用户保持设备在创作中的高效与安全。 一、笔记本电脑渲染的影响 电…

【html+css 绚丽Loading】 000020 三才流转盘

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽Loading&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495…

xss-labs通关攻略 11-15关

第十一关&#xff1a;less-11 步骤一&#xff1a;利用burp抓包 步骤二&#xff1a;添加referer:click me!" type"button" οnmοuseοver"alert(/xss/)进行放包 第十二关&#xff1a;less-12 步骤一&#xff1a;利用burp抓包 步骤二&#xff1a;修改User A…

快团团幸运大转盘是是什么?团长如何使用?

幸运大转盘是什么&#xff1f; 1、团员可以在团内转转盘进行抽奖 2、团员获得的奖励有优惠券&#xff08;无门槛、满减&#xff09;&#xff0c;实物礼品两种形式 3、团员可通过在团内下单&#xff0c;来增加转转盘的次数 4、团长可自行设定奖品、中奖概率&#xff08;中奖…

Linux单用户模式和救援模式

Linux单用户模式和救援模式 单用户模式Initramfs模式进入救援模式 修改被救援Linux的配置挂载boot和/切根 单用户模式 Linux系统的单用户模式有些类似Windows系统的安全模式&#xff0c;只启动最少的程序用于系统修复。在单用户模式中&#xff08;运行级别为1&#xff09;&…

集团数字化转型方案(十八)

为了实现集团的数字化转型&#xff0c;我们将通过引入人工智能、大数据分析、云计算和物联网等先进技术&#xff0c;全面升级现有业务系统与流程&#xff0c;优化企业资源规划&#xff08;ERP&#xff09;&#xff0c;提升业务自动化水平和数据驱动决策能力&#xff1b;建设集成…

一个可以免费上传制作电子版招生简章的网站

当今社会&#xff0c;网络的普及使得越来越多的学校和企业选择通过电子版招生简章来扩大影响力&#xff0c;降低宣传成本。有没有一个免费、便捷且功能强大的平台&#xff0c;能让您轻松上传制作招生简章呢&#xff1f;答案是肯定的&#xff01; 1.要制作电子杂志,首先需要选择…

Mybatis Plus乐观锁实现

1 引言 乐观锁的主要作用在于提高系统的并发性能和减少锁冲突&#xff0c;同时保证数据的一致性。‌其原理简单来说就是&#xff0c;在修改数据的时候&#xff0c;判断数据是否被其他人改过&#xff0c;如果已被其他人改过&#xff0c;则修改失败。 2 代码 在SpringBoot 3.x…

掏耳勺买什么样的好?五大超值不踩雷可视挖耳勺推荐种草!

可视挖耳勺是热度特别高的个人清洁工具&#xff0c;不仅能够更加清晰地观察自己耳内的状况&#xff0c;从而更加安全、有效地清洁耳朵&#xff0c;可以发挥多种多样的作用&#xff0c;但是市面上也隐藏了很多劣质不专业产品&#xff0c;使用这类产品容易出现成像效果模糊、机身…

AI文案新纪元:用ChatGPT构建你的文案创作系统

文章目录 一、ChatGPT在文案创作中的独特优势1. 高效生成&#xff0c;快速响应市场2. 个性化定制&#xff0c;精准触达受众3. 创新表达&#xff0c;提升内容吸引力 二、构建文案创作系统的详细步骤1. 需求分析与系统规划2. 接入ChatGPT API与集成开发3. 设计用户友好的交互界面…

集合及数据结构第十三节(下)———— 枚举与Lambda表达式

系列文章目录 集合及数据结构第十三节&#xff08;下&#xff09;———— 枚举与Lambda表达式 枚举与枚举的使用 什么是C语言数据类型变量、常量字符串转义字符注释选择语句循环语句函数数组操作符常见关键字define 定义常量和宏指针结构体 文章目录 系列文章目录集合及数据…

USB安全存储专家|有效控制U盘读写权限、排名前5的USB安全存储工具大公开啦!

在有效控制U盘读写权限方面&#xff0c;USB安全存储专家及其相关工具扮演着至关重要的角色。 以下是排名前5的USB安全存储工具&#xff0c;它们在保护数据安全、控制U盘读写权限方面表现出色。 1. 安企神 简介&#xff1a;它是一款专注于终端安全管控的软件&#xff0c;具备强…

为你揭秘个股场外期权的盈利模式!

今天带你了解为你揭秘个股场外期权的盈利模式&#xff01;场外个股期权作为一种灵活的金融工具&#xff0c;为投资者提供了多种盈利途径。个股场外期权的盈利模式主要依赖于标的资产价格的变动。 这里是几种常见的个股场外期权盈利方式&#xff1a; 1.看涨期权&#xff1a; …