美文网首页微服务
如何往Spring中动态注册一个Bean和SpringBean的

如何往Spring中动态注册一个Bean和SpringBean的

作者: DH大黄 | 来源:发表于2019-10-21 19:18 被阅读0次

    本文主要叙述的两个点:

    • 如何向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<String> 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的

        本文链接:https://www.haomeiwen.com/subject/islxvctx.html