Spring中Bean创建过程中各个阶段的作用

news2024/10/6 0:28:26

在这里插入图片描述

文章目录

    • Instantiate(实例化)
    • Populate properties(填充属性)
    • BeanNameAware's setBeanName()
    • BeanFactoryAware's setBeanFactory()
    • ApplicationContextAware's setApplicationContext()
    • Pre-initialization BeanPostProcessors
    • InitializingBean's afterPropertiesSet()
    • Call custom init-method
    • Post-initialization BeanPostProcessors

虽然关于Spring中Bean的创建过程的资料很多,但却很少说为什么要划分这些阶段,以及这些阶段划分处理后在开发中可以用来做什么。通过GPT,这里给出了各个阶段的作用,并通过例子帮助理解。

假设我们正在开发一个电子商务系统,其中包含一个OrderService来处理订单。我们将逐步展示每个阶段如何在这个服务的生命周期中发挥作用。

Instantiate(实例化)

public class OrderService {
    private ProductRepository productRepository;
    private UserRepository userRepository;
    private PaymentGateway paymentGateway;
    private OrderRepository orderRepository;
    // 其他属性和方法
}

在这个阶段,Spring 仅仅创建了 OrderService 的一个空实例。这是必要的第一步,因为它为后续的配置和自定义提供了基础。

Populate properties(填充属性)

@Autowired
public void setProductRepository(ProductRepository productRepository) {
    this.productRepository = productRepository;
}

@Autowired
public void setUserRepository(UserRepository userRepository) {
    this.userRepository = userRepository;
}

@Autowired
public void setPaymentGateway(PaymentGateway paymentGateway) {
    this.paymentGateway = paymentGateway;
}

@Autowired
public void setOrderRepository(OrderRepository orderRepository) {
    this.orderRepository = orderRepository;
}

在这个阶段,Spring 注入所有必要的依赖。这个阶段的重要性在于它允许我们灵活地配置依赖关系。例如,我们可以轻松地在测试环境中注入模拟对象,而在生产环境中注入实际实现,而无需修改 OrderService 的代码。

BeanNameAware’s setBeanName()

public class OrderService implements BeanNameAware {
    private String serviceName;

    @Override
    public void setBeanName(String name) {
        this.serviceName = name;
    }

    public void logOrderProcess(Order order) {
        Logger.info("[" + serviceName + "] Processing order: " + order.getId());
    }
}

这个阶段允许 OrderService 知道自己在 Spring 容器中的名称。在本例中,我们使用它来增强日志信息,使得在分布式系统中更容易追踪订单处理过程。

BeanFactoryAware’s setBeanFactory()

public class OrderService implements BeanFactoryAware {
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void processOrder(Order order) {
        // 根据订单类型动态选择合适的支付处理器
        PaymentProcessor processor = (PaymentProcessor) beanFactory.getBean(order.getPaymentMethod() + "PaymentProcessor");
        processor.process(order.getPayment());
    }
}

这个阶段使 OrderService 能够访问 BeanFactory,从而实现了动态选择支付处理器的功能。这种灵活性对于处理不同类型的支付方式(如信用卡、PayPal、银行转账等)非常有用。

ApplicationContextAware’s setApplicationContext()

public class OrderService implements ApplicationContextAware {
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    public void initializeService() {
        Environment env = context.getEnvironment();
        String region = env.getProperty("app.region");
        if ("US".equals(region)) {
            // 使用美国特定的税收计算逻辑
        } else if ("EU".equals(region)) {
            // 使用欧盟特定的税收计算逻辑
        }
    }
}

通过 ApplicationContextOrderService 可以访问环境配置,从而根据不同的地区应用不同的业务逻辑,如税收计算方式。

Pre-initialization BeanPostProcessors

这个阶段允许我们在 Bean 的其他初始化方法之前修改 Bean 或其代理。这对于需要在初始化之前进行的设置或修改特别有用。

例子:安全检查和审计日志

@Component
public class SecurityAuditBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TransactionService) {
            TransactionService service = (TransactionService) bean;
            // 在bean初始化之前进行安全检查
            if (!SecurityContext.isInitialized()) {
                throw new SecurityException("Security context must be initialized before TransactionService");
            }
            // 添加审计日志
            AuditLogger.log("TransactionService is being initialized");
            
            // 返回一个代理对象,用于后续的方法调用
            return Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                new SecurityAuditInvocationHandler(service)
            );
        }
        return bean;
    }
}

这个例子展示了如何在 TransactionService 初始化之前进行安全检查和审计日志记录。这种操作必须在其他初始化步骤之前进行,以确保系统的安全性。

InitializingBean’s afterPropertiesSet()

这个方法在所有属性设置完成后调用,适合用于基于这些属性的初始化逻辑。

例子:连接池初始化

public class TransactionService implements InitializingBean {
    @Autowired
    private DataSource dataSource;
    
    private Connection connection;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化数据库连接
        this.connection = dataSource.getConnection();
        
        // 设置连接属性
        this.connection.setAutoCommit(false);
        this.connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
        
        // 验证连接
        if (!this.connection.isValid(5000)) {
            throw new IllegalStateException("Failed to establish a valid database connection");
        }
    }
}

这个方法确保在 TransactionService 使用之前,数据库连接已经正确设置和验证。这种初始化逻辑依赖于已注入的 dataSource,因此必须在属性填充之后执行。

Call custom init-method

自定义初始化方法提供了更大的灵活性,允许开发者定义特定的初始化逻辑,而不需要实现 InitializingBean 接口。

例子:缓存预热

public class TransactionService {
    @Autowired
    private TransactionRepository repository;
    
    private Cache<String, Transaction> transactionCache;

    @PostConstruct
    public void initCache() {
        // 初始化缓存
        this.transactionCache = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();

        // 预热缓存
        List<Transaction> recentTransactions = repository.getRecentTransactions(100);
        for (Transaction tx : recentTransactions) {
            this.transactionCache.put(tx.getId(), tx);
        }
    }
}

这个自定义初始化方法用于设置和预热缓存。这种操作不适合放在 afterPropertiesSet() 中,因为它是特定于应用的逻辑,而不是通用的初始化。

Post-initialization BeanPostProcessors

这个阶段允许我们在 Bean 完全初始化后进行最终的修改或增强。

例子:事务管理和性能监控

@Component
public class TransactionManagementBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TransactionService) {
            return Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                new TransactionManagementInvocationHandler((TransactionService) bean)
            );
        }
        return bean;
    }
}

class TransactionManagementInvocationHandler implements InvocationHandler {
    private final TransactionService target;
    private final PerformanceMonitor performanceMonitor;

    TransactionManagementInvocationHandler(TransactionService target) {
        this.target = target;
        this.performanceMonitor = new PerformanceMonitor();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.isAnnotationPresent(Transactional.class)) {
            return executeInTransaction(method, args);
        }
        return method.invoke(target, args);
    }

    private Object executeInTransaction(Method method, Object[] args) throws Throwable {
        TransactionStatus status = null;
        try {
            status = TransactionManager.begin();
            long start = System.nanoTime();
            Object result = method.invoke(target, args);
            long end = System.nanoTime();
            TransactionManager.commit(status);
            performanceMonitor.record(method.getName(), end - start);
            return result;
        } catch (Exception e) {
            if (status != null) {
                TransactionManager.rollback(status);
            }
            throw e;
        }
    }
}

这个后处理器在 TransactionService 完全初始化后添加了事务管理和性能监控功能。这必须在最后执行,以确保它能捕获到所有可能的方法调用,包括在之前阶段添加的方法。

后面四个阶段看上去可以合在一起,但它们也有各自的重要性:

  1. Pre-initialization BeanPostProcessors 用于在任何初始化发生之前进行必要的检查或修改。
  2. InitializingBean’s afterPropertiesSet() 用于基于注入的依赖进行初始化。
  3. Custom init-method 提供了一种更灵活的方式来定义特定于应用的初始化逻辑。
  4. Post-initialization BeanPostProcessors 用于在 Bean 完全准备好之后添加额外的行为或增强。

这种分层方法允许开发者在 Bean 生命周期的不同点进行干预,提供了极大的灵活性和可扩展性。它使得框架和应用代码可以清晰地分离关注点,同时仍然允许它们在必要时进行交互。这种设计使得 Spring 能够支持各种复杂的场景,同时保持代码的模块化和可维护性。

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

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

相关文章

【Python篇】从零到精通:全面分析Scikit-Learn在机器学习中的绝妙应用

文章目录 从零到精通&#xff1a;全面揭秘Scikit-Learn在机器学习中的绝妙应用前言第一部分&#xff1a;深入了解Scikit-Learn的基础知识1. 什么是Scikit-Learn&#xff1f;2. 安装Scikit-Learn3. Scikit-Learn中的基本构件4. 数据集的加载与探索5. 数据预处理标准化数据 6. 构…

【Kubernetes】常见面试题汇总(五十五)

目录 121. POD 创建失败&#xff1f; 122. POD 的 ready 状态未进入&#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 题目 69-113 属于【Kube…

C# 数组和集合

本课要点&#xff1a; 1、数组概述 2、一维数组的使用 3、二维数组的使用 4、数组的基本操作 5、数组排序算法 6、ArrayList集合 7、Hashtable类 8、常见错误 一 数组 1 数组引入1 问题&#xff1a; 简单问题&#xff1a;求4个整数的最大值&#xff1f; int a 40,…

C语言自定义类型联合和枚举(25)

文章目录 前言一、联合体联合体的声明联合体的特点联合体和结构体内存布局对比联合体的大小计算联合体的实际使用样例礼品兑换单判断当前机器是大端还是小端 二、枚举枚举的定义枚举类型的声明枚举类型的优点枚举类型的使用 总结 前言 关于自定义类型除了我们常用的结构体&…

Kubernetes-Operator篇-04-operator部署验证

1、部署命令 这个是很多博客教程都在使用的部署命令&#xff1a; make manifests make install export ENABLE_WEBHOOKSfalse make run我们使用之前的demo来进行部署验证&#xff1a;Kubernetes-Operator篇-02-脚手架熟悉 这里面涉及到的makefile的配置可以参考&#xff1a;…

10.5二分专练,二分边界情况,+1不加1的判断,方向判断,各种DEBUG

5 https://leetcode.cn/problems/minimum-speed-to-arrive-on-time/submissions/570242512/ 就是说总时间是 前n-1量汽车的运行时间&#xff0c;向上取整&#xff0c;然后再加上最后一辆列车的运行时间 最快的话是需要n-1个小时 搜索空间就是时速&#xff0c;左边界是1&#x…

数学建模 第三讲 - 简单的优化模型

在数学建模的学习过程中&#xff0c;第三章介绍了几种简单的优化模型&#xff0c;这些模型在实际生活中有广泛的应用。以下是对这些模型的整理和总结。 3.1 存贮模型 问题描述 配件厂为装配线生产产品&#xff0c;更换设备需要支付生产准备费&#xff0c;产量大于需求时需要…

Llama 3.2 微调指南

让我们通过微调 Llama 3.2 来找到一些精神上的平静。 我们需要安装 unsloth&#xff0c;以更小的尺寸实现 2 倍的快速训练 !pip install unsloth!pip uninstall unsloth -y && pip install --upgrade --no-cache-dir "unsloth[colab-new] githttps://github.co…

OpenCV马赛克

#马赛克 import cv2 import numpy as np import matplotlib.pyplot as pltimg cv2.imread(coins.jpg,1) imgInfo img.shape height imgInfo[0] width imgInfo[1]for m in range(200,400): #m,n表示打马赛克区域for n in range(200,400):# pixel ->10*10if m%10 0 and …

初识Linux · 文件(1)

目录 前言&#xff1a; 回顾语言层面的文件 理解文件的预备知识 文件和磁盘 使用和认识系统调用函数 前言&#xff1a; 本文以及下篇文章&#xff0c;揭露的都是Linux中文件的奥秘&#xff0c;对于文件来说&#xff0c;初学Linux第一节课接触的就是文件&#xff0c;对于C…

Windows删除service服务

Windows删除service服务 找到命令提示符&#xff1a; 右键&#xff0c;以管理员身份运行 输入&#xff1a; sc delete 服务名 Windows根据TCP端口号查找进程PID再kill进程_windows tcpkill-CSDN博客文章浏览阅读5.3k次&#xff0c;点赞42次&#xff0c;收藏104次。Windows根据…

【408计算机考研课程】数据结构-数据结构在学什么?

前言 数据结构在学什么&#xff1f; 如何用程序代码把现实世界的问题信息化如何用计算机高效地处理这些信息从而创造价值 第一章&#xff1a;数据结构在学什么&#xff1f; 总览 什么是数据&#xff1f; 简介&#xff1a;数据是信息的载体&#xff0c;是描述客观事物属性的数、…

【在Linux世界中追寻伟大的One Piece】进程信号

目录 1 -> 信号入门 1.1 -> 生活角度的信号 1.2 -> 技术应用角度的信号 1.3 -> 注意 2 -> 信号的概念 2.1 -> 用kill -l命令可以查看系统定义的信号列表 2.2 -> 信号处理常见方式 3 -> 产生信号 3.1 -> Core Dump 3.2 -> 调用系统函数…

已解决-Nacos明明成功运行,但Spring报错连接不上

这天使用windows本地nacos的时候&#xff0c;一直报错&#xff1a; Caused by: com.alibaba.nacos.api.exception.NacosException: Request nacos server failed: Caused by: com.alibaba.nacos.api.exception.NacosException: Client not connected, current status:STARTIN…

(计算机组成原理)

计算机的发展 计算机系统硬件&#xff08;计算机的实体&#xff0c;如主机&#xff0c;外设等&#xff09;软件&#xff08;由具有各种特殊功能的程序组成&#xff09; 硬件是计算机系统的物理基础&#xff0c;硬件决定瓶颈&#xff0c;软件决定性能发挥的程度 第一台电子数字计…

YOLOv4和Darknet实现坑洼检测

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色…

IDEA如何自定义创建类的文档注释

说明&#xff1a;在IDEA中&#xff0c;创建一个Java类文件&#xff0c;会在类上面自动生成文档注释&#xff0c;如下&#xff1a; 看样子&#xff0c;默认是计算机的用户名&#xff0c;然后加上当前的创建时间。可以在IDEA中的Setting中设置&#xff0c;如下&#xff1a; /*** …

汽车追尾为什么是后车的责任?

简单点说&#xff1a;因为人后面没有长眼睛。 结论 在汽车追尾事故中&#xff0c;通常情况下后车被认为是责任方的原因在于交通法规对驾驶安全标准的约定和实践中的责任识别原则。虽然追尾事故常见地被归责于后车&#xff0c;但具体判断并不是绝对的&#xff0c;仍需综合多种…

C++11中的特性

这里主要讲解一些C11相较于C98所新增的比较实用的新特性。 C11的官方文档&#xff1a;C11 - cppreference.comhttps://en.cppreference.com/w/cpp/11 一、列表初始化&#xff08;List-initialization&#xff09; &#xff08;一&#xff09;、使用“{}”进行初始化 在C98中&…

有关自连接表的统一封装

表结构 RecursionBean Getter Setter ToString JsonInclude(JsonInclude.Include.NON_EMPTY) public class RecursionBean<T> extends BaseVO {/*** 编号*/private T id;/*** 父权限ID&#xff0c;根节点的父权限为空* 注释掉JsonIgnore&#xff0c;是为了前端判断是否…