Skip to content

Latest commit

 

History

History
186 lines (131 loc) · 5.99 KB

Spring-容器的生命周期.md

File metadata and controls

186 lines (131 loc) · 5.99 KB

Spring 容器的生命周期

了解Spring 容器的生命周期,我们可以在容器生命周期的各个阶段执行自定义的操作以拓展应用程序的能力。本片博客的所有源代码,可以在 boot-init 仓库找到。有兴趣的自行查阅。



测试日志


2019-09-02 22:47:43.015  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
2019-09-02 22:47:43.101  INFO 61026 --- [           main] com.rainstorm.boot.skyLog                : [ApplicationInit][initialize][][] - ; message: 初始化方法调用
2019-09-02 22:47:43.102  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : org.springframework.boot.context.event.ApplicationContextInitializedEvent

...

2019-09-02 22:47:43.149  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : org.springframework.boot.context.event.ApplicationPreparedEvent

...

2019-09-02 22:47:49.036  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : me.rainstorm.boot.lifecycle.application.JacksonConverterConfigDoneEvent

...

2019-09-02 22:47:50.041  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : org.springframework.context.event.ContextRefreshedEvent

...

2019-09-02 22:47:50.061  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent

2019-09-02 22:47:50.065  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : org.springframework.boot.context.event.ApplicationStartedEvent
2019-09-02 22:47:50.076  INFO 61026 --- [           main] m.r.b.l.a.ApplicationEventTest           : org.springframework.boot.context.event.ApplicationReadyEvent

...

2019-09-02 22:50:41.951  INFO 61026 --- [       Thread-1] m.r.b.l.application.ApplicationInit      : from shutdown hook
2019-09-02 22:50:41.951  INFO 61026 --- [      Thread-18] m.r.b.l.a.ApplicationEventTest           : org.springframework.context.event.ContextClosedEvent

整体流程图

// todo 周末再搞吧

生命周期事件

Spring经典生命周期事件

Spring Context event

// todo 详情周末搞

Spring boot 生命周期事件

Spring boot application event

// todo 详情周末搞

自定义的应用程序事件

// todo 事件的发布订阅模式

借助 ApplicationContext 实现自定义事件发布与监听

监听器事件

@Slf4j
@Component
public class EventPublisherImpl implements ApplicationContextAware, ApplicationEventPublisher {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void publishEvent(Object event) {
        applicationContext.publishEvent(event);
    }
}

自定义事件

public class JacksonConverterConfigDoneEvent extends ApplicationEvent {
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public JacksonConverterConfigDoneEvent(Object source) {
        super(source);
    }
}

发布事件

@Configuration
public class JacksonConverter {

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();

        ....

        eventPublisher.publishEvent(new JacksonConverterConfigDoneEvent(objectMapper));

        return objectMapper;
    }

初始化器

@Slf4j
public class ApplicationInit implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    private static final String CATEGORY = ApplicationInit.class.getSimpleName();

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        final String logMethodName = "initialize";

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("from shutdown hook");
        }));

        LogUtil.info(LogBuilder.init(CATEGORY, logMethodName).setMessage("初始化方法调用").build());
    }
}

JVM shutdownHook

注册 ShutdownHook

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    log.info("from shutdown hook");
}));

注意,因为 ShutdownHook 底层使用Map 作为存储结构,且是多线程并发执行,无法精确的指定执行的先后顺序,除非显示的对 Shutdown hook 进行同步处理

static void runHooks() {
    Collection<Thread> threads;
    synchronized(ApplicationShutdownHooks.class) {
        threads = hooks.keySet();
        hooks = null;
    }

    for (Thread hook : threads) {
        hook.start();
    }
    for (Thread hook : threads) {
        while (true) {
            try {
                hook.join();
                break;
            } catch (InterruptedException ignored) {
            }
        }
    }
}