百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

深入剖析Spring BeanPostProcessor的作用,子类,使用场景

lipiwang 2025-03-06 16:41 26 浏览 0 评论

作用

1. 细粒度控制 Bean 生命周期

Spring 容器在创建 Bean 的过程中,会经过实例化、属性赋值、初始化等多个步骤。BeanPostProcessor 允许开发者在 Bean 初始化前后这两个关键节点插入自定义逻辑,对 Bean 进行定制化处理。

  • 实例化和属性赋值后干预:在 Bean 的构造函数执行完毕且属性赋值完成后,postProcessBeforeInitialization 方法会被调用。这为开发者提供了在 Bean 正式初始化之前进行最后修改的机会,例如根据某些条件修改 Bean 的属性值。
  • 初始化方法执行后增强:postProcessAfterInitialization 方法在 Bean 的初始化方法(如 init-method 或 @PostConstruct 注解标注的方法)执行之后被调用。此时可以对已经完成初始化的 Bean 进行增强,比如添加代理对象,为 Bean 增加额外的功能。

2. 非侵入式扩展

使用 BeanPostProcessor 可以在不修改 Bean 本身代码的情况下,对其进行功能扩展。这符合面向对象编程中的开闭原则,即对扩展开放,对修改关闭。例如,在一个已有的项目中,需要为所有实现了某个接口的 Bean 添加日志记录功能,通过实现 BeanPostProcessor 可以轻松实现,而不需要修改这些 Bean 的源代码。

主要子类及详细分析

1. ApplicationContextAwareProcessor

  • 功能:该处理器主要用于处理实现了一系列 Aware 接口的 Bean。Aware 接口是 Spring 提供的一种回调机制,允许 Bean 获取 Spring 容器的相关信息。ApplicationContextAwareProcessor 会在 Bean 初始化过程中,将 ApplicationContext、BeanFactory 等容器对象注入到实现了相应 Aware 接口的 Bean 中。
  • 示例:当一个 Bean 实现了 ApplicationContextAware 接口时,ApplicationContextAwareProcessor 会调用该 Bean 的 setApplicationContext 方法,将 ApplicationContext 实例传递给它。
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class MyAwareBean implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        // 可以使用 applicationContext 进行其他操作
    }
}

2. InitDestroyAnnotationBeanPostProcessor

  • 功能:负责处理带有 @PostConstruct 和 @PreDestroy 注解的 Bean。这两个注解是 Java EE 规范中定义的,用于标记 Bean 的初始化和销毁方法。InitDestroyAnnotationBeanPostProcessor 会在 Bean 的生命周期中相应的阶段调用这些方法。
  • 示例
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class MyAnnotatedBean {

    @PostConstruct
    public void init() {
        System.out.println("Initializing MyAnnotatedBean");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Destroying MyAnnotatedBean");
    }
}

3. AutowiredAnnotationBeanPostProcessor

  • 功能:处理带有 @Autowired、@Resource、@Inject 等依赖注入注解的 Bean。它会在 Bean 实例化后,根据注解信息从 Spring 容器中查找并注入相应的依赖对象。
  • 示例
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyAutowiredBean {

    private AnotherBean anotherBean;

    @Autowired
    public MyAutowiredBean(AnotherBean anotherBean) {
        this.anotherBean = anotherBean;
    }
}

使用场景

1. AOP 实现细节

  • 代理创建:在 Spring AOP 中,BeanPostProcessor 用于创建代理对象。当一个 Bean 需要被 AOP 增强时,AbstractAutoProxyCreator(它是 BeanPostProcessor 的子类)会在 Bean 初始化后,根据配置的切面信息,为该 Bean 创建代理对象。代理对象会拦截目标 Bean 的方法调用,并在调用前后执行切面逻辑,如日志记录、事务管理等。
  • 示例配置

上述配置会自动注册一个
AnnotationAwareAspectJAutoProxyCreator,它是 AbstractAutoProxyCreator 的子类,负责处理基于注解的 AOP 配置。

2. 数据校验

  • 实现方式:可以在 postProcessAfterInitialization 方法中对 Bean 的属性进行校验。例如,使用 Java 的 Validator 框架对 Bean 的属性进行验证,如果验证不通过,可以抛出异常或者进行默认值设置。
  • 示例代码
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.util.Set;

public class ValidationBeanPostProcessor implements BeanPostProcessor {

    private final Validator validator;

    public ValidationBeanPostProcessor() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        this.validator = factory.getValidator();
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Set<ConstraintViolation<Object>> violations = validator.validate(bean);
        if (!violations.isEmpty()) {
            StringBuilder errorMessage = new StringBuilder();
            for (ConstraintViolation<Object> violation : violations) {
                errorMessage.append(violation.getPropertyPath()).append(": ").append(violation.getMessage()).append("\n");
            }
            throw new IllegalArgumentException("Validation failed for bean " + beanName + ": " + errorMessage.toString());
        }
        return bean;
    }
}

3. 资源注入

  • 自定义资源注入:除了 Spring 内置的依赖注入方式,还可以使用 BeanPostProcessor 实现自定义的资源注入。例如,从外部配置文件或者数据库中读取一些配置信息,并注入到相应的 Bean 中。
  • 示例代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class CustomResourceInjector implements BeanPostProcessor {

    private final Properties properties;

    public CustomResourceInjector() {
        properties = new Properties();
        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("config.properties")) {
            if (inputStream != null) {
                properties.load(inputStream);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof CustomResourceAware) {
            ((CustomResourceAware) bean).setCustomResource(properties.getProperty("custom.resource"));
        }
        return bean;
    }

    public interface CustomResourceAware {
        void setCustomResource(String resource);
    }
}

使用方法

1. 创建自定义的 BeanPostProcessor 实现类

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 可以根据 bean 的类型或名称进行不同的处理
        if (bean instanceof MyCustomBean) {
            // 对 MyCustomBean 进行特殊处理
            ((MyCustomBean) bean).setSomeProperty("Modified value");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyCustomBean) {
            // 可以在这里添加代理对象或进行其他增强操作
        }
        return bean;
    }
}

2. 注册自定义的 BeanPostProcessor

  • 基于 XML 配置
  • 基于 Java 配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public CustomBeanPostProcessor customBeanPostProcessor() {
        return new CustomBeanPostProcessor();
    }
}


相关推荐

ubuntu单机安装open-falcon极度详细操作

备注:以下操作均由本人实际操作并得到验证,喜欢的同学可尝试操作安装。步骤一1.1环境准备(使用系统:ubuntu18.04)1.1.1安装redisubuntu下安装(参考借鉴:https://...

Linux搭建promtail、loki、grafana轻量日志监控系统

一:简介日志监控告警系统,较为主流的是ELK(Elasticsearch、Logstash和Kibana核心套件构成),虽然优点是功能丰富,允许复杂的操作。但是,这些方案往往规模复杂,资源占用高,...

一文搞懂,WAF阻止恶意攻击的8种方法

WAF(Web应用程序防火墙)是应用程序和互联网流量之间的第一道防线,它监视和过滤Internet流量以阻止不良流量和恶意请求,WAF是确保Web服务的可用性和完整性的重要安全解决方案。它...

14配置appvolume(ios14.6配置文件)

使用AppVolumes应用程序功能,您可以管理应用程序的整个生命周期,包括打包、更新和停用应用程序。您还可以自定义应用程序分配,以向最终用户提供应用程序的特定版本14.1安装appvolume...

目前流行的缺陷管理工具(缺陷管理方式存在的优缺点)

摘自:https://blog.csdn.net/jasonteststudy/article/details/7090127?utm_medium=distribute.pc_relevant.no...

开源数字货币交易所开发学习笔记(2)——SpringCloud

前言码云(Gitee)上开源数字货币交易所源码CoinExchange的整体架构用了SpringCloud,对于经验丰富的Java程序员来说,可能很简单,但是对于我这种入门级程序员,还是有学习的必要的...

开发JAX-RPC Web Services for WebSphere(下)

在开发JAX-RPCWebServicesforWebSphere(上)一文中,小编为大家介绍了如何创建一个Web服务项目、如何创建一个服务类和Web服务,以及部署项目等内容。接下来小编将为大...

CXF学习笔记1(cxf client)

webservice是发布服务的简单并实用的一种技术了,个人学习了CXF这个框架,也比较简单,发布了一些笔记,希望对笔友收藏并有些作用哦1.什么是webServicewebService让一个程序可...

分布式RPC最全详解(图文全面总结)

分布式通信RPC是非常重要的分布式系统组件,大厂经常考察的Dubbo等RPC框架,下面我就全面来详解分布式通信RPC@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集》...

Oracle WebLogic远程命令执行0day漏洞(CVE-2019-2725补丁绕过)预警

概述近日,奇安信天眼与安服团队通过数据监控发现,野外出现OracleWebLogic远程命令执行漏洞最新利用代码,此攻击利用绕过了厂商今年4月底所发布的最新安全补丁(CVE-2019-2725)。由...

Spring IoC Container 原理解析(spring中ioc三种实现原理)

IoC、DI基础概念关于IoC和DI大家都不陌生,我们直接上martinfowler的原文,里面已经有DI的例子和spring的使用示例《InversionofControlContainer...

Arthas线上服务器问题排查(arthas部署)

1Arthas(阿尔萨斯)能为你做什么?这个类从哪个jar包加载的?为什么会报各种类相关的Exception?我改的代码为什么没有执行到?难道是我没commit?分支搞错了?遇到问题无法在...

工具篇之IDEA功能插件HTTP_CLENT(idea2021插件)

工具描述:Java开发人员通用的开发者工具IDEA集成了HTTPClient功能,之后可以无需单独安装使用PostMan用来模拟http请求。创建方式:1)简易模式Tools->HTTPCl...

RPC、Web Service等几种远程监控通信方式对比

几种远程监控通信方式的介绍一.RPCRPC使用C/S方式,采用http协议,发送请求到服务器,等待服务器返回结果。这个请求包括一个参数集和一个文本集,通常形成“classname.meth...

《github精选系列》——SpringBoot 全家桶

1简单总结1SpringBoot全家桶简介2项目简介3子项目列表4环境5运行6后续计划7问题反馈gitee地址:https://gitee.com/yidao620/springbo...

取消回复欢迎 发表评论: