使用spring容器管理和配置netty

来源:互联网 发布:淘宝mrd模板 编辑:程序博客网 时间:2024/05/16 14:56
使用spring容器管理和配置netty


为了使程序达到方便配置和管理,spring的ioc容器是特效药之一。本文将使用ioc来管理和配置netty服务器

  • 服务端使用Reactor多线程模型,详见 李林锋老师的博文 Netty系列之Netty高性能之道

这里写图片描述

在本程序中Reactor Thread Acceptor对应BossGroup,Reactor Thread 
Pool对应WorkerGroup


1. netty和spring的maven依赖

<dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-context</artifactId>    <version>3.2.2.RELEASE</version></dependency><dependency>    <groupId>io.netty</groupId>    <artifactId>netty-all</artifactId>    <version>4.0.10.Final</version></dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

java代码结构解析

1. 服务器管理接口

public interface Server {    public interface TransmissionProtocol{    }    // 服务器使用的协议    public enum TRANSMISSION_PROTOCOL implements TransmissionProtocol {        TCP,UDP    }    TransmissionProtocol getTransmissionProtocol();    // 启动服务器    void startServer() throws Exception;    void startServer(int port) throws Exception;;    void startServer(InetSocketAddress socketAddress) throws Exception;    // 关闭服务器    void stopServer() throws Exception;    InetSocketAddress getSocketAddress();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

2. 服务器初始化配置接口

public interface NettyServer extends Server{    /**     * ServerBootstrap创建成功后会有一个ChannelInitializer(即pipeline factory), 本方法主要用于获取这个     * ChannelInitializer     *      * @return      */    public ChannelInitializer<? extends Channel> getChannelInitializer();    /**     * 设置自己的ChannelInitializer     *      * @param initializer     *            pipeline的工厂类,主要为每个新的链接创建一个pipeline     */    public void setChannelInitializer(ChannelInitializer<? extends Channel> initializer);    /**     * 获取netty server的configuration     *      * @return .     */    public NettyConfig getNettyConfig();}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

3. 基本服务器配置类

public abstract class AbstractNettyServer implements NettyServer{    private static final Logger LOG = LoggerFactory.getLogger(AbstractNettyServer.class);    //用于管理所有的channel    public static final ChannelGroup ALL_CHANNELS = new DefaultChannelGroup("NADRON-CHANNELS", GlobalEventExecutor.INSTANCE);    protected final NettyConfig nettyConfig;    protected ChannelInitializer<? extends Channel> channelInitializer;    public AbstractNettyServer(NettyConfig nettyConfig,            ChannelInitializer<? extends Channel> channelInitializer)     {        this.nettyConfig = nettyConfig;        this.channelInitializer = channelInitializer;    }    @Override    public void startServer(int port) throws Exception     {        nettyConfig.setPortNumber(port);        nettyConfig.setSocketAddress(new InetSocketAddress(port));        startServer();    }    @Override    public void startServer(InetSocketAddress socketAddress) throws Exception    {        nettyConfig.setSocketAddress(socketAddress);        startServer();    }    @Override    public void stopServer() throws Exception     {        LOG.debug("In stopServer method of class: {}", this.getClass()                .getName());        ChannelGroupFuture future = ALL_CHANNELS.close();        try         {            future.await();        }         catch (InterruptedException e)         {            LOG.error(                    "Execption occurred while waiting for channels to close: {}",                    e);        }         finally         {            if (null != nettyConfig.getBossGroup())             {                nettyConfig.getBossGroup().shutdownGracefully();            }            if (null != nettyConfig.getWorkerGroup())             {                nettyConfig.getWorkerGroup().shutdownGracefully();            }        }    }    @Override    public ChannelInitializer<? extends Channel> getChannelInitializer()    {        return channelInitializer;    }    // 获取configuration @link(NettyConfig.class)    @Override    public NettyConfig getNettyConfig() {        return nettyConfig;    }    // 获取bossGroup,在spring中配置    protected EventLoopGroup getBossGroup(){        return nettyConfig.getBossGroup();    }    // 获取workerGroup, 在spring中配置    protected EventLoopGroup getWorkerGroup(){        return nettyConfig.getWorkerGroup();    }    @Override    public InetSocketAddress getSocketAddress()    {        return nettyConfig.getSocketAddress();    }    @Override    public String toString()     {        return "NettyServer [socketAddress=" + nettyConfig.getSocketAddress()                + ", portNumber=" + nettyConfig.getPortNumber() + "]";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

4. tcpServer实现类

public class NettyTCPServer extends AbstractNettyServer {    private static final Logger LOG = LoggerFactory            .getLogger(NettyTCPServer.class);    private ServerBootstrap serverBootstrap;    public NettyTCPServer(NettyConfig nettyConfig,            ChannelInitializer<? extends Channel> channelInitializer)     {        super(nettyConfig, channelInitializer);    }    @Override    public void startServer() throws Exception {        try {            serverBootstrap = new ServerBootstrap();            Map<ChannelOption<?>, Object> channelOptions = nettyConfig.getChannelOptions();            if(null != channelOptions){                Set<ChannelOption<?>> keySet = channelOptions.keySet();                // 获取configuration配置到channelOption                for(ChannelOption option : keySet)                {                    serverBootstrap.option(option, channelOptions.get(option));                }            }            // reactor多线程模型,配置bossGroup和workGroup            // bossGroup和workGroup使用spring容器管理            serverBootstrap.group(getBossGroup(),getWorkerGroup())                    .channel(NioServerSocketChannel.class)                    .childHandler(getChannelInitializer());            // 绑定端口,启动并监听            Channel serverChannel = serverBootstrap.bind(nettyConfig.getSocketAddress()).sync()                    .channel();            ALL_CHANNELS.add(serverChannel);        } catch(Exception e) {            LOG.error("TCP Server start error {}, going to shut down", e);            super.stopServer();            throw e;        }    }    @Override    public TransmissionProtocol getTransmissionProtocol() {        return TRANSMISSION_PROTOCOL.TCP;    }    // 配置自己的initializer    @Override    public void setChannelInitializer(ChannelInitializer<? extends Channel> initializer) {        this.channelInitializer = initializer;        serverBootstrap.childHandler(initializer);    }    @Override    public String toString() {        return "NettyTCPServer [socketAddress=" + nettyConfig.getSocketAddress()                + ", portNumber=" + nettyConfig.getPortNumber() + "]";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

5. configuration实现类NettyConfig

// 用于配置serverpublic class NettyConfig {    private Map<ChannelOption<?>, Object> channelOptions;    // reactor多线程模型中的acceptor    private NioEventLoopGroup bossGroup;    // reactor多线程模型中的threadPool    private NioEventLoopGroup workerGroup;    //bossGroup的线程数    private int bossThreadCount;    //workerGroup的线程数    private int workerThreadCount;    private InetSocketAddress socketAddress;    private int portNumber = 18090;    protected ChannelInitializer<? extends Channel> channelInitializer;    public Map<ChannelOption<?>, Object> getChannelOptions() {        return channelOptions;    }    public void setChannelOptions(            Map<ChannelOption<?>, Object> channelOptions) {        this.channelOptions = channelOptions;    }    public synchronized NioEventLoopGroup getBossGroup() {        if (null == bossGroup) {            if (0 >= bossThreadCount) {                bossGroup = new NioEventLoopGroup();            } else {                bossGroup = new NioEventLoopGroup(bossThreadCount);            }        }        return bossGroup;    }    public void setBossGroup(NioEventLoopGroup bossGroup) {        this.bossGroup = bossGroup;    }    public synchronized NioEventLoopGroup getWorkerGroup() {        if (null == workerGroup) {            if (0 >= workerThreadCount) {                workerGroup = new NioEventLoopGroup();            } else {                workerGroup = new NioEventLoopGroup(workerThreadCount);            }        }        return workerGroup;    }    public void setWorkerGroup(NioEventLoopGroup workerGroup) {        this.workerGroup = workerGroup;    }    public int getBossThreadCount() {        return bossThreadCount;    }    public void setBossThreadCount(int bossThreadCount) {        this.bossThreadCount = bossThreadCount;    }    public int getWorkerThreadCount() {        return workerThreadCount;    }    public void setWorkerThreadCount(int workerThreadCount) {        this.workerThreadCount = workerThreadCount;    }    public synchronized InetSocketAddress getSocketAddress() {        if (null == socketAddress) {            socketAddress = new InetSocketAddress(portNumber);        }        return socketAddress;    }    public void setSocketAddress(InetSocketAddress socketAddress) {        this.socketAddress = socketAddress;    }    public int getPortNumber() {        return portNumber;    }    public void setPortNumber(int portNumber) {        this.portNumber = portNumber;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

6. 实现自己的ChannelInitializer

// ChannelInitializer是默认的initializer,因此需要继承ChannelInitializer类来实现自己的initializerpublic class MyChannelInitializer extends    ChannelInitializer<SocketChannel> {    private static final int MAX_IDLE_SECONDS = 60;    @Override    protected void initChannel(SocketChannel ch) throws Exception {        // 添加到pipeline中的handler会被串行处理(PS: 类似工业生产中的流水线)        ChannelPipeline pipeline = ch.pipeline();        pipeline.addLast("idleStateCheck", new IdleStateHandler(                MAX_IDLE_SECONDS, MAX_IDLE_SECONDS, MAX_IDLE_SECONDS));        // 使用addLast来添加自己定义的handler到pipeline中        // pipeline.addLast("multiplexer", createMyProtcolDecoder());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

7. 线程工厂类NamedThreadFactory

在netty4中为bossGroup和workerGroup创建线程时需要使用ThreadFactory来创建
  • 1
  • 2
// 自定义线程工厂类public class NamedThreadFactory implements ThreadFactory {    // a thread counter    private static AtomicInteger counter = new AtomicInteger(1);     private String        name = "Adam";     private boolean       daemon; // 守护线程    private int           priority; // 线程优先级    public NamedThreadFactory(String name) {         this(name, false, -1);     }     public NamedThreadFactory(String name, boolean daemon) {         this(name, daemon, -1);     }     public NamedThreadFactory(String name, boolean daemon, int priority) {         this.name = name;         this.daemon = daemon;         this.priority = priority;     }     @Override     public Thread newThread(Runnable r) {         Thread thread = new Thread(r, name + "[" + counter.getAndIncrement() + "]");         thread.setDaemon(daemon);         if (priority != -1) {             thread.setPriority(priority);         }         return thread;     }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

8. AppContext类获取bean

public class AppContext implements ApplicationContextAware{    public static final String TCP_SERVER = "tcpServer";    // The spring application context.    private static ApplicationContext applicationContext;    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException    {        AppContext.applicationContext = applicationContext;    }    // 根据beanName获取bean    public static Object getBean(String beanName)    {        if (null == beanName)        {            return null;        }        return applicationContext.getBean(beanName);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

以上即为所需用到的java类,接下来要实现的是如何使用spring ioc来配置管理netty server

spring容器配置

<beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"    xmlns:util="http://www.springframework.org/schema/util"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd     http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"><bean id="tcpServer" class= "io.adam.server.netty.NettyTCPServer" destroy-method="stopServer">        <constructor-arg ref="tcpConfig" />        <constructor-arg ref="myChannelInitializer" /></bean><bean id="myChannelInitializer" class="io.adam.server.netty.MyChannelInitializer"><bean id="tcpConfig" class="io.nadron.server.netty.NettyConfig">        <property name="channelOptions" ref="tcpChannelOptions"/>        <property name="bossGroup" ref="bossGroup"/>        <property name="workerGroup" ref="workerGroup"/>        <property name="portNumber" value="10086"/></bean><util:map id="tcpChannelOptions" map-class="java.util.HashMap">        <entry>            <key><util:constant static-field="io.netty.channel.ChannelOption.SO_KEEPALIVE"/></key>            <value type="java.lang.Boolean">true</value>        </entry>        <entry>            <key><util:constant static-field="io.netty.channel.ChannelOption.SO_BACKLOG"/></key>            <value type="java.lang.Integer">100</value>        </entry></util:map><bean id="bossGroup" class="io.netty.channel.nio.NioEventLoopGroup" destroy-method="shutdownGracefully">        <constructor-arg type="int" index="0" value="2" />        <constructor-arg index="1" ref="bossThreadFactory" /></bean><bean id="workerGroup" class="io.netty.channel.nio.NioEventLoopGroup" destroy-method="shutdownGracefully">        <constructor-arg type="int" index="0"            value="8" />        <constructor-arg index="1" ref="workerThreadFactory" /></bean><bean id="bossThreadFactory" class="io.adam.concurrent.NamedThreadFactory">        <constructor-arg type="java.lang.String" value="Server-Boss" /></bean><bean id="workerThreadFactory" class="io.adam.concurrent.NamedThreadFactory">        <constructor-arg type="java.lang.String" index="0" value="Server-Worker" /></bean></beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

以上即为所需spring 容器bean的配置,bean中的class需根据自己的项目路径进行修改

接下来编写测试代码来启动服务端

ServerManager 类

public class ServerManager{    private AbstractNettyServer tcpServer;    public ServerManager() {        tcpServer = (AbstractNettyServer)AppContext.getBean(AppContext.TCP_SERVER);    }    public void startServer(int port) throws Exception {        tcpServer.startServer(port);    }    public void startServer() throws Exception {        tcpServer.startServer();    }    public void stopServer() throws Exception {        tcpServer.stopServer();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

测试类

public class TestServer {    public static void main(String[] args) {        ServerManager manager = new ServerManager();        //manager.startServer(args[0]);        manager.startServer();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

本文基本实现了使用spring配置管理netty server所需的基本骨架,可在此基础上拓展其它功能。


转载:http://blog.csdn.net/u012233832/article/details/52142628   感谢博主分享
原创粉丝点击