ps:太困了,後面再寫
github地址:https://github.com/MrBack/hello
一、創建NettyServer
package back.netty.server;
import back.config.ConfigUtils;
import com.typesafe.config.Config;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* Lession5 : Netty實現的Http協議 寫一個簡單web服務器
*/
public class NettyServer {
private NettyServer(){};
private static NettyServer nettyServer = new NettyServer();
public static NettyServer getInstance(){
return nettyServer;
}
private volatile static EventLoopGroup workerGroup = null;
private volatile static EventLoopGroup bossGroup = null;
private volatile static ServerBootstrap serverBootstrap = null;
public void start(){
Config config = ConfigUtils.getConfig();
int port = config.getInt("server.port");
if(workerGroup == null){
synchronized (NettyServer.class){
if(workerGroup == null){
workerGroup = new NioEventLoopGroup();
}
}
}
if(bossGroup == null){
synchronized (NettyServer.class){
if(bossGroup == null){
bossGroup = new NioEventLoopGroup();
}
}
}
if(serverBootstrap == null){
synchronized (NettyServer.class){
if(serverBootstrap == null){
try{
serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChildChannelHandler());
ChannelFuture future = serverBootstrap.bind(port).sync();
String url = config.getString("server.host") + ":" + port;
System.out.println("Netty服務開啓 ! 請求url:http://" + url);
future.channel().closeFuture().sync();
}catch (Exception e){
System.out.println("異常信息:" + e.getStackTrace());
}finally {
this.close();
}
}
}
}
}
private void close(){
if(bossGroup != null){
bossGroup.shutdownGracefully();
}
if(workerGroup != null){
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
NettyServer.getInstance().start();
}
}
2、設置http相關編解碼器、業務處理器
public class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast("http-decoder", new HttpRequestDecoder());
socketChannel.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
socketChannel.pipeline().addLast("http-encoder", new HttpResponseEncoder());
socketChannel.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
socketChannel.pipeline().addLast("fileServerHandler", new HttpFileServerHandler());
}
}
3、業務處理器
public class HttpFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void messageReceived(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) throws Exception {
//1、uri
String uri = fullHttpRequest.uri();
System.out.println("uri : " +uri);
ByteBuf byteBuf = fullHttpRequest.content();
String params = byteBuf.toString();
System.out.println("params : " + params);
HttpMethod method = fullHttpRequest.method();
System.out.println("http method : " + method.name());
HttpVersion httpVersion = fullHttpRequest.protocolVersion();
System.out.println("httpVersion : " + httpVersion);
HttpHeaders headers = fullHttpRequest.headers();
System.out.println("headers : ");
headers.forEach(entry -> {
System.out.println("key :" + entry.getKey() + ", value : " + entry.getValue());
});
Object resp = null;
BeanFactory.start();
ActionBean actionBean = BeanFactory.map.get(method.toString()).get(uri);
if(actionBean != null){
Method method1 = actionBean.getMethod();
Object bean = actionBean.getBean();
resp = method1.invoke(bean);
}
response(channelHandlerContext, resp);
}
private void response(ChannelHandlerContext ctx, Object resp){
String parse = JsonUtils.parse(resp);
System.out.println("Response : " + parse);
DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(parse.getBytes()));
defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
ctx.writeAndFlush(defaultFullHttpResponse).addListener(ChannelFutureListener.CLOSE);
System.out.println("===========================================================================");
}
}
4、上面的BeanFactory 模仿Spring controller簡單實現
public class BeanFactory {
public static Map<String,Map<String, ActionBean>> map = new HashMap<>();
public static void start(){
Reflections reflections = new Reflections("back.controller");
Set<Class<?>> controllers = reflections.getTypesAnnotatedWith(Controller.class);
if(controllers != null){
controllers.stream().forEach(clazz -> {
Controller annotation = clazz.getAnnotation(Controller.class);
String rootUri = annotation.value();
Object controllerBean = null;
try {
controllerBean = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Method[] methods = clazz.getMethods();
if(methods != null){
final Object obj = controllerBean;
for (Method method : methods){
if(method.isAnnotationPresent(RequestMapping.class)){
RequestMapping rm = method.getAnnotation(RequestMapping.class);
String httpMethod = rm.method();
HttpMethod httpMethod1 = HttpMethod.valueOf(httpMethod);
String methodUri = rm.value();
String uri = rootUri + methodUri;
map.compute(httpMethod, (k,v) ->{
if(v==null){
v = new HashMap<>();
}
ActionBean actionBean = new ActionBean();
actionBean.setMethod(method);
actionBean.setBean(obj);
v.put(uri, actionBean);
return v;
});
}
}
}
});
}
}
}
5、ActionBean定義
@Data
public class ActionBean {
private Method method;
private Object bean;
}
6、模擬http請求NettyServer查看結果;