IOC DI MVC

Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。本文主要讲解如何在不依靠Spring任何栈包的情况下,从无到有手写Spring的全过程。

自定义Spring && SpringMVC核心功能

  1. 配置阶段 配置web.xml, 注意init-param和url-pattern

  2. 初始化阶段
    1) init 加载配置文件
    2) ioc容器初始化
    3) 扫描相关的的类
    4) 实例化(反射机制)
    5) 进行DI操作
    6) handlerMapping(将URL和Method相关联)

  3. 运行阶段
    1) doGet()/doPost()
    2) handlerMapping匹配URI
    3 invoke()
    4) response.getWirter()

话不多说,上代码!!!

一 web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>MySpring</display-name>
  <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>
  
  <servlet>
  		<servlet-name>myMVC</servlet-name>
  		<servlet-class>com.wrf.webmvc.servlet.MyDispatcherServlet</servlet-class>
  		<init-param>
  			<param-name>contextConfigLocation</param-name>
  			<param-value>application.properties</param-value>
  		</init-param>
  		<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  		<servlet-name>myMVC</servlet-name>
  		<url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

附: application.properties

scanPackage=com.wrf.demo

二 重点!!!重点!!!重点!!!

1.新建一个servlet继承自HttpServlet方法,并让其重写doGet(xxx),doPost(xxx),init(xxx)(GenericServlet下的方法,带参数)方法

@Override
	public void init(ServletConfig config) throws ServletException {
		//1.读取配置文件
		doLoadConfig(config.getInitParameter("contextConfigLocation"));
		//2 扫描所有相关的包
		doScanner(contextConfig.getProperty("scanPackage"));
		//3 加载相应的类并加入到IOC容器中
		doInstance();
		//4 自动注入
		doAutoWired();
		//5 初始化HandleMapping
		initHandleMapping();
		System.out.println("MySpringMVC 初始化完成");
	}

2.doLoadConfig() 读取加载配置文件

//读取加载配置文件
	private void doLoadConfig(String contextConfigLocation) {
		InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
		try {
			contextConfig.load(is);
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(null !=is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

3.doScanner() 扫描相应的包

//扫描相应的类
	private void doScanner(String scanPacakage) {
		URL url = this.getClass().getClassLoader().getResource("/"+scanPacakage.replaceAll("\\.","/"));
		File classpathDir=new File(url.getFile());
		for(File file:classpathDir.listFiles() ) {
			if(file.isDirectory()) {
				doScanner(scanPacakage+"."+file.getName());
			}else {
				String className=scanPacakage+"."+file.getName().replace(".class","");
				classNames.add(className);
			}
		}
	}

4.doInstance(); IOC容器初始化

//IOC容器初始化
	private void doInstance() {
		if(classNames.isEmpty()) return ;
		try {
			for(String className:classNames) {
				//映射加载相应的类
				Class<?> clazz = Class.forName(className);
				if(clazz.isAnnotationPresent(MyController.class)) {
					Object instance = clazz.newInstance();
					String beanName=lowerFirstCase(clazz.getSimpleName());
					ioc.put(beanName, instance);
				}else if(clazz.isAnnotationPresent(MyService.class)) {
					//1 默认类名首字母小写
					//2 优先使用自定义类名
					MyService service = clazz.getAnnotation(MyService.class);
					String beanName = service.value();
					if("".equals(beanName)) {
						beanName=lowerFirstCase(clazz.getSimpleName()); 
					}
					Object instance = clazz.newInstance();
					ioc.put(beanName, instance);
					//3 如果是接口,则注入他的实现类
					Class<?>[] interfaces = clazz.getInterfaces();	
					for(Class<?> i:interfaces) {
						ioc.put(i.getName(), instance);
					}
				}else {
					//忽略继续
					continue;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

//类名转换为首字母小写
private String lowerFirstCase(String simpleName) {
char[] array=simpleName.toCharArray();
array[0]+=32;
return String.valueOf(array);
}

5.doAutoWired() 依赖注入DI

//DI 自动赋值
	private void doAutoWired() {
		if(ioc.isEmpty()) return;
		for(Map.Entry<String, Object> entry:ioc.entrySet()) {
			Field[] fields = entry.getValue().getClass().getDeclaredFields();
			for(Field field:fields) {
				if(!field.isAnnotationPresent(MyAutoWired.class))continue;
				MyAutoWired autoWired = field.getAnnotation(MyAutoWired.class);
				String beanName=autoWired.value();
				if("".equals(beanName.trim())) {
					beanName=field.getType().getName();
				}
				//确定注入
				field.setAccessible(true);
				try {
					field.set(entry.getValue(),ioc.get(beanName));
				} catch (IllegalArgumentException | IllegalAccessException e) {
					e.printStackTrace();
					continue;
				}
			}
		}
	}

6.initHandleMapping() URL与Method进行绑定

//初始化映射
private void initHandleMapping() {
		if(ioc.isEmpty()) return;
		for(Map.Entry<String, Object>entry:ioc.entrySet()) {
			Class<?> clazz = entry.getValue().getClass();
			if(!clazz.isAnnotationPresent(MyController.class)) continue;
			String baseUrl="";
			if(clazz.isAnnotationPresent(MyRequestMapping.class)) {
				MyRequestMapping requestMapping = clazz.getAnnotation(MyRequestMapping.class);
				baseUrl=requestMapping.value();
			}
			//Spring只认public方法
			Method[] methods = clazz.getMethods();
			for(Method method:methods) {
				if(!method.isAnnotationPresent(MyRequestMapping.class)) continue;
				MyRequestMapping requestMapping = method.getAnnotation(MyRequestMapping.class);
				String url=(baseUrl+"/"+requestMapping.value()).replaceAll("/+", "/");
				handleMapping.put(url, method);
				System.out.println("Mapping:"+url+"---->"+method);
			}
		}
		
	}

三 运行阶段

1.定义doDispatcher()进行进行请求转发

private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		//执行反射
		String url = req.getRequestURI();
		String contextPath = req.getContextPath();
		url=url.replace(contextPath, "").replaceAll("/+","/");

		if(!handleMapping.containsKey(url)) {
			resp.getWriter().write("404 not Found!");
			return;
		}
		Method method=this.handleMapping.get(url);
		System.out.println("Method:"+method);
	
	}

2.在doPost方法中调用doDispatcher()方法

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//6 调用Dispatcher方法
		try {
			doDispatcher(req,resp);

		}catch (Exception e) {
			e.printStackTrace();
			resp.getWriter().write("500 Exception:<br/>"+Arrays.toString(e.getStackTrace()));
		}  
	}

现在,见证奇迹的时刻到了!!!

启动服务器>>>>>>>>>>>>>>>>>>>>>>
自定义Spring && SpringMVC核心功能

浏览器访问???

自定义Spring && SpringMVC核心功能
咦?怎么什么都没有?写错了?
当然不是!!!!!!
自定义Spring && SpringMVC核心功能

访问到方法!!!
大功告成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
































对了,还有一个问题:注解怎么自定义呢?
往下看 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
自定义Spring && SpringMVC核心功能
是不是很简单呐!!!其实注解在java.lang包下就已经存在啦!!!(其他注解也是大同小异!!!)

另外小编送上彩礼两份:

package com.wrf.demo.action;

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

import com.wrf.demo.service.DemoService;
import com.wrf.webmvc.annotation.MyAutoWired;
import com.wrf.webmvc.annotation.MyController;
import com.wrf.webmvc.annotation.MyRequestMapping;
import com.wrf.webmvc.annotation.MyRequestParam;

@MyController
@MyRequestMapping("/demo")
public class MyAction {
	@MyAutoWired
	private DemoService demoService;
	
	@MyRequestMapping("/query.*.json")
	public void query(HttpServletRequest request,HttpServletResponse response,@MyRequestParam("name") String name) {
		try {
			request.setCharacterEncoding("UTF-8");
			String result=demoService.get(name);
			response.setContentType("text/html;charset=UTF-8");
			response.getWriter().write(result);
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}
	
	@MyRequestMapping("/add.json")
	public void add(HttpServletRequest request,HttpServletResponse response,@MyRequestParam("a") Integer a,@MyRequestParam("b")Integer b) {
		try {
			response.getWriter().write("result:\t"+a+"+"+b+"="+(a+b));
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
	
	@MyRequestMapping("/remove/*.json")
	public void remove(HttpServletRequest request,HttpServletResponse response,@MyRequestParam("id") Integer id) {
		
		
	}
	
	
	 
	
}

MyDispatcherServlet 源代码

package com.wrf.webmvc.servlet;

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

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.wrf.webmvc.annotation.MyAutoWired;
import com.wrf.webmvc.annotation.MyController;
import com.wrf.webmvc.annotation.MyRequestMapping;
import com.wrf.webmvc.annotation.MyService;

public class MyDispatcherServlet extends HttpServlet{

	private Properties contextConfig=new Properties();
	private List<String> classNames=new ArrayList<String>();
	private Map<String,Object> ioc=new HashMap<String,Object>();
	private Map<String, Method> handleMapping=new HashMap<String,Method>();
	
	@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 {
		//6 调用Dispatcher方法
		try {
			doDispatcher(req,resp);

		}catch (Exception e) {
			e.printStackTrace();
			resp.getWriter().write("500 Exception:<br/>"+Arrays.toString(e.getStackTrace()));
		}  
	}

	private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		//执行反射
		String url = req.getRequestURI();
		String contextPath = req.getContextPath();
		url=url.replace(contextPath, "").replaceAll("/+","/");

		if(!handleMapping.containsKey(url)) {
			resp.getWriter().write("404 not Found!");
			return;
		}
		Method method=this.handleMapping.get(url);
		System.out.println("Method:"+method);
	
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		//1.读取配置文件
		doLoadConfig(config.getInitParameter("contextConfigLocation"));
		//2 扫描所有相关的包
		doScanner(contextConfig.getProperty("scanPackage"));
		//3 加载相应的类并加入到IOC容器中
		doInstance();
		//4 自动注入
		doAutoWired();
		//5 初始化HandleMapping
		initHandleMapping();
		System.out.println("MySpringMVC 初始化完成");
	}
	
	//初始化映射
	private void initHandleMapping() {
		if(ioc.isEmpty()) return;
		for(Map.Entry<String, Object>entry:ioc.entrySet()) {
			Class<?> clazz = entry.getValue().getClass();
			if(!clazz.isAnnotationPresent(MyController.class)) continue;
			String baseUrl="";
			if(clazz.isAnnotationPresent(MyRequestMapping.class)) {
				MyRequestMapping requestMapping = clazz.getAnnotation(MyRequestMapping.class);
				baseUrl=requestMapping.value();
			}
			//Spring只认public方法
			Method[] methods = clazz.getMethods();
			for(Method method:methods) {
				if(!method.isAnnotationPresent(MyRequestMapping.class)) continue;
				MyRequestMapping requestMapping = method.getAnnotation(MyRequestMapping.class);
				String url=(baseUrl+"/"+requestMapping.value()).replaceAll("/+", "/");
				handleMapping.put(url, method);
				System.out.println("Mapping:"+url+"---->"+method);
			}
		}
		
	}


	//DI 自动赋值
	private void doAutoWired() {
		if(ioc.isEmpty()) return;
		for(Map.Entry<String, Object> entry:ioc.entrySet()) {
			Field[] fields = entry.getValue().getClass().getDeclaredFields();
			for(Field field:fields) {
				if(!field.isAnnotationPresent(MyAutoWired.class))continue;
				MyAutoWired autoWired = field.getAnnotation(MyAutoWired.class);
				String beanName=autoWired.value();
				if("".equals(beanName.trim())) {
					beanName=field.getType().getName();
				}
				//确定注入
				field.setAccessible(true);
				try {
					field.set(entry.getValue(),ioc.get(beanName));
				} catch (Exception e) {
					e.printStackTrace();
					continue;
				}
			}
		}
	}

	
	//IOC容器初始化
	private void doInstance() {
		if(classNames.isEmpty()) return ;
		try {
			for(String className:classNames) {
				//映射加载相应的类
				Class<?> clazz = Class.forName(className);
				if(clazz.isAnnotationPresent(MyController.class)) {
					Object instance = clazz.newInstance();
					String beanName=lowerFirstCase(clazz.getSimpleName());
					ioc.put(beanName, instance);
				}else if(clazz.isAnnotationPresent(MyService.class)) {
					//1 默认类名首字母小写
					//2 优先使用自定义类名
					MyService service = clazz.getAnnotation(MyService.class);
					String beanName = service.value();
					if("".equals(beanName)) {
						beanName=lowerFirstCase(clazz.getSimpleName()); 
					}
					Object instance = clazz.newInstance();
					ioc.put(beanName, instance);
					//3 如果是接口,则注入他的实现类
					Class<?>[] interfaces = clazz.getInterfaces();	
					for(Class<?> i:interfaces) {
						ioc.put(i.getName(), instance);
					}
				}else {
					//忽略继续
					continue;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//类名转换为首字母小写
	private String lowerFirstCase(String simpleName) {
		char[] array=simpleName.toCharArray();
		array[0]+=32;
		return String.valueOf(array);
	}

	//扫描相应的包
	private void doScanner(String scanPacakage) {
		URL url = this.getClass().getClassLoader().getResource("/"+scanPacakage.replaceAll("\\.","/"));
		File classpathDir=new File(url.getFile());
		for(File file:classpathDir.listFiles() ) {
			if(file.isDirectory()) {
				doScanner(scanPacakage+"."+file.getName());
			}else {
				String className=scanPacakage+"."+file.getName().replace(".class","");
				classNames.add(className);
			}
		}
	}
	
	//读取加载配置文件
	private void doLoadConfig(String contextConfigLocation) {
		InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
		try {
			contextConfig.load(is);
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(null !=is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

项目源码:https://download.csdn.net/download/knight20160302/10700991

祝各位学习快乐!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

相关文章: