带有Spring框架的Netty HTTP服务器

时间:2015-06-19 22:17:06

标签: java spring http netty

我正在用Spring实现一个Netty应用程序;但是,我的应用程序在启动后关闭,没有任何异常。

我的控制台输出是:

Connected to the target VM, address: '127.0.0.1:62313', transport: 'socket'
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Disconnected from the target VM, address: '127.0.0.1:62313', transport: 'socket'
Server started

Process finished with exit code 0

我的代码是:

iServer中

package org.crytek.server;

/**
 * Created by eemrcag on 19.06.2015.
 */
public interface IServer {

    public void start();

    public void restart();

    public void stop();
}

ServerNettyImpl

package org.crytek.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.crytek.server.handler.CryServerInitializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;

/**
 * Created by eemrcag on 19.06.2015.
 */
@Component("serverNettyImpl")
public class ServerNettyImpl implements IServer{

    @Autowired
    @Qualifier("serverInitializer")
    private CryServerInitializer serverInitializer;

    @Autowired
    @Qualifier("bossGroup")
    private NioEventLoopGroup bossGroup;

    @Autowired
    @Qualifier("workerGroup")
    private NioEventLoopGroup workerGroup;

@Autowired
@Qualifier("tcpSocketAddress")
private InetSocketAddress tcpSocketAddress;

    private Channel channel;

        @Override
    public void start() {
        ServerBootstrap b = new ServerBootstrap();
        b.option(ChannelOption.SO_BACKLOG, 1024);
        b.group(bossGroup,workerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(serverInitializer);

            try {
                channel = b.bind(tcpSocketAddress).sync().channel().closeFuture().channel();
                System.out.println("Server started");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    @Override
    public void restart() {
    this.stop();
        this.start();
    }

    @Override
    public void stop() {
        if (this.channel != null) {
            this.channel.close().addListener(ChannelFutureListener.CLOSE);
        }
    }
}

SERVERCONFIG

package org.crytek.server.config;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.crytek.server.handler.CryServerInitializer;
import org.crytek.server.humanPyramid.HumanPyramidCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import java.net.InetSocketAddress;

/**
 * Created by eemrcag on 17.06.2015.
 */
@Configuration
@ComponentScan("org.crytek.server")
@PropertySource("classpath:cryserver.properties")
public class ServerConfig {

    @Value("${port}")
    private int port;

    @Value("${boss.thread.count}")
    private int bossThreadCount;

    @Autowired
    @Qualifier("serverInitializer")
    private CryServerInitializer serverInitializer;


    @Bean(name = "bossGroup", destroyMethod = "shutdownGracefully")
    public NioEventLoopGroup bossGroup() {
        return new NioEventLoopGroup(bossThreadCount);
    }

    @Bean(name = "workerGroup", destroyMethod = "shutdownGracefully")
    public NioEventLoopGroup workerGroup() {
        return new NioEventLoopGroup();
    }
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean(name = "tcpSocketAddress")
    public InetSocketAddress tcpPort() {
        return new InetSocketAddress(port);
    }

    @Bean(name = "humanPyramidCalculator")
    @Scope("singleton")
    public HumanPyramidCalculator humanPyramidCalculator()
    {
        return new HumanPyramidCalculator();
    }

}

CryServerHandler

package org.crytek.server.handler;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import org.crytek.server.humanPyramid.HumanPyramidCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.List;

import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;

/**
 * Created by eemrcag on 15.06.2015.
 */

@Component("serverHandler")
@Sharable
public class CryServerHandler extends ChannelHandlerAdapter {

    @Autowired
    @Qualifier("humanPyramidCalculator")
    private HumanPyramidCalculator humanPyramidCalculator;

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof HttpRequest)
        {
            HttpRequest req = (HttpRequest) msg;
            String level = null;
            String index = null;

            //if(req.method().equals(HttpMethod.GET))
            QueryStringDecoder decoder = new QueryStringDecoder(req.uri());
            if(!decoder.path().equals("/humanEdgeWeight"))
            {
                FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
                ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);

            }
            List<String> levelList  = decoder.parameters().get("level");
            if(levelList.size() != 1)
            {
                //error
            }else{
                level = levelList.get(0);
            }
            List<String> indexList  = decoder.parameters().get("index");
            if(indexList.size() > 1)
            {
                //error
            }else{
                index = indexList.get(0);
            }
            double result = 0.0;
            if(index == null)
            {
                result = humanPyramidCalculator.getHumanWeight(Integer.parseInt(level));
            }else{
                result = humanPyramidCalculator.getHumanWeight(Integer.parseInt(level), Integer.parseInt(index));
            }
            ByteBuf buf = Unpooled.buffer();
            ByteBufUtil.writeAscii(buf,String.valueOf(result));
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
            response.headers().set(CONTENT_TYPE, "text/plain");
            response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
            ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

CryServerInitializer

package org.crytek.server.handler;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * Created by eemrcag on 16.06.2015.
 */
@Component("serverInitializer")
public class CryServerInitializer extends ChannelInitializer<SocketChannel> {
    @Autowired
    @Qualifier("serverHandler")
    private CryServerHandler serverHandler;

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline p = socketChannel.pipeline();
        p.addLast(new HttpServerCodec());
        p.addLast(serverHandler);
    }

    public CryServerHandler getServerHandler() {
        return serverHandler;
    }

    public void setServerHandler(CryServerHandler serverHandler) {
        this.serverHandler = serverHandler;
    }
}

HELLOAPP

package org.crytek.server;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        IServer server=(IServer)context.getBean("serverNettyImpl");
        server.start();
    }
}

** HelloService **:

package org.crytek.server;

import org.springframework.stereotype.Component;

@Component
public class HelloService {
    public String sayHello() {
        return "Hello world!";
    }
}

HumanPyramidCalculator

package org.crytek.server.humanPyramid;

/**
 * Created by eemrcag on 16.06.2015.
 */
public class HumanPyramidCalculator {

    public static double getHumanWeight(int level)
    {
        return 1;
    }
    public static double getHumanWeight(int level, int index)
    {
        return 1;
    }
}

cryserver.properties

port = 8080
boss.thread.count = 1

弹簧-config.xml中

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config />
    <context:component-scan base-package="org.crytek.server"/>
</beans>

有什么想法吗?

感谢。

2 个答案:

答案 0 :(得分:0)

您需要使用阻塞直到关闭的调用结束主方法或服务器启动方法。在netty helloworld示例中,他们调用channel.closeFuture()。sync()

答案 1 :(得分:0)

您需要启动netty服务器,例如将@PostContruct注释添加到ServerNettyImpl start()方法中。

相关问题