如何往Spring中动态注册一个Bean和SpringBean的生命周期

本文主要叙述的两个点:

  • 如何向Spring中注册一个Bean
  • Spring中Bean从创建到销毁都会经历什么(Spring Bean 的生命周期)
第一点:如何向Spring中注册一个Bean

注册一个Bean流程:

以Sentinel的为RestTemplate添加拦截器中的注册Bean为例:

完整代码:

private void registerBean(String interceptorBeanName,
            SentinelRestTemplate sentinelRestTemplate, RestTemplate restTemplate) {
    // register SentinelProtectInterceptor bean
    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
        .getAutowireCapableBeanFactory();
    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
        .genericBeanDefinition(SentinelProtectInterceptor.class);
    beanDefinitionBuilder.addConstructorArgValue(sentinelRestTemplate);
    beanDefinitionBuilder.addConstructorArgValue(restTemplate);
    BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
        .getRawBeanDefinition();
    beanFactory.registerBeanDefinition(interceptorBeanName,
                                       interceptorBeanDefinition);
}
1.获得Bean工厂
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
                .getAutowireCapableBeanFactory();
2.获得动态bean的构造器
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
                .genericBeanDefinition(SentinelProtectInterceptor.class);   
3.往SentinelProtectInterceptor的构造器塞入参数并返回定义的对象
beanDefinitionBuilder.addConstructorArgValue(sentinelRestTemplate);
beanDefinitionBuilder.addConstructorArgValue(restTemplate);
BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
                .getRawBeanDefinition();
public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
    private final SentinelRestTemplate sentinelRestTemplate;

    private final RestTemplate restTemplate;

    public SentinelProtectInterceptor(SentinelRestTemplate sentinelRestTemplate,
            RestTemplate restTemplate) {
        this.sentinelRestTemplate = sentinelRestTemplate;
        this.restTemplate = restTemplate;
    }
    // methods
}
4.注册
beanFactory.registerBeanDefinition(interceptorBeanName,
                interceptorBeanDefinition);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Validation of bean definition failed", ex);
        }
    }

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                             "' with a different definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean '" + beanName +
                             "' with an equivalent definition: replacing [" + existingDefinition +
                             "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        if (hasBeanCreationStarted()) {
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                removeManualSingletonName(beanName);
            }
        }
        else {
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}
由第一点引出第二点:Spring中Bean从创建到销毁都会经历什么(Spring Bean 的生命周期)

首先先看代码,然后对代码进行逐一讲解

代码地址

项目启动类
package com.narcos.frameworklearn;

import com.narcos.frameworklearn.bean.BeanOne;
import com.narcos.frameworklearn.bean.BeanTwo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

/**
 * SpringBootApplication 包含了 @ComponentScan
 * ComponentScan 只能扫描 FrameworkLearnApplication 所在当前包一下的 如果不在当前包 需要另外指定包的路径
 *
 * @author hbj
 */
@Slf4j
@SpringBootApplication
public class FrameworkLearnApplication {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(FrameworkLearnApplication.class, args);

        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        // 注册BeanOne
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(BeanOne.class);
        // BeanOne构造器需要的参数
        beanDefinitionBuilder.addConstructorArgValue("I am BeanOne");
        // 设置init方法(BeanOne中的方法)
        beanDefinitionBuilder.setInitMethodName("init");
        // 设置destory方法(BeanOne中的方法)
        beanDefinitionBuilder.setDestroyMethodName("destroy");
        BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
                .getRawBeanDefinition();
        // 以beanOne为名称注册Bean
        beanFactory.registerBeanDefinition("beanOne",
                interceptorBeanDefinition);
        // 获取BeanOne
        BeanOne beanOne = (BeanOne) applicationContext.getBean("beanOne");
        // 执行BeanOne的方法
        log.info(beanOne.getWords());
        // 销毁BeanOne
        beanOne.destroy();

        BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.genericBeanDefinition(BeanTwo.class);
        beanDefinitionBuilder2.addConstructorArgValue("I am BeanTwo");
        beanDefinitionBuilder2.setInitMethodName("init");
        beanDefinitionBuilder2.setDestroyMethodName("destroy");
        BeanDefinition interceptorBeanDefinition2 = beanDefinitionBuilder2
                .getRawBeanDefinition();
        beanFactory.registerBeanDefinition("beanTwo",
                interceptorBeanDefinition2);
        BeanTwo beanTwo = (BeanTwo) applicationContext.getBean("beanTwo");
        log.info(beanTwo.getWords());
        beanTwo.destroy();
    }
}

对应的两个Bean实体

package com.narcos.frameworklearn.bean;

import lombok.extern.slf4j.Slf4j;

/**
 * @author hbj
 * @date 2019/10/21 23:18
 */
@Slf4j
public class BeanOne {
    private String words;

    public BeanOne(String words) {
        this.words = words;
    }

    public String getWords() {
        return "say : " + words;
    }

    public void setWords(String words) {
        this.words = words;
    }

    public void init() {
        log.info("准备初始化BeanOne");
    }

    public void destroy() {
        log.info("准备销毁BeanOne");
    }
}

package com.narcos.frameworklearn.bean;

import lombok.extern.slf4j.Slf4j;

/**
 * @author hbj
 * @date 2019/10/21 23:18
 */
@Slf4j
public class BeanTwo {
    private String words;

    public BeanTwo(String words) {
        this.words = words;
    }

    public String getWords() {
        return "say : " + words;
    }

    public void setWords(String words) {
        this.words = words;
    }

    public void init() {
        log.info("准备初始化BeanTwo");
    }

    public void destroy() {
        log.info("准备销毁BeanTwo");
    }
}

Bean初始化前后的处理器:

package com.narcos.frameworklearn.processor;

import com.narcos.frameworklearn.bean.BeanOne;
import com.narcos.frameworklearn.bean.BeanTwo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * 注:对所有的Bean都是有效的
 *
 * @author hbj
 * @date 2019/10/21 23:15
 */
@Slf4j
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof BeanOne || bean instanceof BeanTwo) {
            log.info("这是在Bean:{}-{}初始化前执行的前置处理器", bean, beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof BeanOne || bean instanceof BeanTwo) {
            log.info("这是在Bean:{}-{}初始化后执行的后置处理器", bean, beanName);
        }
        return bean;
    }
}

执行代码,观察打印的日志

2019-10-22 10:44:43.622  INFO 9960 --- [           main] c.n.f.processor.MyBeanPostProcessor      : 这是在Bean:com.narcos.frameworklearn.bean.BeanOne@280099a0-beanOne初始化前执行的前置处理器
2019-10-22 10:44:43.622  INFO 9960 --- [           main] com.narcos.frameworklearn.bean.BeanOne   : 准备初始化BeanOne
2019-10-22 10:44:43.623  INFO 9960 --- [           main] c.n.f.processor.MyBeanPostProcessor      : 这是在Bean:com.narcos.frameworklearn.bean.BeanOne@280099a0-beanOne初始化后执行的后置处理器
2019-10-22 10:44:43.623  INFO 9960 --- [           main] c.n.f.FrameworkLearnApplication          : say : I am BeanOne
2019-10-22 10:44:43.623  INFO 9960 --- [           main] com.narcos.frameworklearn.bean.BeanOne   : 准备销毁BeanOne
2019-10-22 10:44:43.623  INFO 9960 --- [           main] c.n.f.processor.MyBeanPostProcessor      : 这是在Bean:com.narcos.frameworklearn.bean.BeanTwo@1bf52f10-beanTwo初始化前执行的前置处理器
2019-10-22 10:44:43.623  INFO 9960 --- [           main] com.narcos.frameworklearn.bean.BeanTwo   : 准备初始化BeanTwo
2019-10-22 10:44:43.623  INFO 9960 --- [           main] c.n.f.processor.MyBeanPostProcessor      : 这是在Bean:com.narcos.frameworklearn.bean.BeanTwo@1bf52f10-beanTwo初始化后执行的后置处理器
2019-10-22 10:44:43.623  INFO 9960 --- [           main] c.n.f.FrameworkLearnApplication          : say : I am BeanTwo
2019-10-22 10:44:43.623  INFO 9960 --- [           main] com.narcos.frameworklearn.bean.BeanTwo   : 准备销毁BeanTwo

由此我们可以发现,实例化一个Bean的流程为:

设置对象属性->BeanPostProcessor前置处理->执行自定义的initMetod->BeanPostProcessor后置处理->执行自定义的destroy方法

你可能感兴趣的:(如何往Spring中动态注册一个Bean和SpringBean的生命周期)