Springboot 启动自定义初始化方式


前言

采用springboot 搭建项目时,有时候可能需要在项目启动后自动加载一些数据 ,那么我们可以采取一下几种方式来帮我们实现这个功能:
Springboot: ApplicationRunner 与 CommandLineRunner 接口
Spring容器初始化时 实现InitializingBean接口和@PostConstruct方法
Spring的ApplicationListener


提示:以下是本篇文章正文内容,下面案例可供参考

一、Springboot 接口:ApplicationRunner 与 CommandLineRunner

我们从springboot启动开始,一步步调用来查看相关的代码实现

SpringApplication.run(MyApplication.class, args) -> 
SpringApplication run(Object source, String... args) ->
SpringApplication run(Object[] sources, String[] args) ->
SpringApplication run(String... args) ->
SpringApplication afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) -> 
SpringApplication callRunners(ApplicationContext context, ApplicationArguments args)

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList();
		//获取spring容器下所有实现ApplicationRunner接口的类加入runners容器中 
       runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		//获取spring容器下所有实现CommandLineRunner接口的类加入runners容器中 
       runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        Iterator var4 = (new LinkedHashSet(runners)).iterator();

        while(var4.hasNext()) {
            Object runner = var4.next();
            if (runner instanceof ApplicationRunner) {
            	//ApplicationRunner接口调用
                this.callRunner((ApplicationRunner)runner, args);
            }

            if (runner instanceof CommandLineRunner) {
            	//CommandLineRunner接口调用
                this.callRunner((CommandLineRunner)runner, args);
            }
        }

    }

好啦,调用过程已经清楚了,那我们写个简单例子来测试下

@Component
public class ApplicationRunnerTest implements ApplicationRunner {
	@Override
	public void run(ApplicationArguments applicationArguments) throws Exception {
		System.out.println("ApplicationRunnerTest ----- only for test");
	}
}

二、PostConstructor 和 InitializingBean

代码如下(示例):
在bean初始化的时候,如果bean实现了 InitializingBean 接口,那么在初始化之后会调用afterPropertiesSet().同样我们也从springboot启动流程来看。

SpringApplication.run(MyApplication.class, args) -> 
SpringApplication run(Object source, String... args) ->
SpringApplication run(Object[] sources, String[] args) ->
SpringApplication run(String... args) ->
SpringApplication refreshContext(ConfigurableApplicationContext context) ->
SpringApplication refresh(ApplicationContext applicationContext) -> 
EmbeddedWebApplicationContext refresh() -> 
AbstractApplicationContext refresh() ->
AbstractApplicationContext finishBeanFactoryInitialization() ->
DefaultListableBeanFactory preInstantiateSingletons() -> 
AbstractBeanFactory getBean(String name) ->
AbstractBeanFactory doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
DefaultSingletonBeanRegistry getSingleton(String beanName, ObjectFactory<?> singletonFactory) ->
AbstractAutowireCapableBeanFactory createBean(String beanName, RootBeanDefinition mbd, Object[] args) -> 
AbstractAutowireCapableBeanFactory doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) ->
AbstractAutowireCapableBeanFactory initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)

//经过坎坷的调用过程,终于来到主题了
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    AbstractAutowireCapableBeanFactory.this.invokeAwareMethods(beanName, bean);
                    return null;
                }
            }, this.getAccessControlContext());
        } else {
            //调用实现Aware接口的方法, 这不是这次的重点忽略
            this.invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
        	//BeforeInitialization 调用beanPostProcessor 的方法
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
        	//调用init方法          
        	this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }

        if (mbd == null || !mbd.isSynthetic()) {
        	//AfterInitialization 调用beanPostProcessor 的方法
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

先看看applyBeanPostProcessorsBeforeInitialization的方法

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        //获取所有实现BeanPostProcessor接口的类
        Iterator var4 = this.getBeanPostProcessors().iterator();

        do {
            if (!var4.hasNext()) {
                return result;
            }

            BeanPostProcessor beanProcessor = (BeanPostProcessor)var4.next();
            //调用postProcessBeforeInitialization方法
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        } while(result != null);

        return result;
    }

这里主要来看CommonAnnotationBeanPostProcessor

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
	//CommonAnnotationBeanPostProcessor是继承自InitDestroyAnnotationBeanPostProcessor 
    public CommonAnnotationBeanPostProcessor() {
        this.setOrder(2147483644);
        //构造函数:这里将AnnotationType设置为PostConstructor类;
        this.setInitAnnotationType(PostConstruct.class);
        this.setDestroyAnnotationType(PreDestroy.class);
        this.ignoreResourceType("javax.xml.ws.WebServiceContext");
    }

由于CommonAnnotationBeanPostProcessor没有实现postProcessBeforeInitialization,那么我们得查看它的父类:InitDestroyAnnotationBeanPostProcessor

  InitDestroyAnnotationBeanPostProcessor postProcessBeforeInitialization(Object bean, String beanName) ->
   InitDestroyAnnotationBeanPostProcessor findLifecycleMetadata(Class<?> clazz) ->
 InitDestroyAnnotationBeanPostProcessor buildLifecycleMetadata(final Class<?> clazz)
   
    private InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        final boolean debug = this.logger.isDebugEnabled();
        LinkedList<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethods = new LinkedList();
        LinkedList<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> destroyMethods = new LinkedList();
        Class targetClass = clazz;

        do {
            final LinkedList<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currInitMethods = new LinkedList();
            final LinkedList<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> currDestroyMethods = new LinkedList();
            ReflectionUtils.doWithLocalMethods(targetClass, new MethodCallback() {
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                	//判断initAnnotationType是否为空,之前CommonAnnotationBeanPostProcessor的构造函数中已经将initAnnotationType设置为PostConstructor。也就是判断方法上是否有PostConstructor注解
                    if (InitDestroyAnnotationBeanPostProcessor.this.initAnnotationType != null && method.getAnnotation(InitDestroyAnnotationBeanPostProcessor.this.initAnnotationType) != null) {
                        InitDestroyAnnotationBeanPostProcessor.LifecycleElement element = new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method);
                        //方法上有PostConstructor注解则就将方法添加进LifecycleMetadata
                        currInitMethods.add(element);
                        if (debug) {
                            InitDestroyAnnotationBeanPostProcessor.this.logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
                        }
                    }

                    if (InitDestroyAnnotationBeanPostProcessor.this.destroyAnnotationType != null && method.getAnnotation(InitDestroyAnnotationBeanPostProcessor.this.destroyAnnotationType) != null) {
                        currDestroyMethods.add(new InitDestroyAnnotationBeanPostProcessor.LifecycleElement(method));
                        if (debug) {
                            InitDestroyAnnotationBeanPostProcessor.this.logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
                        }
                    }

                }
            });
            initMethods.addAll(0, currInitMethods);
            destroyMethods.addAll(currDestroyMethods);
            targetClass = targetClass.getSuperclass();
        } while(targetClass != null && targetClass != Object.class);

        return new InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata(clazz, initMethods, destroyMethods);
    }
        public void invokeInitMethods(Object target, String beanName) throws Throwable {
            Collection<InitDestroyAnnotationBeanPostProcessor.LifecycleElement> initMethodsToIterate = this.checkedInitMethods != null ? this.checkedInitMethods : this.initMethods;
            if (!((Collection)initMethodsToIterate).isEmpty()) {
                boolean debug = InitDestroyAnnotationBeanPostProcessor.this.logger.isDebugEnabled();

                InitDestroyAnnotationBeanPostProcessor.LifecycleElement element;
                //获取到注解上有PostConstructor的方法,在这里invoke(反射调用)
                for(Iterator var5 = ((Collection)initMethodsToIterate).iterator(); var5.hasNext(); element.invoke(target)) {
                    element = (InitDestroyAnnotationBeanPostProcessor.LifecycleElement)var5.next();
                    if (debug) {
                        InitDestroyAnnotationBeanPostProcessor.this.logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
                    }
                }
            }

        }

好啦,调用过程已经清楚了,那我们写个简单例子来测试下

@Component
public class PostConstructorTest {

	@PostConstruct
	public void postConstrctorTest(){
		System.out.println("postConstrctorTest ----- only for test");
	}
}

接下来我们看看InitializingBean的调用过程

    protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
        boolean isInitializingBean = bean instanceof InitializingBean;
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }

            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        public Object run() throws Exception {
                            ((InitializingBean)bean).afterPropertiesSet();
                            return null;
                        }
                    }, this.getAccessControlContext());
                } catch (PrivilegedActionException var6) {
                    throw var6.getException();
                }
            } else {
            	//InitializingBean调用,是不是很简单,直接就调用afterPropertiesSet,没有任何反射过程
                ((InitializingBean)bean).afterPropertiesSet();
            }
        }

        if (mbd != null) {
            String initMethodName = mbd.getInitMethodName();
            if (initMethodName != null && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
                this.invokeCustomInitMethod(beanName, bean, mbd);
            }
        }

    }

三、Spring的ApplicationListener

在spring 容器中,实际上有许多事件例如ContextStartedEvent, ContextStoppedEvent, ContextRefreshedEvent,ContextClosedEvent。甚至我们自己也可以自定义事件,这里我们只对ContextRefreshedEvent进行分析。


首先当然是查看监听器获取的过程。
SpringApplication.run(MyApplication.class, args) -> 
SpringApplication run(Object source, String... args) ->
SpringApplication run(Object[] sources, String[] args) ->
SpringApplication run(String... args) ->
SpringApplication refreshContext(ConfigurableApplicationContext context) ->
SpringApplication refresh(ApplicationContext applicationContext) -> 
EmbeddedWebApplicationContext refresh() -> 
AbstractApplicationContext refresh() ->
AbstractApplicationContext registerListeners()

protected void registerListeners() {
        Iterator var1 = this.getApplicationListeners().iterator();

        while(var1.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var1.next();
            this.getApplicationEventMulticaster().addApplicationListener(listener);
        }
		//从容器中获取所有实现ApplicationListener接口的类
        String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
        String[] var7 = listenerBeanNames;
        int var3 = listenerBeanNames.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String listenerBeanName = var7[var4];
            //将所有ApplicationListener加入 AbstractApplicationEventMulticaster 类中容器,以便以后的调用
            this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            Iterator var9 = earlyEventsToProcess.iterator();

            while(var9.hasNext()) {
                ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
                this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }

    }

接下来查看spring如何发布ContextRefresh事件

SpringApplication.run(MyApplication.class, args) -> 
SpringApplication run(Object source, String... args) ->
SpringApplication run(Object[] sources, String[] args) ->
SpringApplication run(String... args) ->
SpringApplication refreshContext(ConfigurableApplicationContext context) ->
SpringApplication refresh(ApplicationContext applicationContext) -> 
EmbeddedWebApplicationContext refresh() -> 
AbstractApplicationContext refresh() ->
AbstractApplicationContext finishRefresh() ->
AbstractApplicationContext publishEvent(ApplicationEvent event) ->
AbstractApplicationContext publishEvent(Object event, ResolvableType eventType) ->
SimpleApplicationEventMulticaster multicastEvent(final ApplicationEvent event, ResolvableType eventType) -> 
SimpleApplicationEventMulticaster invokeListener(ApplicationListener listener, ApplicationEvent event)

    protected void finishRefresh() {
        this.initLifecycleProcessor();
        this.getLifecycleProcessor().onRefresh();
        //这里传入的事件是ContextRefreshedEvent
        this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
        LiveBeansView.registerApplicationContext(this);
    }
    
	//终于来到了最终方法调用, listener 在之前已经注入到AbstractApplicationEventMulticaster类中容器
    protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
                listener.onApplicationEvent(event);
            } catch (Throwable var6) {
                errorHandler.handleError(var6);
            }
        } else {
            try {
                //调用onApplicationEvent方法
                listener.onApplicationEvent(event);
            } catch (ClassCastException var5) {
                LogFactory.getLog(this.getClass()).debug("Non-matching event type for listener: " + listener, var5);
            }
        }

    }

有两种方法可以创建监听者,一种是直接实现ApplicationListener的接口,一种是使用注解 @EventListener ,取其中一种来试试水。

@Component
public class ApplicationListenerTest {

	@EventListener
	public void onApplicationEvent(ContextRefreshedEvent event){
		System.out.println("ApplicationListenerTest ----- only for test");
	}
}

总结

最终我们测试出结果顺序如下
afterPropertiesSet ----- only for test
postConstrctorTest ----- only for test
ApplicationListenerTest ----- only for test
ApplicationRunnerTest ----- only for test
如此看来,springboot 的启动流程是不是也十分简单~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值