手写实现spring mvc

一直没时间来写一写关于springmvc源码的分析,今天晚上心血来潮就写一段关于springmvc实现的东西给大家分享哈

附一张网上的原理图


首先看一看这个demo的包的架构


这个demo是由注解实现springmvc的,现在流行的方式,简单方便,xml的配置的太繁琐了

注解类:Controller 

package com.springmvc.annotion;

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;

/**
 * 
 * @author Administrator
 * 
 */
@Target(ElementType.TYPE)//指定注解作用在我们(TYPE)类上/(FIELD)变量上/(METHOD)方法上
@Retention(RetentionPolicy.RUNTIME)//用来描述我们自定义注解的生命周期,(RUNTIME)运行时时期,(SOURCE)源文件时间,(CLASS)编译时期
@Documented //工具文档化,将注释生成api
public @interface Controller {
	String value() default "";
}
注解类: Qualifier
package com.springmvc.annotion;

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;

/**
 *  此注解用来将使用该注解的Bean变量,实例注入进去
 * @author Administrator
 * 
 */
@Target(ElementType.FIELD)//指定注解作用在我们的类上/FIELD变量上/方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Qualifier {
	String value() default "";
}

注解类: RequestMapping

package com.springmvc.annotion;

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;

/**
 *
 * @author Administrator
 * 
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
	String value() default "";
}
注解类: Service

package com.springmvc.annotion;

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;

/**
 * 
 * @author Administrator
 * 
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
	String value() default "";
}


核心控制类 DispatcherServlet 


package com.springmvc.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
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.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.springmvc.annotion.Controller;
import com.springmvc.annotion.Qualifier;
import com.springmvc.annotion.RequestMapping;
import com.springmvc.annotion.Service;
/**
 * 核心控制类
 * @author Administrator
 *
 */
@WebServlet("/DispatcherServlet")
public class DispatcherServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	//将基础包中的类的类名放入集合中
	private List<String> packeNames=new ArrayList<String>();
	//注解属性对应各层对象实例MAP
	private Map<String,Object> InstanceMaps=new HashMap<String, Object>();
	//请求Url对应的Method对象
	private Map<String,Method> hanlderMaps=new HashMap<String, Method>();
	@Override
	public void init() throws ServletException {
         /**
          * 扫描包下含有注解的类
          * 扫描基础包后拿到权限命名包+类名
          * com/springmvc/annotion/Controller.java
          * 替换/和.java
          * com.springmvc.annotion.Controller
          */
		//扫描全包
		scanBase("com.springmvc");
		//找到实例
		try {
			fileterAndInstance();
			//注入springIoc,各层的调用的实体
			springIoc();
			//注入对应的方法
			halderMaps();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	

	/**
     * 扫描基包
     */
	private void scanBase(String basePackage){
	URL	url=this.getClass().getClassLoader().getResource("/"+replacePath(basePackage));
	//拿到路径下的文件夹以及文件
	String pathFile=url.getFile();
	//通过路径生成file
	File files=new File(pathFile);
	String[] filesString=files.list();
	for (String path : filesString) {
		//再次构成一个file
		File eachFile=new  File(pathFile +path);
		if(eachFile.isDirectory()){
			//递归引用scanBase
			scanBase(basePackage+"."+eachFile.getName());
		}else if(eachFile.isFile()){
			System.out.println("正在装载:"+basePackage+"."+eachFile.getName());
			//表示扫描到的是一个文件
			packeNames.add(basePackage+"."+eachFile.getName());
		}
	}
	}
	/**
	 * 替换成路径
	 */
	private String replacePath(String path){
		return path.replaceAll("\\.", "/");
		
	}
	/**
	 * 拦截方法请求然后对应请求地址到对应的handler实例
	 * @throws Exception
	 */
	private void fileterAndInstance() throws Exception{
		//判断集合里面是否有实例
		if(packeNames.size()<=0){
			return;
		}
		for(String className:packeNames){
			Class ccName=Class.forName(className.replace(".class", ""));
			if(ccName.isAnnotationPresent(Controller.class)){
				Object instance=ccName.newInstance();
				//将实例装入Map key
				Controller cortollerAnController=(Controller)ccName.getAnnotation(Controller.class);
				//通过注解对象访问属性值
				String key=cortollerAnController.value();
				//通过注解的key找到对应bean的实例
				InstanceMaps.put(key, instance);
				//放入Map
			}else if(ccName.isAnnotationPresent(Service.class)){
				Object instance=ccName.newInstance();
				//将实例装入Map key
				Service serviceAncontroller=(Service)ccName.getAnnotation(Service.class);
			    //通过注解对象拿到属性值
				String key=serviceAncontroller.value();
				//通过注解的key找到对应bean的实例
				InstanceMaps.put(key, instance);
				//放入Map
			}else{
				//没有找到注解
				continue;
			}
		}
	}
	//将实例注入到spring容器里
    private void springIoc() throws IllegalArgumentException, IllegalAccessException {
		if(InstanceMaps.size()<=0){
			return;
		}
		for(Map.Entry<String, Object> entry :InstanceMaps.entrySet()){
			Field[] fields=entry.getValue().getClass().getDeclaredFields();
			for(Field field:fields){
				if(field.isAnnotationPresent(Qualifier.class)){
					//注入
					String qualifierValueString=((Qualifier)field.getAnnotation(Qualifier.class)).value();
					field.setAccessible(true);
					field.set(entry.getValue(),InstanceMaps.get(qualifierValueString));
					
				}else{
					continue;
				}
			}
		}
	}
  //通过url找到相应的method对象进行处理
  	private void halderMaps() throws Exception {
  		if(InstanceMaps.size()<=0){
			return;
		}
  		//存的实例是有控制层的和service层
  		for(Map.Entry<String, Object> entry :InstanceMaps.entrySet()){
			if(entry.getValue().getClass().isAnnotationPresent(Controller.class)){
				Controller controllerAncontroller=(Controller)entry.getValue().getClass().getAnnotation(Controller.class);
			    String baseUrl=controllerAncontroller.value();
			    Method[] controllerMethods=entry.getValue().getClass().getMethods();
			    for(Method controllerMethod:controllerMethods){
			    	if(controllerMethod.isAnnotationPresent(RequestMapping.class)){
			    		//@RequestMapping注解的方法
			    		String methodUrl=((RequestMapping)controllerMethod.getAnnotation(RequestMapping.class)).value();
			    	    hanlderMaps.put("/"+baseUrl+"/"+methodUrl, controllerMethod);
			    	}else{
			    		continue;
			    	}
			    }
			}
		}
  	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		//请求url
		String url=req.getRequestURI();
		//工程路径
		String projectName=req.getContextPath();
		//完整路径
		String path=url.replace(projectName, "").split("\\.")[0];
		//方法对象
		Method method=hanlderMaps.get(path);
		PrintWriter outPrintWriter=resp.getWriter();
		if(method==null){
			outPrintWriter.write("您访问的资源找不到,请检查您的访问地址!");
			return;
		}
		//localhost:8080/SpringMvc/mvcContro/insert
		String className=url.split("/")[2];
			try {
				method.invoke(InstanceMaps.get(className), new Object[]{req,resp});
			} catch (IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
}

服务层接口 MvcService.java

package com.springmvc.service;

import java.util.Map;

public interface MvcService {
     int insert(Map map);
     int delete(Map map);
     int update(Map map);
     int select(Map map);
}

服务层实现 MvcServiceImpl.java

package com.springmvc.service.impl;

import java.util.Map;

import com.springmvc.annotion.Service;
import com.springmvc.service.MvcService;
@Service("mvcServiceImpl")
public class MvcServiceImpl implements MvcService{

	@Override
	public int insert(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的Insert方法");
		return 0;
	}

	@Override
	public int delete(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的delete方法");
		return 0;
	}

	@Override
	public int update(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的update方法");
		return 0;
	}

	@Override
	public int select(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的select方法");
		return 0;
	}

}
控制层  MvcController.java

package com.springmvc.service.impl;

import java.util.Map;

import com.springmvc.annotion.Service;
import com.springmvc.service.MvcService;
@Service("mvcServiceImpl")
public class MvcServiceImpl implements MvcService{

	@Override
	public int insert(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的Insert方法");
		return 0;
	}

	@Override
	public int delete(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的delete方法");
		return 0;
	}

	@Override
	public int update(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的update方法");
		return 0;
	}

	@Override
	public int select(Map map) {
		// TODO Auto-generated method stub
		System.out.println("调用这个服务类的select方法");
		return 0;
	}

}


配置tomcat 启动运行核心控制类 web.xml
<?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_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>SpringMvc</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <!-- 配置编码格式 -->
  <!-- 配置SpringMVC启动的servlet -->
  <servlet>
  	<servlet-name>springMvc</servlet-name>
  	<servlet-class>com.springmvc.servlet.DispatcherServlet</servlet-class>
     <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>springMvc</servlet-name>
  	<url-pattern>*.htm</url-pattern>
  </servlet-mapping>
 
  <!-- 设置session的有效时间 -->
  <session-config>
  	<session-timeout>30</session-timeout>
  </session-config>
  
</web-app>



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值