@PostConstruct 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法。被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
@PreDestroy 销毁bean之前操作
刚开始只做了启动netty没做销毁的,由此引发了一些坑。我是打的war包(和其他http的业务一起的,求轻喷)在linux服务器的tomcat shutdown之后,netty线程还在,端口依然被占用着,tomcat进程还一直在,并且一直没回收。项目需要重新发布的话需要kill掉tomcat进程,删除webapps下面的项目后重新发布才可以(而且有时候因为一些不可描述的原因想要局部更新某个class,因为netty一直没被回收,替换了class文件重启依然无效,这个困扰了我很久,最后才发现是这个问题。)
记录一下。
package com.netty.server;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.netty.server.gprs.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.*;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.*;
/**
* 2 * @Author:ponyWang
* 3 * @Date: 2019/9/9 11:49
* 4
*/
/**
* spring 容器刷新时启动 netty 的 Socket 服务,销毁时关闭netty
*
* Created by xuan on 2018/3/5
*/
@Component
public class ApplicationRefreshListener implements ApplicationListener<ApplicationContextEvent> , ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(ApplicationRefreshListener.class);
private ExecutorService socketSinglePool;
/**
* 上下文对象实例
*/
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 创建线程池来单独开启netty
*/
@PostConstruct
public void setup() {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("SocketSinglePool-%d").build();
socketSinglePool = new ThreadPoolExecutor(100, 100, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024),
namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
LOG.info("SocketSinglePool init.");
}
@Override
public void onApplicationEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent){
//ApplicationContext初始化或者刷新时触发该事件
runWebSocketServer(event.getApplicationContext());
}else if(event instanceof ContextClosedEvent){
//ApplicationContext关闭时触发该事件
//销毁netty线程
destoryNettySocket(event.getApplicationContext());
System.out.println(event.getClass().getSimpleName()+" 事件已发生!");
}else{
System.out.println("有其它事件发生:"+event.getClass().getName());
}
}
private void runWebSocketServer(ApplicationContext applicationContext) {
try {
final Server server = applicationContext.getBean(Server.class);
socketSinglePool.execute(() -> {
try {
server.start(9034);
} catch (Exception e) {
e.printStackTrace();
LOG.error("Socket listen and serve error.", e);
}
});
}catch (Exception e){
e.printStackTrace();
}
}
private void destoryNettySocket(ApplicationContext applicationContext){
final Server server = applicationContext.getBean(Server.class);
server.destroy();
System.out.println("netty destroyed");
}
/**
* 销毁前do something
*/
@PreDestroy
public void cleanup() {
//destoryNettySocket(applicationContext); //前面已经配置了ContextClosedEvent,这里就注释掉,都是用来销毁netty的
socketSinglePool.shutdown();
System.out.println("SocketSinglePool destroyed.");
}
}