仿SpringMVC

最近在看Spring的源码,开始的时候看的没有头绪,自己大脑都是乱麻;自己就在网上找资料,自己慢慢的看,到现在只是刚刚开始,把自己总结的SpringMVC的个人心得分享个大家,很多都是在网上找的资料,现在开始....

首先展示目录结构:

现在开始正文:

创建注解,可以仿照Spring的源码中的注解

@Controller

package com.stone.annotation;

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

/**
 * 
 * @ClassName:Controller   
 * @Description:controller控制器注解  
 * @author: stone
 * @date:2018年2月26日 下午1:34:54   
 *
 */
@Target({ElementType.TYPE})//在类上的注解
@Retention(RetentionPolicy.RUNTIME)//这是代表运行的时候启动
@Documented
public @interface Controller {

	String value() default "";
}

@RequestMapping

package com.stone.annotation;

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

@Target({ ElementType.TYPE, ElementType.METHOD}) // 在类和方法上的注解
@Retention(RetentionPolicy.RUNTIME) // 这是代表运行的时候启动
@Documented
public @interface RequestMapping {
	String value() default "";
}

@RequestParam

package com.stone.annotation;

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

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {

	String value();
}

@Resource

package com.stone.annotation;

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

/**
 * 
 * @ClassName:Quatifier   
 * @Description:TODO(这里用一句话描述这个类的作用)   
 * @author: stone
 * @date:2018年2月26日 下午1:36:39   
 *
 */
@Target({ ElementType.FIELD }) // 代表注解的注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Resource {
	String value() default "";

}

@Service

package com.stone.annotation;

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

/**
 * 
 * @ClassName:Service   
 * @Description:服务注解
 * @author: stone
 * @date:2018年2月26日 下午1:37:21   
 *
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {

	 String value() default "";
}

以上就是项目中要是使用的注解。

接下来重头戏DsiparcherServlet

package com.stone.servlet;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.stone.annotation.Controller;
import com.stone.annotation.Resource;
import com.stone.annotation.RequestMapping;
import com.stone.annotation.Service;
import com.stone.controller.MymvcController;
import com.stone.handlerAdapter.HandlerAdapter;

/**
 * @ClassName:DispatcherServlet   
 * @Description:总控制器   
 * @author: stone
 * @date:2018年2月26日 下午1:50:05   
 *
 */
public class DispatcherServlet extends HttpServlet {
	
	/**
	 * 存放扫描的包+类.class 
	 * 例:com.stone.annotation.Controller.class 有.class后缀
	 */
	List<String> packageNames = new ArrayList<String>();
	
	/**
	 * 所有类的实例 key是注解的value, value是所有类的实例
	 * 例:stone = com.stone.controller.SpringmvcController@7a141541
	 */
	Map<String, Object> instanceMap = new HashMap<String, Object>();

	/**
	 * 请求地址和实例方法
	 * 例:/stone/select = public java.lang.String com.stone.controller.SpringmvcController.select(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
	 */
	Map<String, Object> handlerMap = new HashMap<String, Object>();

	public DispatcherServlet() {
		super();
	}

	/**
	 * @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 系统启动初始化工作
	 * <p>Title:init</p>   
	 * <p>Description: </p>   
	 * @see Servlet#init(ServletConfig)
	 * @param config
	 * @throws ServletException   
	 * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
	 */
	@Override
	public void init(ServletConfig config) throws ServletException {
		
		// 1、包扫描,获取包中的文件
        scanPackage(config.getInitParameter("scanPackage"));
        
        // 2、过滤得到Cotroller,并实例化
        try {
			filterAndInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
        
        // 3、建立映射关系
        handlerMap();
        
        // 4、实现注入
        ioc();
	}

	/**
	 * @Title:scanPackage   
	 * @Description:扫描指定包下的文件(类)
	 * @param:@param basePackage      
	 * @return: void      
	 * @throws
	 */
	private void scanPackage(String basePackage) {
		URL url=this.getClass().getClassLoader().getResource("/"+replaceTo(basePackage));
        
        String pathfile=url.getFile();
        File file=new  File(pathfile);
        
        String[] files=file.list();
        for (String path : files) {
            File eachFile= new File(pathfile+path);
            if(eachFile.isDirectory()){
                scanPackage(basePackage+"."+eachFile.getName());
            }else{
            	// com.stone.annotation.Controller.class
                packageNames.add(basePackage+"."+eachFile.getName());
            }
            
        }
		
	}

	/**
	 * @Title:replaceTo   
	 * @Description:将所有.转义获取对应的路径  
	 * @param:@param path com.stone
	 * @param:@return      
	 * @return:String      
	 * @throws
	 */
	private String replaceTo(String path) {
		
		return path.replaceAll("\\.","/");
	}

	/**
	 * @Title:filterAndInstance   
	 * @Description:过滤得到Cotroller,并实例化   
	 * @param:@throws Exception      
	 * @return: void      
	 * @throws
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void filterAndInstance() throws Exception {
		if(packageNames.size()<=0){
	        return;
	    }
        for (String classname : packageNames) {
            Class ccName=Class.forName(classname.replace(".class",""));
            if(ccName.isAnnotationPresent(Controller.class)){// 判断类是否有@Controller注解
                Object instance= ccName.newInstance();
                Controller an= (Controller)ccName.getAnnotation(Controller.class);
                String key=an.value();
                instanceMap.put(key,instance);
                
            }else if(ccName.isAnnotationPresent(Service.class)){// 判断类是否有@Service注解
                Object instance= ccName.newInstance();
                Service an= (Service) ccName.getAnnotation(Service.class);
                String key=an.value();
                instanceMap.put(key,instance);
            }else{
                continue;
            }
        }
	}
	
	/**
	 * @Title:handlerMap   
	 * @Description:建立映射关系 
	 * @param:      
	 * @return: void      
	 * @throws
	 */
	private void handlerMap() {
		if(instanceMap.size()<=0)
            return;
        for(Map.Entry<String, Object> entry:instanceMap.entrySet()){
            if(entry.getValue().getClass().isAnnotationPresent(Controller.class)){
                Controller controller=(Controller)entry.getValue().getClass().getAnnotation(Controller.class);
                String ctvalue= controller.value();
                Method[] methods=entry.getValue().getClass().getMethods();
                for(Method method:methods){
                    if(method.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping rm= (RequestMapping)method.getAnnotation(RequestMapping.class);
                        String rmvalue=rm.value();
                        // /stone/update,public java.lang.String com.stone.controller.SpringmvcController.select(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
                        handlerMap.put("/"+ctvalue+"/"+rmvalue,method);
                    }else{
                        continue;
                    }
                }
            }else{
                continue;
            }   
            
        }
	}
	
	private void ioc() {
		if(instanceMap.isEmpty())return;
        
        for(Map.Entry<String, Object> entry:instanceMap.entrySet()){
        	//拿到类里面的属性
            Field[] fields= entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
            	// 由于变量的修饰符是private,需要这个操作
                field.setAccessible(true);
                if(field.isAnnotationPresent(Resource.class)){
                    Resource qf=(Resource)field.getAnnotation(Resource.class);
                    String value= qf.value();
                    
                    field.setAccessible(true);
                    try {
                        field.set(entry.getValue(), instanceMap.get(value));
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// /MyMvc/update.ht
		String url= req.getRequestURI();
		// /MyMvc
        String context=req.getContextPath();
        // /update.ht
        String path=url.replace(context,"");
        Method method =(Method) handlerMap.get(path);
        MymvcController controller=(MymvcController) instanceMap.get(path.split("/")[1]); 
        HandlerAdapter handlerAdapter = (HandlerAdapter)instanceMap.get("MymvcHandlerAdepter");
        
        Object[] args = handlerAdapter.hand(req, resp, method, instanceMap);
        
        try {
            method.invoke(controller, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
	}
	
	
	
}

在编码DispacherServlet的过程中,主要还是对于反射有很深入的理解,建议可以多看看,细嚼慢咽,相信大家会有收获。

下面就是Service和Controller:

MymvcServie接口

package com.stone.service;

public interface MymvcServie {

	void insert();

	void delete();

	void update();

	void select();

}

MymvcServiceImpl接口的实现类

package com.stone.service.impl;

import com.stone.annotation.Service;
import com.stone.service.MymvcServie;

@Service("MymvcServiceImpl")
public class MymvcServiceImpl implements MymvcServie {

	@Override
	public void insert() {
		System.out.println("MymvcServiceImpl:insert");

	}

	@Override
	public void delete() {
		System.out.println("MymvcServiceImpl:delete");

	}

	@Override
	public void update() {
		System.out.println("MymvcServiceImpl:update");

	}

	@Override
	public void select() {
		System.out.println("MymvcServiceImpl:select");

	}

}

MymvcController控制器

package com.stone.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.stone.annotation.Controller;
import com.stone.annotation.RequestMapping;
import com.stone.annotation.RequestParam;
import com.stone.annotation.Resource;
import com.stone.service.MymvcServie;

@Controller("stone")
public class MymvcController {

	@Resource("MymvcServiceImpl")
	private MymvcServie mymvcServie;

	@RequestMapping("insert")
	public void insert(HttpServletRequest request, HttpServletResponse response,@RequestParam("name") String name) {
		System.out.println(name);
		mymvcServie.insert();
	}

	@RequestMapping("delete")
	public void delete(HttpServletRequest request, HttpServletResponse response) {
		mymvcServie.delete();
	}

	@RequestMapping("update")
	public void update(HttpServletRequest request, HttpServletResponse response) {
		mymvcServie.update();
	}

	@RequestMapping("select")
	public void select(HttpServletRequest request, HttpServletResponse response) {
		mymvcServie.select();
	}

}

修改Web.xml,添加DispacherServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>MyMvc</display-name>
  
  <!-- spring mvc 入口 -->
  <servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>com.stone.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>scanPackage</param-name>
      <param-value>com.stone</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

到现在为止,基本上可以使用了,效果如下:


刚开始自己走到了这里,又看了相关资料,添加以下配置

HandlerAdapter参数适配器接口

package com.stone.handlerAdapter;

import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface HandlerAdapter {

	public Object[] hand(HttpServletRequest request, HttpServletResponse response, Method method,Map<String, Object> instanceMap);
}

接口的实现

package com.stone.handlerAdapter;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.stone.annotation.Service;
import com.stone.argumentResolver.ArgumentResolver;

@Service("MymvcHandlerAdepter")
public class MymvcHandlerAdepter implements HandlerAdapter {

	@Override
	public Object[] hand(HttpServletRequest request, HttpServletResponse response, Method method, Map<String, Object> instanceMap) {
		
		Class<?>[] parameterTypes = method.getParameterTypes();
		
		Object[] args = new Object[parameterTypes.length];
		
		Map<String, Object> ArgumentResolverbeans = getBeansOfType(instanceMap,ArgumentResolver.class);
		
		int paramIndex = 0;
		int i = 0;
		for (Class<?> parmclazz : parameterTypes) {
			
			for (Map.Entry<String, Object> bean : ArgumentResolverbeans.entrySet()) {
				
				ArgumentResolver argumentResolver =(ArgumentResolver)bean.getValue();
				
				if (argumentResolver.support(parmclazz, paramIndex, method)) {
					args[i++] = argumentResolver.argumentResolver(request, response, parmclazz, paramIndex, method);
				}
			}
			paramIndex++;
		}
		
		return args;
	}
	
	/**
	 * 
	 * @Title:getBeansOfType   
	 * @Description:取得实现了intfType接口的实现类  
	 * @param:@param beans
	 * @param:@param intfType
	 * @param:@return      
	 * @return:Map<String,Object>      
	 * @throws
	 */
	private Map<String, Object> getBeansOfType(Map<String, Object> beans,Class<?> intfType) {
		
		Map<String, Object> resultBeans = new HashMap<>();
		
		for(Map.Entry<String, Object> entry : beans.entrySet()){
			Class<?>[] interfaces = entry.getValue().getClass().getInterfaces();
			if (interfaces != null && interfaces.length > 0 ) {
				for (Class<?> class1 : interfaces) {
					
					if(class1.isAssignableFrom(intfType)){
						resultBeans.put(entry.getKey(), entry.getValue());
					}
				}
			}
		}
		return resultBeans;
	}

}

还有就是ArgumentResolver,通过策略模式,配置参数类型

接口

package com.stone.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface ArgumentResolver {

	public boolean support(Class<?> type, int paramIndex, Method method);

	public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
			int paramIndex, Method method);

}

相关的实现类

package com.stone.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.stone.annotation.Service;

@Service("HttpServletRequestArgumentResolver")
public class HttpServletRequestArgumentResolver implements ArgumentResolver {

	@Override
	public boolean support(Class<?> type, int paramIndex, Method method) {
		
		return ServletRequest.class.isAssignableFrom(type);
	}

	@Override
	public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
			int paramIndex, Method method) {
		
		return request;
	}

}
package com.stone.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.stone.annotation.Service;

@Service("HttpServletResponseArgumentResolver")
public class HttpServletResponseArgumentResolver implements ArgumentResolver {

	@Override
	public boolean support(Class<?> type, int paramIndex, Method method) {
		return ServletResponse.class.isAssignableFrom(type);
	}

	@Override
	public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
			int paramIndex, Method method) {
		return response;
	}

}
package com.stone.argumentResolver;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.stone.annotation.RequestParam;
import com.stone.annotation.Service;

@Service("StringArgumentResolver")
public class StringArgumentResolver implements ArgumentResolver {

	@Override
	public boolean support(Class<?> type, int paramIndex, Method method) {
		
		Annotation[][] parameterAnnotations = method.getParameterAnnotations();
		
		Annotation[] paramans = parameterAnnotations[paramIndex];
		
		for (Annotation annotation : paramans) {
			if (RequestParam.class.isAssignableFrom(annotation.getClass())) {
				return true;
			}
		}
		return false;
	}

	@Override
	public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
			int paramIndex, Method method) {
		Annotation[][] parameterAnnotations = method.getParameterAnnotations();
		
		Annotation[] paramans = parameterAnnotations[paramIndex];
		
		for (Annotation annotation : paramans) {
			if (RequestParam.class.isAssignableFrom(annotation.getClass())) {
				RequestParam requestParam = (RequestParam)annotation;
				String value = requestParam.value();
				return request.getParameter(value);
			}
		}
		return null;
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值