IOC DI MVC
Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。本文主要讲解如何在不依靠Spring任何栈包的情况下,从无到有手写Spring的全过程。
-
配置阶段 配置web.xml, 注意init-param和url-pattern
-
初始化阶段
1) init 加载配置文件
2) ioc容器初始化
3) 扫描相关的的类
4) 实例化(反射机制)
5) 进行DI操作
6) handlerMapping(将URL和Method相关联) -
运行阶段
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()));
}
}
现在,见证奇迹的时刻到了!!!
启动服务器>>>>>>>>>>>>>>>>>>>>>>
浏览器访问???
咦?怎么什么都没有?写错了?
当然不是!!!!!!
访问到方法!!!
大功告成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
对了,还有一个问题:注解怎么自定义呢?
往下看 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
是不是很简单呐!!!其实注解在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
祝各位学习快乐!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!