netty在web项目中的启动与销毁

[亡魂溺海] 提交于 2019-12-11 03:27:09
@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.");
    }
}

 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!