spring boot启动参数及自定义事件配置的几种方法

spring boot启动停止服务的配置

spring boot构建的项目,开发完成后通常配置文件会自动打包在项目中,尽管我们启动项目时可以通过–spring.config.location参数设置读取application.xml或者application.yml文件的位置,但我们还是希望项目启动时可以自动从某些路径读取配置文件。

如果我们用spring boot构建web项目,尽管程序会自动将http服务自动启动,可默认情况下,项目的启动停止只对http服务有效。当我们的项目需要添加其他服务或监听(如tcp服务、webservice服务)时,项目默认的启动停止无法对其他服务生效。

有什么方法能够让我们的spring boot项目在启动停止时,让我们可以指定一些其他操作呢,下面介绍三种实现方法。

main方法中添加监听方法和启动参数

spring boot启动时,我们可以在启动方法SpringApplicationd的run方法执行前,设置启动参数或添加自定义的监听程序。代码案例如下,其中getFilePath()方法是启动类中的私有方法;GramServiceListener类为自己编写的服务监听类(需要实现 org.springframework.context.ApplicationListener接口),可根据实际需要自己编写修改该类。

public static void main(String[] args) throws IOException  {
	Properties properties = new Properties();
	String path = getFilePath();//获取文件路径方法
	//InputStream in = Runner.class.getClassLoader().getResourceAsStream("C:/Users/Administrator/cwht_dir/batchproject/batchConf.properties");
	InputStream in = new FileInputStream(new File(path));
	properties.load(in);
	SpringApplication app = new SpringApplication(Runner.class);
	app.setDefaultProperties(properties);
	app.addListeners(new GramServiceListener());
	app.run(args);
	in.close();
}

GramServiceListener类内容如下

@Override
public void onApplicationEvent(ApplicationEvent event) {
	// TODO Auto-generated method stub
	if (event instanceof ApplicationEnvironmentPreparedEvent){ // 初始化环境变量 
		logger.info("\n\n-======初始化环境变量 ");
	}else if (event instanceof ApplicationPreparedEvent){ // 初始化完成 
		logger.info("\n\n======初始化完成 ");
	} else if (event instanceof ContextRefreshedEvent) { // 应用刷新 }
		logger.info("\n\n=======应用刷新 ");
	}else if (event instanceof ApplicationStartingEvent ) {// 应用已启动完成}
		logger.info("\n\n=======应用已启动完成");
	}else if (event instanceof ContextStartedEvent) { //应用启动,需要在代码动态添加监听器才可捕获 }
		logger.info("\n\n=======应用启动,需要在代码动态添加监听器才可捕获");
	}else if (event instanceof ContextStoppedEvent) { // 应用停止 }
		 logger.info("\n\n=======应用停止");
	}else if(event instanceof ContextClosedEvent) { // 应用关闭 }
		logger.info("\n\n=======应用关闭");
	}
}

实现CommandLineRunner

该方法与对SpringApplication对象添加自定义监听类的效果是一样的。
使用该方法需要我们在spring boot项目的启动类中实现org.springframework.boot.CommandLineRunner接口;同时需要我们在启动类中编写监听方法,并需要为自定义的监听方法添加注解 @EventListener 且方法必须为无返回的公用方法(public void修饰)
以下为案例

public class Application implements CommandLineRunner{
	
	private static Logger logger = LoggerFactory.getLogger(Application.class);

	/**
	 * 描述 : 程序启动入口
	 * @param args
	 * @return void
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		SpringApplication.run(Application.class,args);
	}

	
	@EventListener
	public void eventApplicationListener(ApplicationEvent applicationEvent) throws Exception{
		if(applicationEvent instanceof ApplicationReadyEvent){
			logger.info("~~~~~~~正在启动服务~~~~~~~~~");
			server.start(port);
		}else if(applicationEvent instanceof ContextClosedEvent){
			logger.info("~~~~~~~正在关闭服务~~~~~~~~~");
			
		}
	}

	@Override
	public void run(String... strings) throws Exception {
		
	}
}

注意:由于CommandLineRunner接口中存在run方法,故启动类中必须重新实现run方法;否则spring boot项目无法正常启动

自定义spring boot的执行器Actuator

该方法需要项目导入Actuator插件(spring-boot-starter-actuator),且由于该方法采用自定义执行器的方式,在spring boot运行的生命流程中,执行我们自己定义的执行器中的相关内容,故可能造成项目运行故障。同时,使用该方式修改,需要编写代码更多,且需要注解的配合或其他插件。故不建议采用该方式实现功能
注意:本文中的执行器基于spring boot 1.5;spring boot 2.0以后已经对执行器进行了升级修改,变化较大,修改时请参考官方文档
我们以执行器插件中停止spring boot服务的执行器ShutdownEndpoint相关的代码为例

1. ShutdownEndpoint

import java.util.Collections;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;

@ConfigurationProperties(prefix="endpoints.shutdown")
public class ShutdownEndpoint
  extends AbstractEndpoint<Map<String, Object>>
  implements ApplicationContextAware
{
  private static final Map<String, Object> NO_CONTEXT_MESSAGE = Collections.unmodifiableMap(Collections.singletonMap("message", "No context to shutdown."));
  private static final Map<String, Object> SHUTDOWN_MESSAGE = Collections.unmodifiableMap(Collections.singletonMap("message", "Shutting down, bye..."));
  private ConfigurableApplicationContext context;
  
  public ShutdownEndpoint()
  {
    super("shutdown", true, false);
  }
  
  public Map<String, Object> invoke()
  {
    if (this.context == null) {
      return NO_CONTEXT_MESSAGE;
    }
    try
    {
      Thread thread;
      return SHUTDOWN_MESSAGE;
    }
    finally
    {
      Thread thread = new Thread(new Runnable()
      {
        public void run()
        {
          try
          {
            Thread.sleep(500L);
          }
          catch (InterruptedException ex)
          {
            Thread.currentThread().interrupt();
          }
          ShutdownEndpoint.this.context.close();
        }
      });
      thread.setContextClassLoader(getClass().getClassLoader());
      thread.start();
    }
  }
  
  public void setApplicationContext(ApplicationContext context)
    throws BeansException
  {
    if ((context instanceof ConfigurableApplicationContext)) {
      this.context = ((ConfigurableApplicationContext)context);
    }
  }
}

2. ShutdownMvcEndpoint

import java.util.Collections;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@ConfigurationProperties(prefix="endpoints.shutdown")
public class ShutdownMvcEndpoint
 extends EndpointMvcAdapter
{
 public ShutdownMvcEndpoint(ShutdownEndpoint delegate)
 {
   super(delegate);
 }
 
 @PostMapping(produces={"application/vnd.spring-boot.actuator.v1+json", "application/json"})
 @ResponseBody
 public Object invoke()
 {
   if (!getDelegate().isEnabled()) {
     return new ResponseEntity(
       Collections.singletonMap("message", "This endpoint is disabled"), HttpStatus.NOT_FOUND);
   }
   return super.invoke();
 }
}

3. Endpoint的相关配置

在EndpointWebMvcManagementContextConfiguration类中有各种状态检查的配置,其中与停止服务相关的配置如下

import org.springframework.boot.actuate.autoconfigure.EndpointCorsProperties;
import org.springframework.boot.actuate.autoconfigure.HealthMvcEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration;
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@ManagementContextConfiguration
@EnableConfigurationProperties({HealthMvcEndpointProperties.class, EndpointCorsProperties.class})
public class EndpointWebMvcManagementContextConfiguration
{
  
  @Bean
  @ConditionalOnMissingBean
  @ConditionalOnBean({ShutdownEndpoint.class})
  @ConditionalOnEnabledEndpoint(value="shutdown", enabledByDefault=false)
  public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate)
  {
    return new ShutdownMvcEndpoint(delegate);
  }
 
}

自定义的执行器可参考shutdown执行器代码,自己添加相应配置即可

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值