IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring之Bean后处理器——BeanPostProcessor的使用与源码解析 -> 正文阅读

[Java知识库]Spring之Bean后处理器——BeanPostProcessor的使用与源码解析

BeanPostProcessor介绍

BeanPostProcessor接口使得程序可以在Bean被初始化的前后执行自定义动作,如检查或更改Bean的属性值、包装即将注册到BeanFactorysingletonObjects中的原对象等。
BeanPostProcessor接口提供了如下方法:

方法描述
Object postProcessBeforeInitialization(Object bean, String beanName)在容器调用BeanInitializingBean#afterPropertiesSet()或自定义的init-method之前,调用该方法进行处理;传入的bean对象属性此时已经装配好。
Object postProcessAfterInitialization(Object bean, String beanName)在容器调用BeanInitializingBean#afterPropertiesSet()或自定义的init-method之后,调用该方法进行处理;传入的bean对象属性此时已经装配好。

BeanPostProcessor执行流程


BeanPostProcessor的执行会在Bean实例化并装配好属性之后,before和after之间会插入BeanAfterPropertiesSet()init-method的执行。
下图能比较好的反应出过程:
在这里插入图片描述


BeanPostProcessor使用

接下来写个例子。全量代码会在最后贴出来,直接CV运行即可。

Book

Book类,它实现了InitializingBean接口,其afterPropertiesSet()方法仅输出一行信息用来记录执行流程;还有一个customInit()方法使其加入到Springinit-method的执行过程;该类还有一个show()方法,用来在后面的BeanPostProcessor处理器中对原始的Book对象生成一个代理类,该代理类将对show()方法进行增强处理,用来让咱们的BeanPostProcessor能实际干点事儿。

public class Book implements InitializingBean {
        private String name;
        private String author;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAuthor() {
            return author;
        }

        public void setAuthor(String author) {
            this.author = author;
        }

        public void show() {
            System.out.printf("book#show():%s\n", this);
        }

        public void customInit() {
            System.out.printf("%-70s:%s{%s}%n", "------Book#customInit", this.getClass().getSimpleName(), this);
        }

        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", author='" + author + '\'' +
                    '}';
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.printf("%-70s:%s{%s}%n", "------Book#afterPropertiesSet", this.getClass().getSimpleName(), this);
        }
    }

BookProxyBeanPostProcessor

BookProxyBeanPostProcessor实现了BeanPostProcessor接口;在其postProcessBeforeInitialization()方法中对Book类型进行判断,如果是Book类型则使用CGLIB生成其代理,用来增强Book#show()方法,在其前后各打印一句话。

public class BookProxyBeanPostProcessor implements BeanPostProcessor {

    /**
     * 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之前,调用该方法进行处理;传入的bean对象属性此时已经装配好。
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.printf("%-70s:%s{%s}%n",
                "------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
                bean.getClass().getSimpleName(),
                bean);
        if (Book.class.equals(bean.getClass())) {
            System.out.printf("\033[1;33m%-70s:对[%s]的\033[1;31mshow()\033[1;33m方法进行增强 \033[0m%n",
                    "------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
                    bean.getClass().getSimpleName());
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Book.class);
            enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) -> {
                if (!method.equals(Book.class.getMethod("show"))) {
                    return methodProxy.invokeSuper(obj, args);
                }
                System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行前");
                Object result = methodProxy.invokeSuper(obj, args);
                System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行后");
                return result;
            });
            Book book = (Book) enhancer.create();
            book.setName(((Book) bean).getName());
            book.setAuthor(((Book) bean).getAuthor());
            return book;
        }
        return bean;
    }

    /**
     * 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之后,调用该方法进行处理;传入的bean对象属性此时已经装配好。
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.printf("%-70s:%s{%s}%n",
                "------BookProxyBeanPostProcessor#postProcessAfterInitialization",
                bean.getClass().getSimpleName(), bean);
        return bean;
    }
}

main

定义一个Book类型的GenericBeanDefinition,将Book#customInit()添加到BeanDefinition中,并设置MutablePropertyValues用于初始化后的属性装配。
同时将BookProxyBeanPostProcessor注册到容器中。

public static void main(String[] args) {
    GenericApplicationContext context = new GenericApplicationContext();
    GenericBeanDefinition bookBeanDefinition = new GenericBeanDefinition();
    bookBeanDefinition.setBeanClass(Book.class);
    bookBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);//指定为单例模式
    //设置属性
    bookBeanDefinition.setPropertyValues(new MutablePropertyValues()
            .addPropertyValue(new PropertyValue("name", "《非暴力沟通》"))
            .addPropertyValue(new PropertyValue("author", "马歇尔·卢森堡"))
    );
    bookBeanDefinition.setInitMethodName("customInit");//设置初始化方法
    context.registerBeanDefinition("book", bookBeanDefinition);//注册BeanDefinition
    context.registerBean("bookProxyBeanPostProcessor", BookProxyBeanPostProcessor.class);//注册Bean后处理器
    context.refresh();//刷新容器
    context.getBean("book", Book.class).show();
}

全量代码

package com.baiyang.beanpostprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.context.support.GenericApplicationContext;


public class BookProxyBeanPostProcessor implements BeanPostProcessor {

    /**
     * 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之前,调用该方法进行处理;传入的bean对象属性此时已经装配好。
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.printf("%-70s:%s{%s}%n",
                "------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
                bean.getClass().getSimpleName(),
                bean);
        if (Book.class.equals(bean.getClass())) {
            System.out.printf("\033[1;33m%-70s:对[%s]的\033[1;31mshow()\033[1;33m方法进行增强 \033[0m%n",
                    "------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
                    bean.getClass().getSimpleName());
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Book.class);
            enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) -> {
                if (!method.equals(Book.class.getMethod("show"))) {
                    return methodProxy.invokeSuper(obj, args);
                }
                System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行前");
                Object result = methodProxy.invokeSuper(obj, args);
                System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行后");
                return result;
            });
            Book book = (Book) enhancer.create();
            book.setName(((Book) bean).getName());
            book.setAuthor(((Book) bean).getAuthor());
            return book;
        }
        return bean;
    }

    /**
     * 在容器调用Bean的InitializingBean#afterPropertiesSet()或自定义的init-method之后,调用该方法进行处理;传入的bean对象属性此时已经装配好。
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.printf("%-70s:%s{%s}%n",
                "------BookProxyBeanPostProcessor#postProcessAfterInitialization",
                bean.getClass().getSimpleName(), bean);
        return bean;
    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        GenericBeanDefinition bookBeanDefinition = new GenericBeanDefinition();
        bookBeanDefinition.setBeanClass(Book.class);
        bookBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);//指定为单例模式
        //设置属性
        bookBeanDefinition.setPropertyValues(new MutablePropertyValues()
                .addPropertyValue(new PropertyValue("name", "《非暴力沟通》"))
                .addPropertyValue(new PropertyValue("author", "马歇尔·卢森堡"))
        );
        bookBeanDefinition.setInitMethodName("customInit");//设置初始化方法
        context.registerBeanDefinition("book", bookBeanDefinition);//注册BeanDefinition
        context.registerBean("bookProxyBeanPostProcessor", BookProxyBeanPostProcessor.class);//注册Bean后处理器
        context.refresh();//刷新容器
        context.getBean("book", Book.class).show();
    }


    static class Book implements InitializingBean {
        private String name;
        private String author;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAuthor() {
            return author;
        }

        public void setAuthor(String author) {
            this.author = author;
        }

        public void show() {
            System.out.printf("book#show():%s\n", this);
        }

        public void customInit() {
            System.out.printf("%-70s:%s{%s}%n", "------Book#customInit", this.getClass().getSimpleName(), this);
        }

        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", author='" + author + '\'' +
                    '}';
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.printf("%-70s:%s{%s}%n", "------Book#afterPropertiesSet", this.getClass().getSimpleName(), this);
        }
    }
}

执行结果

在这里插入图片描述
从执行结果即可反应出BeanPostProcessor执行流程

源码解析

spring版本:5.2.9

该节源码解析仅仅只讲关键的与BeanPostProcessor相关的位置。如果想要知其与BeanPostProcessor前后的细节,可以针对本节的所讲述的位置自行Debug进入详细阅读。

首先是Spring容器的经典入口:refresh()
在这里插入图片描述
然后调用AbstractApplicationContext所持有的实际BeanFactory(DefaultListableBeanFactory)句柄的preInstantiateSingletons()做Bean容器的初始化工作。
在这里插入图片描述


org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons:在这里插入图片描述
进入getBean()方法,由于我们是新创建bean,所以流程将会是getBean()->doGetBean()->createBean()->doCreateBean()的流程,咱们一路DEBUG到doCreateBean():
在这里插入图片描述
由于我们重点是在了解BeanPostProcessor的内部执行流程上,所以上图隐藏了一些不太相关的代码,避免干扰;
此时还没有调用到BeanPostProcessor,所以从doCreateBean的执行流程可以看出,此时已经将Bean进行的实例化,并且装配好了属性值。
接着进入到关键方法exposedObject = initializeBean(beanName, exposedObject, mbd);


org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
在这里插入图片描述
从上面的initializeBean()的流程可以看到我们首先调用了BeanPostProcessor#postProcessBeforeInitialization(),然后执行了invokeInitMethods()来处理bean的实现的InitializingBean接口的afterPropertiesSet()与自定义init-method;最后执行BeanPostProcessor#postProcessAfterInitialization();


org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
在这里插入图片描述
从上面的方法可以看出BeanPostProcessor#postProcessBeforeInitialization是可以改变即将注册到BeanFactory 中的实际对象的。


org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods
在这里插入图片描述
从上面的invokeInitMethods()可以看到包含了InitializingBean接口的处理与init-method的方法处理流程;
init-method方法最终会通过反射执行。


最后就是BeanPostProcessor#postProcessAfterInitialization()方法的执行:
在这里插入图片描述


至此initializeBean()方法执行结束返回到doCreateBean():
在这里插入图片描述
doCreateBean()initializeBean()返回的对象返回出去,一路回到getSingleton():
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
在这里插入图片描述
可以看到此时,已经将一个经过了BeanPostProcess处理的Bean对象注册到了BeanFactory中(在本例子里面是我们的BookProxyBeanPostProcessor创建的Book对象的代理类)。

总结

以上通过围绕BeanPostProcessor创建一个对指定Bean对象的代理对象,对其特定方法进行代理增强的例子,来介绍了BeanPostProcessor的应用。
同时,通过对源码的浅析来对BeanPostProcessor执行前后流程进行了讲解。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-06 10:55:43  更:2022-05-06 10:56:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:56:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码