spring4.1.8扩展实战之七:控制bean(BeanPostProcessor接口)

简介: 实战在容器初始化的时候对bean实例做设置

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码): https://github.com/zq2599/blog_demos
  • 本章是《spring4.1.8扩展实战》的第七篇,我们来尝试在容器初始化的时候对bean实例做设置;

控制bean的两种扩展方式

  • 两种方式可以对bean做控制(例如修改某个成员变量)
  1. 改变bean的定义(BeanFactoryPostProcessor接口) ,可以想象成修改了class文件,这样实例化出来的每个对象都变了;
  2. 只改变实例化的对象(BeanPostProcessor接口);

本章概览

  • 全文由以下部分组成:
  1. spring源码分析,了解BeanPostProcessor接口的实现类如何被注册到spring容器;
  2. spring源码分析,了解已经注册到spring环境的BeanPostProcessor实现类如何被使用;
  3. 实战,开发一个BeanPostProcessor实现类,验证是否能用来改变指定的bean;

源码分析:BeanPostProcessor接口的实现类如何被注册到spring容器

  • 从spring容器的初始化代码看起吧,看AbstractApplicationContext类的refresh方法,如下图所示,红框中的方法负责将BeanPostProcessor接口的实现类注册到spring容器:

image.png

  • 展开registerBeanPostProcessors方法,发现是委托PostProcessorRegistrationDelegate类的静态方法registerBeanPostProcessors来完成注册工作的:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
  • 展开PostProcessorRegistrationDelegate.registerBeanPostProcessors方法,里面的代码逻辑简洁整齐,意图目的一目了然:
public static void registerBeanPostProcessors(
        ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    //获取所有实现BeanPostProcessor接口的bean的名称
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

    //注意,此时尽管注册操作还没有开始,但是之前已经有一些特殊的bean已经注册进来了,
    //详情请看AbstractApplicationContext类的prepareBeanFactory方法,
    //因此getBeanPostProcessorCount()方法返回的数量并不为零,
    //加一是因为方法末尾会注册一个ApplicationListenerDetector接口的实现类
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    //这里的BeanPostProcessorChecker也是个BeanPostProcessor的实现类,用于每个bean的初始化完成后,做一些简单的检查
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

    //如果这些bean还实现了PriorityOrdered接口(在意执行顺序),就全部放入集合priorityOrderedPostProcessors 
    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
    //集合internalPostProcessors,用来存放同时实现了PriorityOrdered和MergedBeanDefinitionPostProcessor接口的bean
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
    //集合orderedPostProcessorNames用来存放实现了Ordered接口的bean的名称(在意执行顺序)
    List<String> orderedPostProcessorNames = new ArrayList<String>();
    //集合nonOrderedPostProcessorNames用来存放即没实现PriorityOrdered接口,也没有实现Ordered接口的bean的名称(不关心执行顺序)
    List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            //实现了PriorityOrdered接口的bean,都放入集合priorityOrderedPostProcessors
            priorityOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                //实现了MergedBeanDefinitionPostProcessor接口的bean,都放入internalPostProcessors集合
                internalPostProcessors.add(pp);
            }
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            //实现了Ordered接口的bean,将其名称都放入orderedPostProcessorNames集合
            orderedPostProcessorNames.add(ppName);
        }
        else {
            //既没实现PriorityOrdered接口,也没有实现Ordered接口的bean,将其名称放入nonOrderedPostProcessorNames集合
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    //实现了PriorityOrdered接口的bean排序
    OrderComparator.sort(priorityOrderedPostProcessors);
    //注册到容器
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
    //处理所有实现了Ordered接口的bean
    for (String ppName : orderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        orderedPostProcessors.add(pp);
        //前面将所有实现了PriorityOrdered和MergedBeanDefinitionPostProcessor的bean放入internalPostProcessors,
        //此处将所有实现了Ordered和MergedBeanDefinitionPostProcessor的bean放入internalPostProcessors
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }

    //实现了Ordered接口的bean排序
    OrderComparator.sort(orderedPostProcessors);
    //注册到容器
    registerBeanPostProcessors(beanFactory, orderedPostProcessors);

    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
    for (String ppName : nonOrderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        nonOrderedPostProcessors.add(pp);
        //此处将其余实现了MergedBeanDefinitionPostProcessor的bean放入internalPostProcessors
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    //注册到容器
    registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

    OrderComparator.sort(internalPostProcessors);
    //将所有实现了MergedBeanDefinitionPostProcessor接口的bean也注册到容器
    registerBeanPostProcessors(beanFactory, internalPostProcessors);
    //创建一个ApplicationListenerDetector对象并且注册到容器,这就是前面计算beanProcessorTargetCount的值时加一的原因
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
  • 以上代码已加注释,就不多解读了,有一点需要注意:对于实现了MergedBeanDefinitionPostProcessor接口的bean,在前面几次调用registerBeanPostProcessors方法的时候已经注册过了,那么在最后执行的registerBeanPostProcessors(beanFactory, internalPostProcessors),岂不是将一个bean注册了多次?
  • 为了弄清楚这个问题需要看registerBeanPostProcessors方法:
private static void registerBeanPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

    for (BeanPostProcessor postProcessor : postProcessors) {
        //对每个bean都调用beanFactory.addBeanPostProcessor方法来注册
        beanFactory.addBeanPostProcessor(postProcessor);
    }
}
  • addBeanPostProcessor方法的代码在AbstractApplicationContext类中,如下所示,先删除再添加,这样反复注册也没有问题
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    //如果已经注册,就先删除掉
    this.beanPostProcessors.remove(beanPostProcessor);
    //再注册
    this.beanPostProcessors.add(beanPostProcessor);
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
        this.hasInstantiationAwareBeanPostProcessors = true;
    }
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
        this.hasDestructionAwareBeanPostProcessors = true;
    }
}
  • 至此,我们已经弄清楚了BeanPostProcessor实现类的bean注册到spring容器的逻辑,接下来看看spring容器如何使用这些bean;

源码分析,BeanPostProcessor实现类如何被使用

  • 要弄清楚BeanPostProcessor接口的实现类是在哪里被用到的,还是从负责容器初始化的AbstractApplicationContext类的refresh方法看起,如下图红框中的finishBeanFactoryInitialization方法,就是负责实例化和初始化bean的:

image.png

  • 从finishBeanFactoryInitialization方法到BeanPostProcessor的实现类被使用,中间有多层逻辑和调用,篇幅所限就不逐个展开了,直接列出堆栈信息,您可以根据此信息去查看对应源码:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean()
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean()
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean()
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject()
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton()
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean()
org.springframework.beans.factory.support.AbstractBeanFactory.getBean()
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons()
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization()
org.springframework.context.support.AbstractApplicationContext.refresh()
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh()
org.springframework.boot.SpringApplication.refresh()
org.springframework.boot.SpringApplication.refreshContext()
org.springframework.boot.SpringApplication.run()
org.springframework.boot.SpringApplication.run()
org.springframework.boot.SpringApplication.run()
  • 根据上述堆栈信息,直接查看AbstractAutowireCapableBeanFactory类的initializeBean()方法:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //对已经实例化的bean,在初始化前用BeanPostProcessor实现类去处理
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        //bean的初始化
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        //对已经实例化的bean,在初始化后用BeanPostProcessor实现类去处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
  • 如上所示,我们最关注的代码是applyBeanPostProcessorsBeforeInitializationapplyBeanPostProcessorsAfterInitialization这两个方法,它们分别在bean的初始化方法invokeInitMethods的前后被执行;
  • 先看看applyBeanPostProcessorsBeforeInitialization方法,逻辑非常简单,就是取出所有已注册的BeanPostProcessor实现类,执行其postProcessBeforeInitialization方法,入参是当前正在做实例化和初始化的bean实例:
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    //逐一执行每个BeanPostProcessor实现类的postProcessBeforeInitialization方法
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}
  • 在invokeInitMethods方法执行完毕后会执行applyBeanPostProcessorsAfterInitialization方法,代码如下,与applyBeanPostProcessorsBeforeInitialization如出一辙,仅有的不同是调用的beanProcessor的方法变成了postProcessAfterInitialization:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    //逐一执行每个BeanPostProcessor实现类的postProcessAfterInitialization方法
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}
  • 以上就是spring容器初始化过程中对BeanPostProcessor实现类的使用场景,此时还剩一点疑问需要澄清:在分析注册过程的时候,曾看到实现MergedBeanDefinitionPostProcessor接口的bean是最后注册的,那么这些MergedBeanDefinitionPostProcessor实现类在spring容器中是何处使用的呢?
  • 为了搞清这个问题,来看看AbstractAutowireCapableBeanFactory类的doCreateBean方法,前面我们分析的initializeBean方法就是在这里面被调用的:

image.png

  • 如上图所示,红框中就是用所有MergedBeanDefinitionPostProcessor实现类去处理当前正在实例化的bean,然后才会执行绿框中的initializeBean方法(里面是我们刚才分析的bean的初始化,BeanPostProcessor实现类被使用的逻辑);
  • 来看看红框中的applyMergedBeanDefinitionPostProcessors方法,主要目的是处理特殊的合成bean的定义类:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
            throws BeansException {

    try {
        //取出每个注册的BeanPostProcessor实现类
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            //只有实现了MergedBeanDefinitionPostProcessor接口才执行
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                //执行postProcessMergedBeanDefinition
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
    }
    catch (Exception ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Post-processing failed of bean type [" + beanType + "] failed", ex);
    }
}
  • 至此,我们对BeanPostProcessor有关的源码分析就完成了,小结一下:
  1. 初始化时,spring容器有特别处理,会直接调用beanFactory.addBeanPostProcessor进行注册(例如AbstractApplicationContext类的prepareBeanFactory方法中就有);
  2. 找出所有实现了BeanPostProcessor接口的bean,注册到容器,注册顺序如下:

第一:实现了PriorityOrdered接口的,排序后;
第二:实现了Ordered接口的,排序后;
第三:既没实现PriorityOrdered接口,也没有实现Ordered接口的;
第四:实现了MergedBeanDefinitionPostProcessor接口的(这些也按照PriorityOrdered、Ordered等逻辑拍过续);
第五:实例化一个ApplicationListenerDetector对象;

  1. 实例化bean的时候,对于每个bean,先用MergedBeanDefinitionPostProcessor实现类的postProcessMergedBeanDefinition方法处理每个bean的定义类;
  2. 再用BeanPostProcessor的postProcessBeforeInitialization方法处理每个bean实例;
  3. bean实例初始化;
  4. 用BeanPostProcessor的postProcessAfterInitialization方法处理每个bean实例;
  • 源码分析结束,接下来自定义一个BeanPostProcessor实现类,验证我们之前的分析:控制bean实例;

实战自定义BeanPostProcessor实现类

  • 本次实战的内容是创建一个springboot工程,在里面自定义一个BeanPostProcessor接口的实现类,如果您不想敲代码,也可以去github下载源码,地址和链接信息如下表所示:
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本章源码在文件夹customizebeanpostprocessor下,如下图红框所示:

image.png

  • 接下来开始实战吧:
  • 基于maven创建一个springboot的web工程,名为customizebeanpostprocessor,pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bolingcavalry</groupId>
    <artifactId>customizebeanpostprocessor</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>customizebeanpostprocessor</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.15.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
  • 创建Utils.java,里面有一些静态的工具方法,例如打印当前堆栈:
package com.bolingcavalry.customizebeanpostprocessor.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Utils {

    private static final Logger logger = LoggerFactory.getLogger(Utils.class);

    /**
     * 打印当前线程堆栈信息
     * @param prefix
     */
    public static void printTrack(String prefix){
        StackTraceElement[] st = Thread.currentThread().getStackTrace();

        if(null==st){
            logger.info("invalid stack");
            return;
        }

        StringBuffer sbf =new StringBuffer();

        for(StackTraceElement e:st){
            if(sbf.length()>0){
                sbf.append(" <- ");
                sbf.append(System.getProperty("line.separator"));
            }

            sbf.append(java.text.MessageFormat.format("{0}.{1}() {2}"
                    ,e.getClassName()
                    ,e.getMethodName()
                    ,e.getLineNumber()));
        }

        logger.info(prefix
                + "\n************************************************************\n"
                + sbf.toString()
                + "\n************************************************************");
    }
}
  • 创建接口CalculateService,定义了几个方法:
package com.bolingcavalry.customizebeanpostprocessor.service;

public interface CalculateService {
    /**
     * 整数加法
     * @param a
     * @param b
     * @return
     */
    int add(int a, int b);

    /**
     * 返回当前实现类的描述信息
     * @return
     */
    String getServiceDesc();

    /**
     * 设置当前实现类的描述信息
     * @return
     */
    void setServiceDesc(String serviceDesc);
}
  • 创建CalculateService的实现类CalculateServiceImpl,并且用@Service注解将定义为spring的bean:
package com.bolingcavalry.customizebeanpostprocessor.service.impl;


import com.bolingcavalry.customizebeanpostprocessor.service.CalculateService;
import org.springframework.stereotype.Service;

@Service("calculateService")
public class CalculateServiceImpl implements CalculateService {

    private String serviceDesc = "desc from class";

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public String getServiceDesc() {
        return serviceDesc;
    }

    @Override
    public void setServiceDesc(String serviceDesc) {
        this.serviceDesc = serviceDesc;
    }
}
  • 注意该类的成员变量serviceDesc,值已经固定为"desc from class";
  • 创建Controller类HelloController,在响应web请求的时候,会用到calculateService提供的服务:
package com.bolingcavalry.customizebeanpostprocessor.controller;

import com.bolingcavalry.customizebeanpostprocessor.service.CalculateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @Autowired(required = false)
    CalculateService calculateService;


    @GetMapping("/add/{a}/{b}")
    public String add(@PathVariable("a") int a, @PathVariable("b") int b){
        return "add result : " + calculateService.add(a, b) + ", from [" + calculateService.getServiceDesc() + "]";
    }
}
  • 如上所示,正常情况下,web响应为"add result : x, from [desc from class]",这个desc from class,就是CalculateServiceImpl的成员变量serviceDesc的值;
  • 创建BeanPostProcessor的实现类CustomizeBeanPostProcessor,这里面会修改calculateService实例的成员变量serviceDesc的值,记得用注解@Component将其设置为bean:
package com.bolingcavalry.customizebeanpostprocessor.processor;

import com.bolingcavalry.customizebeanpostprocessor.service.CalculateService;
import com.bolingcavalry.customizebeanpostprocessor.util.Utils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class CustomizeBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if("calculateService".equals(beanName)) {
        //打印当前堆栈
            Utils.printTrack("do postProcess before initialization");
            CalculateService calculateService = (CalculateService)bean;
            //修改calculateService实例的成员变量serviceDesc的值
            calculateService.setServiceDesc("desc from " + this.getClass().getSimpleName());
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if("calculateService".equals(beanName)) {
            //打印当前堆栈
            Utils.printTrack("do postProcess after initialization");
        }
        return bean;
    }
}
  • 启动应用,在启动日志中可以看到CustomizeBeanPostProcessor实例的两个方法被调用时打印的堆栈日志,和之前我们分析的源码是一致的:
2018-09-02 18:35:53.618  INFO 22520 --- [           main] c.b.c.util.Utils                         : do postProcess before initialization
************************************************************
java.lang.Thread.getStackTrace() 1,559 <- 
com.bolingcavalry.customizebeanpostprocessor.util.Utils.printTrack() 15 <- 
com.bolingcavalry.customizebeanpostprocessor.processor.CustomizeBeanPostProcessor.postProcessBeforeInitialization() 14 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization() 409 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean() 1,626 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean() 555 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean() 483 <- 
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject() 312 <- 
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton() 230 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean() 308 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.getBean() 202 <- 
org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate() 208 <- 
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency() 1,138 <- 
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency() 1,066 <- 
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject() 585 <- 
org.springframework.beans.factory.annotation.InjectionMetadata.inject() 88 <- 
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues() 366 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean() 1,272 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean() 553 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean() 483 <- 
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject() 312 <- 
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton() 230 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean() 308 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.getBean() 197 <- 
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons() 761 <- 
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization() 867 <- 
org.springframework.context.support.AbstractApplicationContext.refresh() 543 <- 
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh() 122 <- 
org.springframework.boot.SpringApplication.refresh() 693 <- 
org.springframework.boot.SpringApplication.refreshContext() 360 <- 
org.springframework.boot.SpringApplication.run() 303 <- 
org.springframework.boot.SpringApplication.run() 1,118 <- 
org.springframework.boot.SpringApplication.run() 1,107 <- 
com.bolingcavalry.customizebeanpostprocessor.CustomizebeanpostprocessorApplication.main() 10
************************************************************
2018-09-02 18:35:53.619  INFO 22520 --- [           main] c.b.c.util.Utils                         : do postProcess after initialization
************************************************************
java.lang.Thread.getStackTrace() 1,559 <- 
com.bolingcavalry.customizebeanpostprocessor.util.Utils.printTrack() 15 <- 
com.bolingcavalry.customizebeanpostprocessor.processor.CustomizeBeanPostProcessor.postProcessAfterInitialization() 24 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization() 423 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean() 1,638 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean() 555 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean() 483 <- 
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject() 312 <- 
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton() 230 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean() 308 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.getBean() 202 <- 
org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate() 208 <- 
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency() 1,138 <- 
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency() 1,066 <- 
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject() 585 <- 
org.springframework.beans.factory.annotation.InjectionMetadata.inject() 88 <- 
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues() 366 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean() 1,272 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean() 553 <- 
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean() 483 <- 
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject() 312 <- 
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton() 230 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean() 308 <- 
org.springframework.beans.factory.support.AbstractBeanFactory.getBean() 197 <- 
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons() 761 <- 
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization() 867 <- 
org.springframework.context.support.AbstractApplicationContext.refresh() 543 <- 
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh() 122 <- 
org.springframework.boot.SpringApplication.refresh() 693 <- 
org.springframework.boot.SpringApplication.refreshContext() 360 <- 
org.springframework.boot.SpringApplication.run() 303 <- 
org.springframework.boot.SpringApplication.run() 1,118 <- 
org.springframework.boot.SpringApplication.run() 1,107 <- 
com.bolingcavalry.customizebeanpostprocessor.CustomizebeanpostprocessorApplication.main() 10
************************************************************
  • 在浏览器访问地址:http://localhost:8080/add/1/2,可以看到响应如下图所示,calculateService的成员变量serviceDesc的值已经被CustomizeBeanPostProcessor改为desc from CustomizeBeanPostProcessor

image.png

  • 至此,本次实战就完成了,从spring源码分析再到动手实战,我们对BeanPostProcessor的扩展有了更深入的认识,也希望这种扩展能帮助您更好的控制bean实例为业务需求服务;

欢迎关注阿里云开发者社区博客:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...
相关文章
|
13天前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
53 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
2天前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
8 2
|
3天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
13天前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
42 1
|
15天前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
16 1
|
15天前
|
Java 数据库连接 Spring
【2021Spring编程实战笔记】Spring开发分享~(下)
【2021Spring编程实战笔记】Spring开发分享~(下)
22 1
|
5天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
17 0
|
13天前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
|
存储 Java 程序员
深入理解 Spring BeanPostProcessor
回顾上一篇博客中,在AbstractApplicationContext这个抽象类中,Spring使用invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor,通过回调Spring自己添加的ConfigurationClassPostProcessor以及用户添加的bean工厂的后置处理器,完成了包扫描以及对主配置类代理的工作 本篇博文将继续往下跟进
144 0
|
1月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。