欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

整理在Spring IOC容器初始化后可以处理特定逻辑的多种实现方式

程序员文章站 2022-06-22 10:38:04
Spring框架的核心是依赖注入、切面;Spring Boot是在Spring框架的基础上为其提供许多默认配置、默认约定(约定优于配置),从而达到减少或减化配置进而可开箱即用、快速上手;Spring Cloud又是在Spring Boot框架的基础上提供了大量的微服务体系内的各种组件(starter ......

  spring框架的核心是依赖注入、切面;spring boot是在spring框架的基础上为其提供许多默认配置、默认约定(约定优于配置),从而达到减少或减化配置进而可开箱即用、快速上手;spring cloud又是在spring boot框架的基础上提供了大量的微服务体系内的各种组件(starter),简化了微服务开发实现的成本;但不管是spring、spring boot、spring cloud的底层实现都是充分利用了ioc、aop;有时我们想在所有bean都成功注册到ioc容器后,并实例化完成后统一做一些初始化的工作,那么就需要捕获spring ioc容器初始化后的事件点,而这个事件点我结合自己经验及网上分享进行了一次整理汇总,主要是有如下几种方式(先后触发顺序):

  1. applicationcontextaware.setapplicationcontext
  2. bean 添加了@postconstruct的方法
  3. initializingbean.afterpropertiesset
  4. beanpostprocessor (postprocessbeforeinitialization、postprocessafterinitialization)
  5. smartlifecycle.start
  6. applicationlistener.onapplicationevent
  7. applicationrunner.run

 

下面是把如上的触发点都集中实现在一个bean中看效果,示例代码如下:

package cn.zuowenjun.demo.ioc.service;

import cn.zuowenjun.demo.ioc.mapper.demoinfomapper;
import org.springframework.aop.support.aoputils;
import org.springframework.beans.beansexception;
import org.springframework.beans.factory.initializingbean;
import org.springframework.beans.factory.config.beanpostprocessor;
import org.springframework.boot.applicationarguments;
import org.springframework.boot.applicationrunner;
import org.springframework.context.applicationcontext;
import org.springframework.context.applicationcontextaware;
import org.springframework.context.applicationlistener;
import org.springframework.context.smartlifecycle;
import org.springframework.context.event.contextrefreshedevent;
import org.springframework.stereotype.component;
import org.springframework.web.context.webapplicationcontext;

import javax.annotation.postconstruct;
import java.util.date;

@component
public class demomodescollection
        implements applicationcontextaware,
        applicationlistener<contextrefreshedevent>,
        applicationrunner,
        smartlifecycle,
        initializingbean,
        beanpostprocessor {

    private  applicationcontext context;


    @postconstruct
    public void postconstructmethod(){
        system.out.printf("%1$tf %1$tt.%1$tl --->@postconstruct postconstructmethod:running!%n",new date());
        demoinfomapper mapper= context.getbean(demoinfomapper.class);

        system.out.println("@postconstruct >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
    }

    @override
    public void afterpropertiesset() throws exception {
        system.out.printf("%1$tf %1$tt.%1$tl --->initializingbean.afterpropertiesset:running!%n",new date());
        demoinfomapper mapper= context.getbean(demoinfomapper.class);
        system.out.println("afterpropertiesset >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
    }

    @override
    public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception {
        system.out.printf("%1$tf %1$tt.%1$tl --->applicationcontextaware.setapplicationcontext:running! ===beanscount:%2$d %n",
                new date(), applicationcontext.getbeandefinitioncount());
        this.context=applicationcontext;
        demoinfomapper mapper= context.getbean(demoinfomapper.class);
        system.out.println("setapplicationcontext >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
    }

    @override
    public void onapplicationevent(contextrefreshedevent event) {

        if (event.getapplicationcontext().getparent() == null || event.getapplicationcontext() instanceof webapplicationcontext) {
            system.out.printf("%1$tf %1$tt.%1$tl --->applicationlistener.onapplicationevent:running! ===beanscount:%2$d  (beantype:%3$s) %n",
                    new date(), event.getapplicationcontext().getbeandefinitioncount(), event.getapplicationcontext().getclass().gettypename());

            demoinfomapper mapper= event.getapplicationcontext().getbean(demoinfomapper.class);
            system.out.println("onapplicationevent >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
        }
    }

    @override
    public void run(applicationarguments args) throws exception {
        system.out.printf("%1$tf %1$tt.%1$tl --->applicationrunner.run:running!%n", new date());
        demoinfomapper mapper= context.getbean(demoinfomapper.class);
        system.out.println("run >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
    }



    private boolean isrunning = false;

    @override
    public void start() {

        system.out.printf("%1$tf %1$tt.%1$tl --->smartlifecycle.start:running!%n",new date());

        isrunning=true;

        demoinfomapper mapper= context.getbean(demoinfomapper.class);
        system.out.println("start >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
    }

    @override
    public void stop() {
        isrunning = false;
    }

    @override
    public boolean isrunning() {
        return isrunning;
    }



    @override
    public object postprocessbeforeinitialization(object bean, string beanname) throws beansexception {
        system.out.printf("%1$tf %1$tt.%1$tl --->beanpostprocessor.postprocessbeforeinitialization:running!%n",new date());
        demoinfomapper mapper= context.getbean(demoinfomapper.class);
        system.out.println("postprocessbeforeinitialization >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
        return bean;
    }

    @override
    public object postprocessafterinitialization(object bean, string beanname) throws beansexception {
        system.out.printf("%1$tf %1$tt.%1$tl --->beanpostprocessor.postprocessafterinitialization:running!%n",new date());
        demoinfomapper mapper= context.getbean(demoinfomapper.class);
        system.out.println("postprocessafterinitialization >>>context.getbean:" + (mapper==null?"null":aoputils.gettargetclass(mapper).getname()));
        return bean;
    }
}

 如上代码,大家可将尝试其加入到一个spring boot项目中,就可以看到运行的效果(执行的顺序) ,比如我这里的输出如下:


2019-11-16 12:25:48.283 --->applicationcontextaware.setapplicationcontext:running! ===beanscount:325
setapplicationcontext >>>context.getbean:com.sun.proxy.$proxy84
2019-11-16 12:25:48.558 --->@postconstruct postconstructmethod:running!
@postconstruct >>>context.getbean:com.sun.proxy.$proxy84
2019-11-16 12:25:48.559 --->initializingbean.afterpropertiesset:running!
afterpropertiesset >>>context.getbean:com.sun.proxy.$proxy84
2019-11-16 12:25:48.567 --->beanpostprocessor.postprocessbeforeinitialization:running!
postprocessbeforeinitialization >>>context.getbean:com.sun.proxy.$proxy84
2019-11-16 12:25:48.567 --->beanpostprocessor.postprocessafterinitialization:running!
......有很多的beanpostprocessor.postprocessbeforeinitialization、beanpostprocessor.postprocessafterinitialization(每一个bean初始化前后都会触发,省略)
2019-11-16 12:25:50.045 --->smartlifecycle.start:running!
start >>>context.getbean:com.sun.proxy.$proxy84
2019-11-16 12:25:50.053 --->applicationlistener.onapplicationevent:running! ===beanscount:325 (beantype:org.springframework.boot.web.servlet.context.annotationconfigservletwebserverapplicationcontext)
onapplicationevent >>>context.getbean:com.sun.proxy.$proxy84
2019-11-16 12:25:50.080 --->applicationrunner.run:running!
run >>>context.getbean:com.sun.proxy.$proxy84

从输出结果我们可以看出整个的顺序,那么也得出结论最好是在:smartlifecycle.start、applicationlistener.onapplicationevent、applicationrunner.run 这三种实现方式中才能真正达到ioc初始后全部完成后触发的事件点的要求。

注:如果需要在控制台直接看到上面的内容,建议调整spring root的log level,避免无效的日志输出影响观看,配置如:

logging.level.root=error