Spring后处理器-BeanPostProcessor

news2024/11/25 7:42:35

Spring后处理器-BeanPostProcessor

  • Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过bean的初始化过程((该后处理器的执行时机)),例如:属性的填充、初始化方法init的执行等,其中有一个对外拓展的点BeanPostProcessor,我们称之为bean后处理器。与上文bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor(即在配置文件中对其进行配置),会在流程节点上被Spring自动调用。
  • BeanPostProcessor接口代码如下
    • //
      // Source code recreated from a .class file by IntelliJ IDEA
      // (powered by FernFlower decompiler)
      //
      
      package org.springframework.beans.factory.config;
      
      import org.springframework.beans.BeansException;
      import org.springframework.lang.Nullable;
      
      public interface BeanPostProcessor {
          @Nullable
          default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              return bean;
          }
      
          @Nullable
          default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              return bean;
          }
      }
      
  • 创建实现该接口(BeanPsotProcessor)的类,要在配置文件中进行管理
    • 快捷键 ctrl + insert 重写接口方法
    • package com.example.PostProcessor;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanPostProcessor;
      
      public class MyBeanPostProcessor implements BeanPostProcessor {
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              System.out.println(beanName + ":postProcessBeforeInitialization");
              return bean;
          }
      
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              System.out.println(beanName + ":postProcessAfterInitialization");
              return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
          }
      }
      
  • 测试类代码

    • package com.example.Test;
      
      
      import com.example.Service.Impl.UserServiceImpl;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      public class TestApplicationContext {
          public static void main(String[] args) {
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
              System.out.println(context.getBean(UserServiceImpl.class));
          }
      }
      
  • 运行结果如下


    •  

    • 展示了该后处理器的执行时机 


Before和After执行时机

  • 在Bean实例化过程可以配置相关对于bean对象的操作方法,具体间往期文章:Bean的配置- CSDN搜索
  • 注册为bean的类
    • package com.example.Service.Impl;
      
      import com.example.DAO.UserDAO;
      import com.example.Service.UserService;
      import org.springframework.beans.factory.InitializingBean;
      
      import java.util.List;
      import java.util.Map;
      import java.util.Set;
      
      
      public class UserServiceImpl implements UserService, InitializingBean {
          // todo 无参构造方法
          public UserServiceImpl() {
              System.out.println("UserServiceImpl实例化");
          }
      
          // todo 自定义初始化方法
          public void init() {
              System.out.println("自定义初始化方法init()");
          }
      
          @Override
          public void afterPropertiesSet() throws Exception {
              System.out.println("属性设置之后执行afterPropertiesSet()");
          }
      
      }
      
  • 实现bean后处理器的类
    • package com.example.PostProcessor;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanPostProcessor;
      
      public class MyBeanPostProcessor implements BeanPostProcessor {
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              System.out.println(beanName + ":postProcessBeforeInitialization");
              return bean;
          }
      
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              System.out.println(beanName + ":postProcessAfterInitialization");
              return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
          }
      }
      
  • 配置文件

    • <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
          <bean class="com.example.PostProcessor.MyBeanPostProcessor"></bean>
          <bean id="userService" class="com.example.Service.Impl.UserServiceImpl" init-method="init">
      </beans>
  • 测试类

    • package com.example.Test;
      
      
      import com.example.Service.Impl.UserServiceImpl;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      public class TestApplicationContext {
          public static void main(String[] args) {
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
              System.out.println(context.getBean(UserServiceImpl.class));
          }
      }
      
  • 运行结果

小结 

  • 从上述运行结果来看,首先完成bean对象的创建,然后执行后处理器中的before方法,然后执行属性设置之后的方法,然后执行自定义的初始化方法,最后执行后处理器的after方法

案例

  • 对Bean方法进行执行时间日志增强
  • 要求
    • Bean的方法执行之前控制台打印当前时间
    • Bean的方法执行之后控制台打印当前时间
  • 分析
    • 对方法进行增强主要就是代理设计模式和包装设计模式
    • 由于Bean方法不确定,所以使用动态代理在运行期间执行增强操作
    • 在Bean实例创建完毕之后,进入到单例之前,使用Proxy真实的目标bean
  • 具体代码如下
    • 代理类(实现了bean后处理接口)
    • package com.example.PostProcessor;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanPostProcessor;
      
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Proxy;
      import java.util.Date;
      
      public class TimeLogBeanPostProcessor implements BeanPostProcessor {
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              // todo 使用动态代理对目标bean进行增强,返回proxy对象,进而存储到单例池singletonObjects中
              Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (InvocationHandler) (proxy, method, args) -> {
                  // 输出开始时间
                  System.out.println("方法" + method.getName() + "开始执行时间" + new Date());
                  // 执行目标方法
                  Object rs = method.invoke(bean, args);
                  // 输出结束时间
                  System.out.println("方法" + method.getName() + "结束执行时间" + new Date());
                  return rs;
              });
              return beanProxy;// 将增强的bean存入单例池中
          }
      }
      
      
    • bean对象对应的类

    • package com.example.Service.Impl;
      
      import com.example.Service.UserService;
      
      
      public class UserServiceImpl implements UserService {
          public void show() {
              System.out.println("show......");
          }
      
      }
      
    • 接口类

    • package com.example.Service;
      
      public interface UserService {
          public void show();
      }
      
    • 配置文件

    • <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
          <bean class="com.example.PostProcessor.TimeLogBeanPostProcessor"></bean>
          <bean id="userService" class="com.example.Service.Impl.UserServiceImpl">
          </bean>
      
      
      </beans>
    • 测试类

    • package com.example.Test;
      
      
      import com.example.Service.UserService;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestApplicationContext {
          public static void main(String[] args) {
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
              UserService UserServiceBean = (UserService) context.getBean(UserService.class);
              UserServiceBean.show();
          }
      }
      
      
    • 运行结果

Bean实例化基本流程图



  • 首先通过Reader读取配置文件,解析bean标签,然后将每个bean标签变成beanDefinition对象存储到beanDefinitionMap中,然后经过所有的BeanFactoryPostProcessor(bean工厂后处理器),再从Map中取出每个beanDefiniton对象,通过反射变成Object对象,创建完对象后,经过beanPoatProcessor中的before方法和after方法(之间还存在bean中的init方法,后面会讲述),最终存入单例池中。 

在学习本文章内容的时候,我也去补充了一下,基础知识,便于更加程序运行原理,具体文章如下

Java高级-代理(proxy)_熵240的博客-CSDN博客
Java高级-注解_熵240的博客-CSDN博客
反射的作用、应用场景_熵240的博客-CSDN博客
Java高级-反射_熵240的博客-CSDN博客
Lambda表达式_熵240的博客-CSDN博客

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

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

相关文章

第 364 场 LeetCode 周赛题解

A 最大二进制奇数 降序排序字符串&#xff0c;然后将最后一个 1 与最后一位交换 class Solution { public:string maximumOddBinaryNumber(string s) {sort(s.begin(), s.end(), greater<>());for (int i s.size() - 1;; i--)if (s[i] 1) {swap(s[i], s.back());break;…

【Oracle】Oracle系列之八--SQL查询

文章目录 往期回顾前言1. 基本查询&#xff08;1&#xff09;All&#xff08;2&#xff09;in/exists 子查询&#xff08;3&#xff09;union/except/intersect&#xff08;4&#xff09;group by&#xff08;5&#xff09;having&#xff08;6&#xff09;聚集函数&#xff1a…

SLAM从入门到精通(用c++实现机器人运动控制)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 之前的一篇文章&#xff0c;我们知道了可以通过wpr_simulation包仿真出机器人和现场环境。如果需要控制机器人&#xff0c;这个时候就需要rqt_robo…

AcWing 5153. 删除(AcWing杯 - 周赛)(结论+枚举)

思路&#xff1a; ACcode: #include<bits/stdc.h> using namespace std; #define int long long string s; void solve() {cin>>s;s"00"s;int lens.size();for(int i0; i<len; i) {for(int ji1; j<len; j) {for(int kj1; k<len; k) {int xs[i]*…

leetcode:2446. 判断两个事件是否存在冲突(python3解法)

难度&#xff1a;简单 给你两个字符串数组 event1 和 event2 &#xff0c;表示发生在同一天的两个闭区间时间段事件&#xff0c;其中&#xff1a; event1 [startTime1, endTime1] 且event2 [startTime2, endTime2] 事件的时间为有效的 24 小时制且按 HH:MM 格式给出。 当两个…

Windows 基于Visual Studio 开发Qt 6 连接MySQL 8

前提条件&#xff1a; 1、Visual Studio 2022 社区版(免费版) 2、Qt-6.5.1版本 3、MySQL 8 Qt 6 配置MySQL 8 动态/静态连接库和MySQL 8 驱动。 libmysql.dll 和libmysql.lib是QT所需的动态和静态链接库&#xff1b;qsqlmysql.dll 和qsqlmysql.dll.debug是Qt所需的mysql驱…

机器人过程自动化(RPA)入门 1. 什么是机器人过程自动化?

如今&#xff0c;我们生活中几乎没有任何方面不受自动化的影响。一些例子包括洗衣机、微波炉、汽车和飞机的自动驾驶模式&#xff0c;雀巢在日本的商店里使用机器人销售咖啡豆&#xff0c;沃尔玛在美国测试无人机送货&#xff0c;我们的银行支票使用光学字符识别&#xff08;OC…

【Linux】调试代码的工具 - gdb

1、安装gdb sudo yum -y install gdb【安装gdb】 2、gdb的使用 在 Linux 下&#xff0c;我们编写代码默认以 release 方式发布如果想让代码以 debug 方式发布&#xff0c;必须给 gcc 添加 -g 选项 (gdb) q / quit【退出gdb】(gdb) l / list&#xff08;list可缩写为 l&#xf…

C++的文件操作

文件操作 程序运行时产生的数据都属于临时数据&#xff0c;通过文件可将数据持久化 C中对文件操作需要包含头文件<fstream> 文件类型分为两种&#xff1a; 文本文件 - 文件以文本的ASCII码形式存储在计算机中二进制文件 - 文件以文本的二进制形式存储在计算机中&…

如何取消自动播放音乐:取消手机汽车连上后汽车自动播放音乐?

背景 手机和汽车通过蓝牙连接上之后&#xff0c;汽车音响会自动播放手机上的音乐&#xff0c;似乎是自动唤醒APP的&#xff0c;因为这些音乐APP在手机上是已经被杀了后台的了。 而且汽车的屏幕的播放列表里头会显示播放的音乐的名称&#xff0c;也有可能是视频的名称&#xf…

安卓备份分区----手动查询安卓系统分区信息 导出系统分区的一些基本操作

在玩机搞机过程中。有时候需要手动查看有些分区信息&#xff0c;或者备份分区的操作。那么今天以小米8为例解析下其中的操作步骤 机型&#xff1a;小米8 adb版本&#xff1a;https://developer.android.com/studio/releases/platform-tools 机型芯片&#xff1a;高通骁龙845…

基于微信小程序的校园商铺系统,附源码、数据库

文章目录 第一章 简介第二章 技术栈第三章&#xff1a;总体设计第四章系统详细设计4.1 前台功能模块4.2后台功能模块4.2.1管理员功能模块 五 源码咨询 第一章 简介 今天&#xff0c;为大家带来的事基于微信小程序的校园商铺系统。本系统的主要意义在于&#xff0c;全力以赴为用…

Redis双写一致性、持久化机制、分布式锁

一.双写一致性: 含义:当数据库中的数据被修改了以后&#xff0c;我们也需要同时修改缓存&#xff0c;使缓存和数据库的数据保持一致 &#xff08;1&#xff09;读操作:当请求发来的时候&#xff0c;先去看redis里面是否有对应的数据&#xff0c;如果有直接返回&#xff0c;如果…

轻量级的日志采集组件 Filebeat 讲解与实战操作

文章目录 一、概述二、Kafka 安装三、Filebeat 安装1&#xff09;下载 Filebeat2&#xff09;Filebeat 配置参数讲解3&#xff09;filebeat.prospectors 推送kafka完整配置1、filebeat.prospectors2、processors3、output.kafka 4&#xff09;filebeat.inputs 与 filebeat.pros…

【STL】vector常见用法及模拟实现(附源码)

目录 前言1. vector介绍及使用1.1vector的介绍1.2 vector的使用1.2.1 构造函数 1.2.2 vector对象遍历1.2.3 reserve和resize1.2.4 insert和erase 2. vector模拟实现2.1 vector迭代器失效问题2.2 模拟实现reserve函数浅拷贝问题2.3模拟实现源码2.3.1 vector.h2.3.2 test.cpp 前言…

org.postgresql.util.PSQLException: Bad value for type long

项目用 springbootmybatis mybatisplus&#xff0c; 数据库是&#xff1a;postgresql 。 执行查询时候返回错误。 org.springframework.dao.DataIntegrityViolationException: Error attempting to get column city_id from result set. Cause: org.postgresql.util.PSQLExce…

如何让ChatGPT为留学生所用?

“我们这一届学Data Analyics和Data Science的没一个找到工作的。”朋友饭桌上的闲话让研究生才算踏入DA圈子的我瑟瑟发抖。 还没开始正式求职的我&#xff0c;似乎已经被宣告失业了。而这一切都要“归功”于以ChatGPT为代表的大语言模型&#xff08;LLMs&#xff09;。 问世不…

接口测试练习步骤

在接触接口测试过程中补了很多课&#xff0c; 终于有点领悟接口测试的根本&#xff1b; 偶是个实用派&#xff5e;&#xff0c;那么现实中没有用的东西&#xff0c;基本上我都不会有很大的概念&#xff1b; 下面给的是接口测试的统一大步骤&#xff0c;其实就是让我们对接口…

第9章 【MySQL】InnoDB的表空间

表空间 是一个抽象的概念&#xff0c;对于系统表空间来说&#xff0c;对应着文件系统中一个或多个实际文件&#xff1b;对于每个独立表空间来说&#xff0c;对应着文件系统中一个名为 表名.ibd 的实际文件。大家可以把表空间想象成被切分为许许多多个 页 的池子&#xff0c;当我…

机器学习之正则化与验证提高模型泛化

文章目录 正则化&#xff08;Regularization&#xff09;&#xff1a;验证&#xff08;Validation&#xff09;&#xff1a; 正则化和验证是机器学习中重要的概念&#xff0c;它们帮助提高模型的性能和泛化能力。让我详细介绍一下这两个概念&#xff1a; 正则化&#xff08;Re…