从理论到实践—Spring bean生命周期

Spring Bean的生命周期,总结为五大阶段,十三个环节,如下图所示:

Bean生命周期流程图

每个阶段详解的说明可以参考:Spring Bean生命周期详解

下面是不是开始讲怎么用了?慢着,现在是Springboot的天下,先看一下Springboot中是怎么管理Bean的

先从启动类SpringApplication开始

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

源码就不一一跟了,重点在this.refreshContext(context);接着进入AbstractApplicationContext.refresh()方法

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            // 准备刷新
            this.prepareRefresh();
            // 获取BeanFactory;默认实现是DefaultListableBeanFactory,在创建容器的时候创建的
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            // 设置beanFactory类加载器,添加多个beanPostProcesser
            this.prepareBeanFactory(beanFactory);

            try {
                // BeanFactory准备工作完成后进行的后置处理工作
                this.postProcessBeanFactory(beanFactory);
                // 调用BeanFactoryPostProcessor各个实现类的方法
                this.invokeBeanFactoryPostProcessors(beanFactory);
                // 注册 BeanPostProcessor 的实现类
                this.registerBeanPostProcessors(beanFactory);
                //初始化ApplicationContext的MessageSource(做国际化功能;消息绑定,消息解析);
                this.initMessageSource();
                //初始化ApplicationContext事件广播器
                this.initApplicationEventMulticaster();
                // 初始化子类特殊bean(钩子方法,如创建Tomcat,Jetty等WEB服务器)
                this.onRefresh();
                // 注册事件监听器
                this.registerListeners();
                // 初始化所有非懒加载的singleton bean
                this.finishBeanFactoryInitialization(beanFactory);
                // 广播事件(ContextRefreshedEvent),完成context的刷新
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

源码中特意添加了注释,大家可以自己和上面Bean生命周期的节点一一对应。

 

从理论到实践

这么多内容根本记不住啊,下面我们来划重点,结合项目中的应用来帮助大家记忆,需要记住以下几个关键点:

1、registerBeanDefinition:执行完 registerBeanDefinition 方法后,Bean 的名称和对应的 BeanDefinition 就被放入了容器中,后续获取 Bean 也是从这个容器中获取,在插件式开发中经常用到,是加载fatjar的关键。下面是一个在Springboot启动后将jar包中的class注册成bean的例子:

    /**
     * 将jar包插件中的class注册成bean.
     * 
     * @param classes
     */
    private void registBean(Vector<Class> classes) {
        BeanDefinitionRegistry beanDefinitionRegistry = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
​
        classes.forEach(c -> {
            // 将有Component注解的类注册成bean
            Component annotation = AnnotationUtils.findAnnotation(c, Component.class);
            if (null != annotation && condition(c)) {
​
                // 如果Component未指定bean名称, 就用第一个字母小写的类名作为bean名称.
                String beanName = annotation.value();
                if (!StringUtils.hasText(beanName)) {
                    char[] cs = c.getSimpleName().toCharArray();
                    cs[0] = ("" + cs[0]).toLowerCase().toCharArray()[0];
                    beanName = String.valueOf(cs);
                }
​
                // 注册bean.
                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(c);
                BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
                beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
                logger.info("[{}] registered as {}", c.getName(), beanName);
            }
        });
    }

2、InstantiationAwareBeanPostProcessor:作用于实例化阶段的前后,实现了InstantiationAwareBeanPostProcessor接口的bean,是@Autowired、@Value注解的依赖注入的关键。

下面是@Autowired的2处关键源码,可以看出@Autowired是利用了InstantiationAwareBeanPostProcessor和java反射机制实现的

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
 
   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   boolean continueWithPropertyPopulation = true;
    // InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
    // 方法作为属性赋值的前置检查条件,在属性赋值之前执行,能够影响是否进行属性赋值!
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }
 
   // 忽略后续的属性赋值操作代码
}
​
public void processInjection(Object bean) throws BeanCreationException {
        Class<?> clazz = bean.getClass();
        InjectionMetadata metadata = this.findAutowiringMetadata(clazz.getName(), clazz, (PropertyValues)null);
​
        try {
            metadata.inject(bean, (String)null, (PropertyValues)null);
        } catch (BeanCreationException var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", var6);
        }
    }

3、BeanPostProcessor:作用于初始化阶段的前后,Spring AOP的实现原理就是从BeanPostProcessor接口postProcessBeforeInitialzation方法开始的。

下面是一段自定义注解的方式发送日志埋点的例子:

/**
     * 发送埋点数据
     * 调用次数类型指标
     */
    @After(value = "@annotation(com.iflytek.cosmo.guidance.annotation.CosmoCriusAnnotation)")
    public void doAfter(JoinPoint point) throws Throwable {
        logger.debug("CriusAspect doAfter begin");
        // 获取方法签名
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        CosmoCriusAnnotation criusAnnotation = targetMethod.getAnnotation(CosmoCriusAnnotation.class);
        //获取发送的指标
        String metric = criusAnnotation.criusMetric();
        CriusMetaData criusMetaData;
        try {
            if (CriusMetricConstant.WEBSOCKET.equals(criusAnnotation.metricType())) {
                Object[] obj = point.getArgs();
                WebSocketSession session = (WebSocketSession) obj[0];
                //转写开始时间埋点
                session.getAttributes().put(CriusMetricConstant.BEGINTIME, System.currentTimeMillis());
                //转写字数埋点
                session.getAttributes().put(CriusMetricConstant.TRANSLITERATIONWORDS, 0);
                criusMetaData = criusService.getCriusMetaDataBySession(session);
            } else {
                criusMetaData = criusService.getCriusMetaData();
            }
            //判断appid是自有还是第三方
            if (selfAppIdProperties.getSelfAppIds().contains(criusMetaData.getAppId())) {
                metric += ".self";
                //发送一次自有应用总调用次数
                criusService.sendDataToCrius(criusMetaData, CriusMetricConstant.BIZ_NL_SELF, 1);
            } else {
                metric += ".third";
                //发送一次第三方总调用次数
                criusService.sendDataToCrius(criusMetaData, CriusMetricConstant.BIZ_NL_THIRD, 1);
            }
            //发送对应能力的埋点数据
            criusService.sendDataToCrius(criusMetaData, metric, 1);
        } catch (Exception e) {
            logger.error("CriusAspect error:{}", e);
        }
    }

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值