栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

# SpringBoot 常用扩展点介绍、容器启动源码分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

# SpringBoot 常用扩展点介绍、容器启动源码分析

SpringBoot 常用扩展点介绍、容器启动源码分析 SpringApplication.run() 实例化一个SpringApplication

创建一个SpringApplication实例

public static ConfigurableApplicationContext run(Class[] primarySources, String[] args) {
    return new SpringApplication(primarySources).run(args);
}

SpringApplication构造方法:属性赋值

// 收集所有的容器初始化组件对象:解析 spring.factories 文件获取容器自定义组件
private List> initializers;

// 收集所有的监听器:扩展方式和上面的初始化组件方式差不多
private List> listeners;

总结

SpringApplication的构建都是为了run()方法启动做铺垫,构造方法中总共就有几行代码,最重要的部分就是设置应用类型、设置初始化器、设置监听器。 spring-boot自定义容器初始化组件 Demo 定义组件

实现ApplicationContextInitializer

public class CustomInitializer implements ApplicationContextInitializer {

    private static final Logger logger = LoggerFactory.getLogger(CustomInitializer.class);

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        logger.info("====================CustomInitializer start======================");
        logger.info("CustomInitializer initialize方法被执行...");
        logger.info("ApplicationName: {}", applicationContext.getApplicationName());
        logger.info("isActive: {}", applicationContext.isActive());
        logger.info("====================CustomInitializer end======================");
    }
}
配置容器组件

SpringBoot的SPI扩展 meta-INF下面 spring.factories配置自定义组件的位置

org.springframework.context.ApplicationContextInitializer=com.li.springbootproject.spring.initializer.CustomInitializer

add方式添加

@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MySpringBootApplication.class);
        application.addInitializers(new MyApplicationContextInitializer());
        application.run(args);
    }
}
总结

ApplicationContextInitializer 是 Spring 对外提供的扩展点之一,用于在 ApplicationContext 容器加载 Bean 之前对当前的上下文进行配置。重要的还是如何将这一组件和我们的具体业务相结合,实现我们具体的业务,这应该是需要思考的。 调用对象的 Run() Run() 方法流程

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
    	// 获取运行监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
    	// 启动运行监听器
		listeners.starting();
		try 
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 环境构建这一步加载了系统环境配置、用户自定义配置并且广播了ApplicationEnvironmentPreparedEvent事件,触发监听器。
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
            // 打印 Banner
			Banner printedBanner = printBanner(environment);
            // 依据是否为 web 环境创建 web 容器或者普通的 IOC 容器(只是创建) 见下面截图
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
            // IOC 容器的前置处理,为刷新容器之前做准备,关键操作(将启动类注入容器)
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// 刷新容器,完成组件的扫描,创建,加载等
            refreshContext(context);
    		//  IOC容器的后置处理
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

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

创建 BeanFactory
初始化完成之后就进到了run方法,run方法完成了所有Spring的整个启动过程:准备Environment——发布事件——创建上下文、bean——刷新上下文——结束
对比 ApplicationContext,ConfigurableApplicationContext提供了配置上下文的接口,如设置Environment、监听器、切面类、关闭上下文的钩子等。


容器启动过程中的 refreshContext() 源码refresh()
@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        // 告诉子类去刷新bean工厂,这步完成后配置文件就解析成一个个bean定义,注册到BeanFactory(但是未被初始化,仅将信息写到了beanDefination的map中)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        try {
             // 处理自定义的BeanFactoryPostProcess:允许BeanFactoryPostProcessor在容器实例化任何bean之前读取bean的定义(配置元数据)
            postProcessBeanFactory(beanFactory);
            //  调用BeanFactoryPostProcessor各个实现类的方法
            invokeBeanFactoryPostProcessors(beanFactory);
            
            // 注册 BeanPostProcessor 的实现类
            // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         	// 两个方法分别在 Bean 初始化之前和初始化之后得到执行。
            registerBeanPostProcessors(beanFactory);
            
            // 国际化
            initMessageSource();
            
            initApplicationEventMulticaster();
            onRefresh();
            registerListeners();
            
            // 实例化所有剩余的非懒加载单例 bean
            finishBeanFactoryInitialization(beanFactory);
            
            finishRefresh();
        }catch(Exception e){
            // ...
        }
    }
}
SpringBoot 容器 启动流程

常用技巧 初始化类的属性 @PostConstruct 初始化类变量

首先这个注解是由Java提供的,它用来修饰一个非静态的void方法。它会在服务器加载Servlet的时候运行,并且只运行一次。

它的作用在于声明一个Bean对象初始化完成后执行的方法。

Bean初始化中的执行顺序:

Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)

@Component
public class InitStaticVariableThree {

    private static final Logger logger = LoggerFactory.getLogger(InitStaticVariableThree.class);

    
    public static RedissonClient redissonClientOne;

    
    @Autowired
    private RedissonClient redissonClient;

    
    @PostConstruct
    public void init() {
        redissonClientOne = redissonClient;
        logger.info(String.valueOf(redissonClient));
        logger.info(String.valueOf(redissonClientOne));
    }

}

注册 Bean

除了注解、Java配置和XML配置的方式来创建Bean,还有另外一种方式来创建我们的BeanDefinition。通过 BeanDefinitionRegistryPostProcessor可以创建一个特别的后置处理器,来将BeanDefinition添加到BeanDefinitionRegistry中。BeanDefinition 是对 Bean 的定义,其保存了 Bean 的各种信息,如属性、构造方法参数、是否单例、是否延迟加载等。这里的注册 Bean 是指将 Bean 定义成 BeanDefinition,之后放入 容器中 BeanDefinitionRegistryPostProcessor

和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。这就跟类与类实例之间的区别类似。 执行时机

在Bean定义没有被加载,bean实例还没有被初始化时候。 使用

注册PersonBean:MyBeanDefinitionRegistryPostProcessor.java

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    private static final Logger logger = LoggerFactory.getLogger(MyBeanDefinitionRegistryPostProcessor.class);

    
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "MyBeanDefinitionRegistryPostProcessor 中的 postProcessBeanDefinitionRegistry 方法");
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "bean 定义的数据量:" + registry.getBeanDefinitionCount());
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(PersonBean.class);
        registry.registerBeanDefinition("personbean", rootBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "MyBeanDefinitionRegisterPostProcessor中的postProcessBeanFactory方法");
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "bean 定义的数据量:" + beanFactory.getBeanDefinitionCount());
    }
}

使用PersonBean:直接注入使用


实现 Bean 的初始化 实现InitializingBean

定义 Bean 实现 InitializingBean

public class InitializingBeanExample implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(InitializingBeanExample.class);

    private int id;

    private String name;

    @Override
    public void afterPropertiesSet() {
        logger.info(LogConst.LOG_SUCCESS_PREFIX + " 初始化前的值为:{}", this);
        logger.info(LogConst.LOG_SUCCESS_PREFIX + " 我要对 PeopleBean 进行初始化!");
        this.id = 100;
        this.name = "李四";
        logger.info(LogConst.LOG_SUCCESS_PREFIX + " 初始化后的值为:{}", this);
    }
}

注册 Bean

@Configuration
public class InitializingBeanExampleTest {

    private static final Logger logger = LoggerFactory.getLogger(InitializingBeanExampleTest.class);

    @Bean
    public InitializingBeanExample initializingBeanExample() {
        InitializingBeanExample initializingBeanExample = new InitializingBeanExample();
        initializingBeanExample.setId(1);
        initializingBeanExample.setName("test1");
        logger.info(LogConst.LOG_SUCCESS_PREFIX + initializingBeanExample);
        return initializingBeanExample;
    }
}
使用initMethod方法

定义 Bean

@Bean(initMethod = "initBean")
@Lazy
public InitMethodBean initMethodBean() {
    InitMethodBean initMethodBean = new InitMethodBean();
    logger.info(LogConst.LOG_SUCCESS_PREFIX + "实例化 InitMethodBean 信息为:" + initMethodBean);
    return initMethodBean;
}

定义 Bean的 inti-method 方法

public class InitMethodBean {

    private static final Logger logger = LoggerFactory.getLogger(InitMethodBean.class);

    private UUID id;

    private String name;

    private void initBean() {
        this.id = UUID.randomUUID();
        this.name = "InitMethodBean";
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "执行 InitMethodBean 的 initBean():" + this);
    }
    
    // ...
}
@PostConstruct

看前面的讲解 总结

初始化 Bean 的顺序

Constructor > @PostConstruct > InitializingBean > init-method


获取 Bean 修改 Bean 信息 实现 BeanPostProcessor 接口

实现BeanPostProcessor 接口,重写postProcessBeforeInitialization()、postProcessAfterInitialization(),在重写的方法中,可以获得Bean的属性,对Bean进行相关的操作。

@Component
public class UserBeanPostProcessor implements BeanPostProcessor {

    private static final Logger logger = Logger.getLogger(String.valueOf(UserBeanPostProcessor.class));

	// 在这里可以拿到bean的相关信息,进行相关操作
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        final String name = "myUser";
        if(name.equals(beanName)){
            User user = (User) bean;
            user.setName("李四");
            user.setDate(new Date());
            logger.info("=====> postProcessBeforeInitialization():"+ JSONObject.toJSONString(user));
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
执行时机

postProcessBeforeInitialization() 方法:在 Bean 实例化、属性注入后,初始化前调用。postProcessAfterInitialization() 方法:在 Bean 实例化、属性注入、初始化都完成后调用。


SpringBoot 启动后执行操作

springboot给我们提供了两种方式:ApplicationRunner和CommandLineRunner。

这两种方法提供的目的是为了满足,在项目启动的时候立刻执行某些方法。我们可以通过实现ApplicationRunner和CommandLineRunner,来实现,他们都是在SpringApplication 执行之后开始执行的。

Order 注解使用

在Spring容器启动后可以加载一些资源或者做一些业务操作实现 CommandLineRunner

@Component
@Order(1)
public class OrderTestOne implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(OrderTestOne.class);

    
    @Override
    public void run(String... args) throws Exception {
        logger.info("OrderTestOne...");
    }
}

order的值越小,优先级越高order如果不标注数字,默认最低优先级,因为其默认值是int最大值 实现 ApplicationRunner、Ordered 接口

@Component
public class OrderTestTwo implements ApplicationRunner, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(OrderTestTwo.class);

    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        logger.info("OrderTestTwo...");
    }

    
    @Override
    public int getOrder() {
        return 2;
    }
}

获取 ApplicationContext 容器 直接注入

直接在使用的地方注入使用

@Autowired
private ApplicationContext applicationContextBean;
实现ApplicationContextAware接口

实例代码SpringContextUtils,定义全局的获取上下文的工具类

@Component
public class SpringContextUtils implements ApplicationContextAware {
    
    private static final Logger logger = LoggerFactory.getLogger(SpringContextUtils.class);

    
    private static ApplicationContext applicationContext = null;


    private SpringContextUtils() {
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (Objects.isNull(SpringContextUtils.applicationContext)) {
            logger.info(LogConst.LOG_SUCCESS_PREFIX + "ApplicationUtils初始化...");
            SpringContextUtils.applicationContext = applicationContext;
        }
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "ApplicationUtils初始化成功!");
    }

    
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    
    @SuppressWarnings("all")
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    
    public static  T getBean(Class tClass) {
        return getApplicationContext().getBean(tClass);
    }
}
作为参数获取 ApplicationContext Bean

Spring在初始化AutoConfiguration时会自动传入ApplicationContext,这时我们就可以使用下面的方式来获取ApplicationContext:

@Configuration
public class TestConfig {

    private static final Logger logger = LoggerFactory.getLogger(TestConfig.class);

    
    public TestConfig(ApplicationContext applicationContext) {
        logger.info(String.valueOf(applicationContext));
    }
}
通过WebApplicationContextUtils获取

Spring提供了一个工具类用于获取ApplicationContext对象:

@Autowired
private ServletContext servletContext;

@Override
public String testSix() {
    WebApplicationContext context1 = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
    WebApplicationContext context2 = WebApplicationContextUtils.getWebApplicationContext(servletContext);
    return "测试成功!";
}

获取BeanFactory Spring中的Aware

Aware这个类主要是辅助Spring进行访问容器中的数据,在实现这个类重写的方法中,可以拿到相关组件的信息,从而可以进行相应的扩展。

常用的Aware实现类

BeanFactoryAware:获取BeanFactory容器BeanNameAware:获取Bean的名称ApplicationContextAware:获取ApplicationContext 得到 BeanFactory

实现BeanFactoryAware,在setXXX()中获得相关的Spring组件。

@Component
public class GetBeanFactory implements BeanFactoryAware {

    private static final Logger logger = LoggerFactory.getLogger(GetBeanFactory.class);

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        MyBeans bean = beanFactory.getBean(MyBeans.class);
        logger.info("-----> 获得当前的BeanFactory "+ beanFactory);
    }

}

FactoryBean、BeanFactoryPostProcessor 扩展

Mybatis 中 Mapper

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHUfeeFt-1647340618646)(images/image-20220313111913059.png)]

BeanFactoryPostProcessor是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。

FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

实现汽车装配引擎的过程

BeanProduct

@Configuration
public class BeanProduct {

    
    @Bean
    public SpecialBeanForEngine specialBeanForEngine() {
        return new SpecialBeanForEngine();
    }

    
    @Bean(initMethod = "start")
    public Car car(CarEngine carEngine) {
        Car car = new Car();
        car.setEngine(carEngine);
        return car;
    }

}

注册 EngineFactory 的 BeanDefine

public class SpecialBeanForEngine implements BeanFactoryPostProcessor, BeanNameAware {

    public String name;

    @Override
    public void setBeanName(String name) {
        this.name = name;
    }

    public class SpecialBeanForEngine implements BeanFactoryPostProcessor, BeanNameAware {

    public String name;

    @Override
    public void setBeanName(String name) {
        this.name = name;
    }

    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(EngineFactory.class);
        genericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
        genericBeanDefinition.setAutowireCandidate(true);
        beanDefinitionRegistry.registerBeanDefinition("engine007", genericBeanDefinition);
    }
}
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(EngineFactory.class);
        genericBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
        genericBeanDefinition.setAutowireCandidate(true);
        beanDefinitionRegistry.registerBeanDefinition("engine007",genericBeanDefinition);
    }
}

汽车 Bean 的配置

public class Car implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(Car.class);

    private String code = String.valueOf(UUID.randomUUID());

    
    private CarEngine engine;

    public Car() {
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "Car Constructor...");
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "Car engine not setting");
    }

    private void start() {
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "Car start...");
        engine.fire();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        logger.info("Car initializingBean after propertieSet");
        if (engine == null) {
            logger.info("Car's engine not setting, in initializingBean ");
        } else {
            logger.info("Car's engine installed, in initializingBean");
            // 使用接口方法
            engine.fire();
        }
    }

    @PostConstruct
    public void postConstruct() {
        logger.info("Car postConstruct");
        if (engine == null) {
            logger.info("Car engine not setting, in postConstruct");
        } else {
            logger.info("Car engine installed, in postConstruct");
        }
    }
}

需要代理的接口

public interface CarEngine {

    void fire();

    void close();
}

工厂Bean EngineFactory

public class EngineFactory implements FactoryBean, BeanNameAware, InvocationHandler {

    private static final Logger logger = LoggerFactory.getLogger(EngineFactory.class);

    private String name;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("fire".equalsIgnoreCase(method.getName())) {
            logger.info(LogConst.LOG_SUCCESS_PREFIX + "here is invoke  engine:" + method.getName());
        }
        if ("close".equalsIgnoreCase(method.getName())) {
            logger.info(LogConst.LOG_SUCCESS_PREFIX + "here is invoke  engine:" + method.getName());
        }
        return null;
    }

    @Override
    public void setBeanName(String name) {
        this.name = name;
    }

    
    @Override
    public CarEngine getObject() {
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "EngineFactory  to build Engine01 , EngineFactory :" + name);
        CarEngine carEngine = (CarEngine) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{CarEngine.class}, this);
        return carEngine;
    }

    @Override
    public Class getObjectType() {
        return CarEngine.class;
    }

    
    @Override
    public boolean isSingleton() {
        return true;
    }
}

测试代码

@Autowired
private CarEngine carEngine;

carEngine.fire();
carEngine.close();

执行结果

2022-03-12 20:04:25.508  INFO 12836 --- [           main] c.l.s.s.beanfactorypostprocessor.Car     : ==========> Car Constructor...
2022-03-12 20:04:25.508  INFO 12836 --- [           main] c.l.s.s.beanfactorypostprocessor.Car     : ==========> Car engine not setting
2022-03-12 20:04:25.509  INFO 12836 --- [           main] c.l.s.s.beanfactorypostprocessor.Car     : ==========> Car postConstruct
2022-03-12 20:04:25.509  INFO 12836 --- [           main] c.l.s.s.beanfactorypostprocessor.Car     : ==========> Car engine installed, in postConstruct
2022-03-12 20:04:25.509  INFO 12836 --- [           main] c.l.s.s.beanfactorypostprocessor.Car     : ==========> Car initializingBean after propertieSet
2022-03-12 20:04:25.509  INFO 12836 --- [           main] c.l.s.s.beanfactorypostprocessor.Car     : ==========> Car engine installed, in initializingBean
2022-03-12 20:04:25.509  INFO 12836 --- [           main] c.l.s.s.b.EngineFactory                  : ==========> here is invoke  engine:fire
2022-03-12 20:04:25.509  INFO 12836 --- [           main] c.l.s.s.beanfactorypostprocessor.Car     : ==========> Car start...
2022-03-12 20:04:25.509  INFO 12836 --- [           main] c.l.s.s.b.EngineFactory                  : ==========> here is invoke  engine:fire

SpringBoot Event事件同步、异步处理

场景:按照一定的顺序做一些事情,例如向A表插入数据事物提交之后,向B表中插入历史记录,最后向C表插入。 Spring 事件

在 Spring 中,初始化容器时会调用 org.springframework.context.ConfigurableApplicationContext 接口中的 reFresh() 方法进行 Bean的加载,该方法会进行事件的监听注册。

示例代码

定义事件

public class UserEvent extends ApplicationEvent {

    private T data;

    public UserEvent(T source) {
        super(source);
        this.data =source;
    }

    public T getData() {
        return this.data;
    }

    public void setData(final T data) {
        this.data = data;
    }
}

发布事件

@Autowired
private ApplicationEventPublisher publisher;


private void sendInsertUser() {
    User user = new User();
    user.setId(20210317);
    user.setUsername("测试张三");
    UserEvent userEvent = new UserEvent<>(user);
    // 发布事件
    publisher.publishEvent(userEvent);

}

监听用户插入的事件

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT,fallbackExecution = true)
public void insertUserLinster(UserEvent userEvent) {
    User data = userEvent.getData();
    String message = String.format("get user message: %s", JSON.toJSONString(data));
    log.info(message);
    // 后续操作;继续处理
}

SpringBoot 关机函数

实现 ExitCodeGenerator 接口,生成自己的退出代码

@Component
public class ExitCodeApplication implements ExitCodeGenerator {

    private static final Logger logger = LoggerFactory.getLogger(ExitCodeApplication.class);

    @Override
    public int getExitCode() {
        logger.info(LogConst.LOG_SUCCESS_PREFIX + "容器已经关机...");
        return 999;
    }
}

调用

@Autowired
private ApplicationContext applicationContext;

@RequestMapping("/close")
public void testFive(HttpServletRequest request, HttpServletResponse response) {
    SpringApplication.exit(applicationContext);
}

SpringBoot starter机制

SpringBoot 在启动时会去依赖的 starter 包中寻找 /meta-INF/spring.factories 文件,然后根据文件中配置的 Jar 包去扫描项目所依赖的 Jar 包,这类似于 Java 的 SPI 机制。

SpringBoot中的starter是一种非常重要的机制(自动化配置),能够抛弃以前繁杂的配置,将其统一集成进starter

生成配置文件

@Configuration
@ConditionalOnClass(StarterService.class)
@EnableConfigurationProperties(StarterServiceProperties.class)
public class StarterAutoConfigure {

    @Autowired
    private StarterServiceProperties properties;

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "example.service", value = "enabled", havingValue = "true")
    public StarterService starterService() {
        return new StarterService(properties.getConfig());
    }
}

resources下meta-INF的spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.li.StarterAutoConfigure

引入依赖


    com.li
    springboot-starter-demo
    1.0-SNAPSHOT

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768524.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号