Spring之Bean后处理器——BeanPostProcessor的使用与源码解析

Spring之Bean后处理器——BeanPostProcessor的使用与源码解析,第1张

文章目录
      • BeanPostProcessor介绍
        • BeanPostProcessor执行流程
      • BeanPostProcessor使用
        • Book
        • BookProxyBeanPostProcessor
        • main
        • 全量代码
        • 执行结果
      • 源码解析
      • 总结

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("3[1;33m%-70s:对[%s]的3[1;31mshow()3[1;33m方法进行增强 3[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("3[1;33m%-70s3[0m%n", "Book#show()执行前");
                Object result = methodProxy.invokeSuper(obj, args);
                System.out.printf("3[1;33m%-70s3[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("3[1;33m%-70s:对[%s]的3[1;31mshow()3[1;33m方法进行增强 3[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("3[1;33m%-70s3[0m%n", "Book#show()执行前");
                Object result = methodProxy.invokeSuper(obj, args);
                System.out.printf("3[1;33m%-70s3[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的执行前后流程进行了讲解。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/872102.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存