SpringBoot集成Socket服务后打包(war包)启动时如何启动Socket服务(web应用外部tomcat启动)
//jar包启动入口
@SpringBootApplication
public class HelloWorldApplcation { public static void main(String[] args) {
SpringApplication.run(HelloWorldApplcation.class, args);
} }
②、war包通常使用Tomcat进行部署启动,在tomcat启动war应用时,会先进行Servlet环境的初始化,之后才会进行到IOC容器的初始化,也就是说,在servlet初始化过程中是不能使用IOC依赖注入的。
public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(HelloWorldApplcation.class);
    }
}
@SpringBootApplication
public class HelloWorldApplcation { public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(HelloWorldApplcation.class, args);
SocketServer socketServer =applicationContext.getBean(SocketServer.class);
socketServer.start();
} }
2.2、war包情况下,由于是先进行Servlet环境的初始化,然后再进行IOC容器的创建,有了这个先后顺序,即知道,是不可能在Servlet创建时拿到WebApplicationContext对象的,下面是我的验证
package com.geniuses.sewage_zero_straight.listener; import com.geniuses.sewage_zero_straight.net.socket.SocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener; @Slf4j
@WebListener
public class SocketListener implements ServletContextListener { @Autowired
private SocketServer socketServer; @Override
public void contextInitialized(ServletContextEvent sce) { log.info("准备启动Socket服务...");
log.info("SocketServer:{}", socketServer);
socketServer.start();
} @Override
public void contextDestroyed(ServletContextEvent sce) { }
}

package com.geniuses.sewage_zero_straight.config; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes; @Slf4j
@HandlesTypes({WebApplicationInitializer.class})
public class SocketConfig implements WebApplicationInitializer { @Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
log.info("application: {}", webApplicationContext);
//log.info("SocketServer: {}", webApplicationContext.getBean(SocketServer.class));
}
}

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package org.springframework.boot.web.servlet.support; import java.util.Collections;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.ParentContextApplicationContextInitializer;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.Assert;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ConfigurableWebEnvironment;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext; public abstract class SpringBootServletInitializer implements WebApplicationInitializer {
protected Log logger;
private boolean registerErrorPageFilter = true; public SpringBootServletInitializer() {
} protected final void setRegisterErrorPageFilter(boolean registerErrorPageFilter) {
this.registerErrorPageFilter = registerErrorPageFilter;
} public void onStartup(ServletContext servletContext) throws ServletException {
this.logger = LogFactory.getLog(this.getClass());
//这里开始创建IOC容器
WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
if (rootAppContext != null) {
servletContext.addListener(new ContextLoaderListener(rootAppContext) {
public void contextInitialized(ServletContextEvent event) {
}
});
} else {
this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
} } //IOC容器创建方法
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
SpringApplicationBuilder builder = this.createSpringApplicationBuilder();
builder.main(this.getClass());
ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext);
if (parent != null) {
this.logger.info("Root context already created (using as parent).");
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null);
builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)});
} builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)});
builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
builder = this.configure(builder);
builder.listeners(new ApplicationListener[]{new SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)});
SpringApplication application = builder.build();
if (application.getAllSources().isEmpty() && AnnotationUtils.findAnnotation(this.getClass(), Configuration.class) != null) {
application.addPrimarySources(Collections.singleton(this.getClass()));
} Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation");
if (this.registerErrorPageFilter) {
application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
}
return this.run(application);
} protected WebApplicationContext run(SpringApplication application) {
return (WebApplicationContext)application.run(new String[0]);
} }
}
这个时候我想到,如果不将SocketServer交由IOC进行管理,那么可以在实现的WebApplicationInitializer自定义类中启动SocketServer
package com.geniuses.sewage_zero_straight.config; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes; /**
*
*/
@Slf4j
@HandlesTypes({WebApplicationInitializer.class})
public class SocketConfig implements WebApplicationInitializer { @Override
public void onStartup(ServletContext servletContext) throws ServletException {
new Thread(new SocketRunnable(new SocketServer())).start();
}
}
这里为什么要用一个新的线程来启动Socket服务,因为SocketServer服务端的实现中,使用while循环进行等待客户端socket进行连接,启动时便开始等待(阻塞),如果不使用一个新的线程启动,那么整个war应用服务启动线程便会在此处阻塞。这样虽然可以解决Socket服务随着应用启动而启动,但是又出现了一个新的问题,那就是SocketServer无法使用@Autowired了,因为SocketServer没有被IOC进行管理,无法进行依赖的注入。如果你不需要依赖,那么此法可行。
然后我又开始思考了,如果我需要进行依赖注入,由IOC进行SocketServer的管理,那么我要怎么样才能获取到WebApplicationContext对象,然后再通过该对象拿到SocketServer实例,然后再启动Socket服务。如果我继承了SpringBootServletInitializer,并重写onStartup方法,再重写的onStartup方法中进行Socket服务的启动会怎么样,最后发现Socket服务启动了,但是进行了两次onStartup方法的调用,第一次是自定义的SpringBootServletInitializer的实现类,第二次便是SpringBootServletInitializer类。即便只会启动一次,这样的代码也具有着极强的侵入性,便放弃了。
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
this.logger = LogFactory.getLog(this.getClass());
//这里开始创建IOC容器
WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
//在这里进行启动Socket服务
new Thread(new SocketRunnable(rootAppContext.getBean(SocketServer.class))).start();
if (rootAppContext != null) {
servletContext.addListener(new ContextLoaderListener(rootAppContext) {
public void contextInitialized(ServletContextEvent event) {
}
});
} else {
this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
} }
package com.geniuses.sewage_zero_straight.listener; import com.geniuses.sewage_zero_straight.net.socket.SocketServer;
import com.geniuses.sewage_zero_straight.net.socket.SocketThread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener; @Slf4j
@WebListener
public class MyContextLoaderListener extends ContextLoaderListener { @Override
public void contextInitialized(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
log.info("webApplicationContext:{}",webApplicationContext);
SocketThread socketThread = webApplicationContext.getBean(SocketThread.class);
servletContext.setAttribute("SocketThread", socketThread);//在这里放进去之后......,好像也没有必要放,可以从WebApplicationContext中获取...
log.info("socketThread:{}", socketThread);
socketThread.start();
}
}

在这里由SocketThread实现InitializingBean,实现afterPropertiesSet,这样,在该类的依赖注入完毕之后,会自动调用afterPropertiesSet方法,这样便可以在这里启动socket服务。关于InitializingBean的介绍,参见上面的这个链接。
package com.geniuses.sewage_zero_straight.net.socket; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Slf4j
@Component
public class SocketThread extends Thread implements InitializingBean { @Autowired
private SocketServer socketServer; @Override
public void run() {
log.info("当前线程名:{}", Thread.currentThread().getName());
log.info("由当前线程开始启动Socket服务...");
socketServer.start();
} @Override
public void afterPropertiesSet() throws Exception {
start();
}
}

SpringBoot集成Socket服务后打包(war包)启动时如何启动Socket服务(web应用外部tomcat启动)的更多相关文章
- 持续集成之Jenkins自动部署war包到远程服务器
		
一.无war包链接的情况 无war包链接时,需先下载war包到本地,然后执行: ---------------------------------------------以下部分为转载-------- ...
 - 【Maven】项目打包-war包-Jar包[IDEA将项目打成war包]
		
[Maven]项目打包-war包-Jar包[IDEA将项目打成war包] 2017年01月31日 00:21:06 阅读数:22912 标签: ideamaven发布博客插件 更多 个人分类: ❷ J ...
 - SpringBoot小技巧:Jar包换War包
		
SpringBoot小技巧:Jar包换War包 情景 我们都知道springBoot中已经内置了tomcat,是不需要我们额外的配置tomcat服务器的,但是有时这也可能是我们的一个瓶颈,因为如果我们 ...
 - springboot 集成swagger2.x 后静态资源报404
		
package com.bgs360.configuration; import org.springframework.context.EnvironmentAware; import org.sp ...
 - SpringBoot集成Swagger2并配置多个包路径扫描
		
1. 简介 随着现在主流的前后端分离模式开发越来越成熟,接口文档的编写和规范是一件非常重要的事.简单的项目来说,对应的controller在一个包路径下,因此在Swagger配置参数时只需要配置一 ...
 - springboot使用内部tomcat启动和外部tomcat启动的区别
		
springboot本身提供了内部tomcat,可以使用main方法直接启动即可,此时在访问项目请求时,不需要加上项目名称.例如:http://localhost:8088/user/ 如果使用外部t ...
 - 从零开始的SpringBoot项目 ( 三 ) 项目打包( war包篇 )
		
pom.xml 修改打包类型 jar 改为 war 添加 tomcat 依赖 找到最右边的 Maven Projects,点击进去,选择需要打包的项目,并点击 install,就开始打包了,打包前先点 ...
 - 【spring   Boot】2.在Myecplise上把spring Boot项目打包   war包和jar包
		
========================================================第一部分======================================== ...
 - Spring boot打包war包
		
1.设置打包的类型(war/jar) 在pom.xml里设置 <packaging>war</packaging> 2.移除嵌入式tomcat插件 //在pom.xml里找到s ...
 
随机推荐
- iOS - UIEvent事件及UIResponder响应者
			
在iOS中不是所有的对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件,称之为响应者对象: UIApplication.UIViewController.UIView都继承自U ...
 - springMVC访问 WEB-INF 下的 jsp 和 html
			
配置freemarker,记得加上jar包 <?xml version="1.0" encoding="UTF-8"?> <beans xml ...
 - python---使用md5加密
			
python中使用md5进行加密字符串: __author__ = 'Administrator' #-*- coding: utf-8 -*- import hashlib aa = ' #需要加密 ...
 - FZU2110 Star【计算几何】
			
Overpower often go to the playground with classmates. They play and chat on the playground. One day, ...
 - OpenCV学习笔记之课后习题练习4-1
			
第四章课后练习1 1.本章完整讲述了基本的输入/输出编程以及OpenCV的数据结构.下面的练习是基于前面的知识做一些应用,为后面大程序的实现提供帮助.a.创建一个程序实现以下功能:(1)从视频文件中读 ...
 - redis系列之数据库与缓存数据一致性解决方案
			
redis系列之数据库与缓存数据一致性解决方案 数据库与缓存读写模式策略 写完数据库后是否需要马上更新缓存还是直接删除缓存? (1).如果写数据库的值与更新到缓存值是一样的,不需要经过任何的计算,可以 ...
 - 【紫书】BigInteger 高精度类型 原书上有一个bug:A+B!=B+A
			
存个代码 struct BigInterger { static const int BASE = 1e8; ; vector<int> s; BigInterger() { *this ...
 - bisecting k-means
			
总结 1.二分法 2.总体中的最值 bisecting k-means :在初始时将所有数据当成一个聚簇,然后递归地将最不紧凑的聚簇用2-means拆分为2个聚簇,直至满意
 - python2.X编码
			
1.Python文件的编码 在Python文件中,可以在第一或第二行指定文件的编码格式(以注释的形式加),这也是Python语法规定的,见http://www.python.org/peps/pep- ...
 - Shell初学(三)传参
			
一. 脚本代码:test.sh echo "Shell 传递参数实例!"; echo "执行的文件名:$0"; echo "第一个参数为:$1&quo ...