Spring-MVC,多路复用的实现(代码)

自己实现spring-mvc功能以及多路复用

实现过程

  1. 自定义注解 ,MyRestController,MyRequestMapping ;
    @Retention(RetentionPolicy.RUNTIME),运行时起作用。
    @Target(ElementType.METHOD),注解作用对象,方法或类。
package com.bailiban.socket.nioHttp.MyMVC;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyRequestMapping {

    String value() default "";
}
package com.bailiban.socket.nioHttp.MyMVC;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyRestController {

    public String value() default "";
}
  1. 定义容器 分别定义两个map当作ioc容器以及url的映射容器;
	//ioc容器
    public static Map<String,Object> beanMap=new HashMap<>();
    //url映射
    public static Map<String, MethodInfo> methodMap=new HashMap<>();`
  1. 扫描方法 扫描该包,将该路径下的 类以及类的方法 放入beanmap和methodmap;
private static void refreshBeanFactory(String s) {
    String path = s.replace(".", "/");
    URL url = ServerTest.class.getClassLoader().getResource(path);
    File file = null;
    try {
        file = new File(URLDecoder.decode(url.getPath(),"utf-8"));
    } catch (UnsupportedEncodingException e) {``
        e.printStackTrace();
    }
    beanParase(file);
}`
  
   private static void beanParase(File file) {
        //如果不是文件夹,就返回。
        if (!file.isDirectory())
            return;
        File[] files=file.listFiles(pathname -> {
            if (pathname.isDirectory())
            {
                beanParase(pathname);
                return false;
            }
            return pathname.getName().endsWith(".class");
        });
        for (File f:files) {
            String path = f.getAbsolutePath();
            String classname=path.split("classes\\\\")[1].replace("\\",".").split("\\.class")[0];
            try {
                Class<?> cls=Class.forName(classname);
                MyRestController annotation = cls.getAnnotation(MyRestController.class);
                if (annotation!=null)
                {
                    controllerParase(cls);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
  1. 多路复用的实现 将socket注册到selector中,取出selector中有请求的socket;
`ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(80));
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true)
        {
            if (selector.select(3000)<=0)
            {
                continue;
            }
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                handler(next);
                iterator.remove();
            }
        }`

全部代码

package com.bailiban.socket.nioHttp.MyMVC;



import com.bailiban.socket.nioHttp.MyMVC.Model.MethodInfo;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.InetSocketAddress;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;

public class ServerTest {
    //ioc容器
    public static Map<String,Object> beanMap=new HashMap<>();
    //url映射
    public static Map<String, MethodInfo> methodMap=new HashMap<>();

    public static void main(String[] args) throws IOException, InvocationTargetException, IllegalAccessException {
        //扫描该包,将该路径下的 类以及类的方法 放入beanmap和methodmap
        refreshBeanFactory("com.bailiban.socket.nioHttp.MyMVC");
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(80));
        serverSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true)
        {
            if (selector.select(3000)<=0)
            {
                continue;
            }
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                handler(next);
                iterator.remove();
            }
        }
    }

    private static void handler(SelectionKey next) throws IOException, InvocationTargetException, IllegalAccessException {
        if (next.isAcceptable())
        {
            acceptHandler(next);
        }else if (next.isReadable())
        {
            requestHandler(next);
        }
    }

    private static void requestHandler(SelectionKey key) throws IOException, InvocationTargetException, IllegalAccessException {
        SocketChannel socketChannel=(SocketChannel) key.channel();
        ByteBuffer byteBuffer=(ByteBuffer)key.attachment();
        //byteBuffer设置为 写 模式
        byteBuffer.clear();
        if (socketChannel.read(byteBuffer)==-1)
        {
            socketChannel.close();
            return;
        }
        //设置为读模式
        byteBuffer.flip();
        String requestMsg=new String(byteBuffer.array());
        String url=requestMsg.split("\r\n")[0].split(" ")[1];


        ArrayList<String> urlParams = new ArrayList<>();
        urlParamsParase(url,urlParams);

        url=url.split("\\?")[0];
        MethodInfo methodInfo = methodMap.get(url);
        String content=null;
        content=methondInvoke(url,urlParams);
        if (content == null)
            content = "404";
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("HTTP/1.1 200 OK\r\n");
        stringBuilder.append("Content-Type:text/html;charset=utf-8\r\n\r\n");
//        stringBuilder.append("<html><head><title>HttpTest</title></head><body>\r\n");
        stringBuilder.append(content);
//        stringBuilder.append("</body></html>");
        socketChannel.write(ByteBuffer.wrap(stringBuilder.toString().getBytes()));
        socketChannel.close();
    }

    private static String methondInvoke(String url, ArrayList<String> urlParams) throws InvocationTargetException, IllegalAccessException {
        MethodInfo methodInfo = methodMap.get(url);
        if (methodInfo==null)
        {
            return "404";
        }
        String className=methodInfo.getName();
        Method method = methodInfo.getMethod();
        Object beanObj = beanMap.get(className);
        Object[] params=new Object[urlParams.size()];
        Parameter[] parameters = method.getParameters();
        if (params.length!=parameters.length)
        {
            return "参数个数不匹配";
        }
        int i=0;
        for (Parameter p:parameters)
        {
            String type = p.getType().getSimpleName();
            String pName = p.getName();
            boolean flag=false;
            for (String p2:urlParams) {
                String pp[]=p2.split("=");
                if (pName.equals(pp[0].trim()))
                {
                    Object pValue=paramTranslate(type,pp[1]);
                    params[i++]=pValue;
                    flag=true;
                    continue;
                }
            }
            if (!flag)
            {
                return "参数名称不匹配";
            }
        }
        return (String) method.invoke(beanObj,params);
    }

    private static Object paramTranslate(String type, String s) {
        switch (type){
            case "int":
                return Integer.valueOf(s);
            case "double":
                return Double.valueOf(s);
            case "float":
                return Float.valueOf(s);
            default:
                return s;
        }
    }

    private static void urlParamsParase(String url, ArrayList<String> urlParams) {
        if (!url.contains("?"))
        {
            return;
        }
        String[] ps = url.replaceFirst(".*?\\?", "").split("&");
        for (String p:ps)
        {
            if (!p.contains("="))
            {
                continue;
            }
            urlParams.add(p);
        }
    }

    private static void acceptHandler(SelectionKey key) throws IOException {
        SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
        socketChannel.configureBlocking(false);
        socketChannel.register(key.selector(),SelectionKey.OP_READ, ByteBuffer.allocate(1024));
    }


    private static void refreshBeanFactory(String s) {
        String path = s.replace(".", "/");
        URL url = ServerTest.class.getClassLoader().getResource(path);
        File file = null;
        try {
            file = new File(URLDecoder.decode(url.getPath(),"utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        beanParase(file);
    }

    private static void beanParase(File file) {
        //如果不是文件夹,就返回。
        if (!file.isDirectory())
            return;
        File[] files=file.listFiles(pathname -> {
            if (pathname.isDirectory())
            {
                beanParase(pathname);
                return false;
            }
            return pathname.getName().endsWith(".class");
        });
        for (File f:files) {
            String path = f.getAbsolutePath();
            String classname=path.split("classes\\\\")[1].replace("\\",".").split("\\.class")[0];
            try {
                Class<?> cls=Class.forName(classname);
                MyRestController annotation = cls.getAnnotation(MyRestController.class);
                if (annotation!=null)
                {
                    controllerParase(cls);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    private static void controllerParase(Class<?> cls) {
        try {
            //ioc容器注入,类名和类的实例
            beanMap.put(cls.getSimpleName(),cls.newInstance());
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        Method[] methods = cls.getDeclaredMethods();
        for (Method m:methods) {
            MyRequestMapping annotation = m.getAnnotation(MyRequestMapping.class);
            if (annotation==null)
                continue;
            String value = annotation.value();
            methodMap.put(value, new MethodInfo(m, cls.getSimpleName()));
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值