本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作如有错误之处忘不吝批评指正!

理解Spring本质:

    相信之前在使用spring的时候大家都配置web.xml文件、会配置spring,(如下)配置其实就是一个Servlet,DispatcherServlet源码中,它(父类)重写了 HttpServlet接口,所有的请求将交给 DispatcherServlet来处理了    <servlet>

        <servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/</url-pattern>

</servlet-mapping>

配置

    web.xm: 配置一个servlet 并接收所有请求

<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>MySpringMVC</servlet-name>
<servlet-class>cn.lyh.mySpring.MyDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>context.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>MySpringMVC</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

    context.properties:

#包扫描
scan.package=cn.lyh.mySpringTest

注解类

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
String value() default "";
} @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
String value() default "";
} @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
} @Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestParam {
/**
* 表示参数的别名,必填
* @return
*/
String value(); } @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyResponseAdvice {
} @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyResponseBody {
} @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}

MyDispacherServlet(核心实现):

    MyDispacherServlet实现了HttpServlet 并复写doGet、doPost、init 方法

·

package cn.lyh.mySpring;

import cn.lyh.mySpring.Handler.ResponseBodyHandler;
import cn.lyh.mySpring.annotation.*;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.log4j.Logger; import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.util.*; /***
*dispatcherServlet
* @author lyh
*/
public class MyDispatcherServlet extends HttpServlet {
/***配置***/
private Properties contextConfig = new Properties();
/***扫描的类名列表****/
private List<String> classNames = new ArrayList<>();
/***ioc容器 存放实例****/
private Map<String, Object> ioc = new HashMap<>();
/***url映射****/
private Map<String, Method> handlerMapping = new HashMap<>();
private static Logger logger = Logger.getLogger(MyDispatcherServlet.class);
/***返回处理器****/
private ResponseBodyHandler responseBodyHandler; @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doDispatcherServlet(req, resp);
} /****
* 加载启动
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
String contextConfigLocation = config.getInitParameter("contextConfigLocation");
try {
initMyDispatcherServlet(contextConfigLocation);
} catch (Exception e) {
e.printStackTrace();
throw new ServletException(e.getMessage());
}
} /***
* url请求映射到具体方法
* @param request
* @param response
*/
private void doDispatcherServlet(HttpServletRequest request, HttpServletResponse response) {
invoke(request, response);
} private void invoke(HttpServletRequest request, HttpServletResponse response) {
String queryUrl = request.getRequestURI();
queryUrl = queryUrl.replaceAll("/+", "/");
Method method = handlerMapping.get(queryUrl);
if (null == method) {
PrintWriter pw = null;
try {
response.setStatus(404);
logger.debug("request fail(404): " + request.getRequestURI());
pw = response.getWriter();
pw.print("404 not find -> " + request.getRequestURI());
pw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
pw.close();
}
} else {
//todo method parameters need to deal
Object[] paramValues = getMethodParamAndValue(request, response, method);
try {
String controllerClassName = toFirstWordLower(method.getDeclaringClass().getSimpleName());
Object object = method.invoke(ioc.get(controllerClassName), paramValues);
if (object != null) {
if (method.isAnnotationPresent(MyResponseBody.class)) {
response.setHeader("content-type", "application/json;charset=UTF-8");
if (null == responseBodyHandler) {
object = JSONObject.toJSONString(object, SerializerFeature.WriteMapNullValue);
} else {
object = responseBodyHandler.equals(object);
}
}
response.getWriter().print(object);
logger.debug("request-> " + request.getRequestURI() + ", response success ->" + response.getStatus());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} }
} /****
* @MyRequestParam
* 参数解析 复制
* @注意: 参数解析暂不完整 int float long double boolean string
* 实体接收暂不支持
* @param request
* @param response
* @param method
* @return
*/
private Object[] getMethodParamAndValue(HttpServletRequest request, HttpServletResponse response, Method method) {
Parameter[] parameters = method.getParameters();
Object[] paramValues = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) { if (ServletRequest.class.isAssignableFrom(parameters[i].getType())) {
paramValues[i] = request;
} else if (ServletResponse.class.isAssignableFrom(parameters[i].getType())) {
paramValues[i] = response;
} else {
String bindingValue = parameters[i].getName();
if (parameters[i].isAnnotationPresent(MyRequestParam.class)) {
bindingValue = parameters[i].getAnnotation(MyRequestParam.class).value();
}
String paramValue = request.getParameter(bindingValue);
paramValues[i] = paramValue;
if (paramValue != null) {
if (Integer.class.isAssignableFrom(parameters[i].getType())) {
paramValues[i] = Integer.parseInt(paramValue);
} else if (Float.class.isAssignableFrom(parameters[i].getType())) {
paramValues[i] = Float.parseFloat(paramValue);
} else if (Double.class.isAssignableFrom(parameters[i].getType())) {
paramValues[i] = Double.parseDouble(paramValue);
} else if (Long.class.isAssignableFrom(parameters[i].getType())) {
paramValues[i] = Long.parseLong(paramValue);
} else if (Boolean.class.isAssignableFrom(parameters[i].getType())) {
paramValues[i] = Boolean.parseBoolean(paramValue);
}
}
}
}
return paramValues;
} /****
* 初始化
* @param contextConfigLocation
* @throws Exception
*/
private void initMyDispatcherServlet(String contextConfigLocation) throws Exception {
logger.info("-----------------------------mySpring init start-----------------------------------------");
logger.debug("doLoadConfig:" + contextConfigLocation);
//加载配置
doLoadConfig(contextConfigLocation);
//扫描 包扫描
logger.debug("scan:" + contextConfig.getProperty("scan.package"));
doScanner(contextConfig.getProperty("scan.package"));
//创建实体类、ioc
doInstance();
//注入 di
doAutowired();
//url 映射
initHandlerMapping(); } /***
* 注入
*/
private void doAutowired() {
if (ioc.isEmpty()) {
return;
}
for (Map.Entry<String, Object> entry : ioc.entrySet()) {
Object object = entry.getValue();
Field[] fields = object.getClass().getDeclaredFields();
for (Field filed : fields) {
if (filed.isAnnotationPresent(MyAutowired.class)) {
MyAutowired myAutowired = filed.getAnnotation(MyAutowired.class);
String key = filed.getType().getName();
String val = myAutowired.value();
if (val != null && "".equals(val.trim())) {
key = val.trim();
}
filed.setAccessible(true);
try {
filed.set(object, ioc.get(key));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
continue;
}
}
}
} /***
* 初始化HandlerMapper
*/
private void initHandlerMapping() {
if (ioc.isEmpty()) {
return;
}
for (Map.Entry<String, Object> entry : ioc.entrySet()) {
Object object = entry.getValue();
Class<?> clazz = object.getClass();
if (clazz.isAnnotationPresent(MyController.class)) {
Method[] methods = clazz.getDeclaredMethods();
MyRequestMapping requestMapping = clazz.getAnnotation(MyRequestMapping.class);
String crlRequstMapping = requestMapping.value() == null ? "" : requestMapping.value();
for (Method method : methods) {
if (method.isAnnotationPresent(MyRequestMapping.class)) {
String url = ("/" + crlRequstMapping + "/" + method.getAnnotation(MyRequestMapping.class).value()).replaceAll("/+", "/");
// check request url must only
if (handlerMapping.containsKey(url)) {
logger.error("mapping request url:" + url + "is already exist! request url must only");
new Exception("mapping:" + url + "is already exist!");
}
handlerMapping.put(url, method);
logger.debug("mapping: " + url);
} else {
continue;
}
}
} }
} /***
* 加载配置文件
* @param contextConfigLocation
* @throws Exception
*/
private void doLoadConfig(String contextConfigLocation) throws Exception {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
if (is == null) {
logger.error("config:" + contextConfigLocation + " not exist");
throw new Exception("config:" + contextConfigLocation + " not exist");
} else {
try {
contextConfig.load(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
//关流
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
} /****
* 包扫描
* @param packageName
* @throws Exception
*/
private void doScanner(String packageName) throws Exception {
if (packageName == null || packageName.length() == 0) {
throw new Exception("init scan is empty");
} URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
if (null != url) {
File dir = new File(url.getFile());
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
//递归读取包
doScanner(packageName + "." + file.getName());
} else {
String className = packageName + "." + file.getName().replace(".class", "");
logger.debug("scan class find:" + className);
classNames.add(className);
}
}
} } /****
* ioc实例化
*/
private void doInstance() {
if (classNames.isEmpty()) {
return;
}
for (String className : classNames) {
try {
// @MyController instance
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(MyController.class)) {
logger.debug("MyController instance: " + clazz.getName());
ioc.put(toFirstWordLower(clazz.getSimpleName()), clazz.newInstance());
} else if (clazz.isAnnotationPresent(MyService.class)) {
//todo @MyService instance
// 1 以自己本类或者用户自定义别名为key
Object newInstance = clazz.newInstance();
String key = toFirstWordLower(clazz.getSimpleName());
logger.debug("MyService instance: " + clazz.getName());
MyService service = clazz.getAnnotation(MyService.class);
String value = service.value().trim();
if (!"".equals(value)) {
key = value;
}
if (!ioc.containsKey(key)) {
ioc.put(key, newInstance);
} else {
logger.error("MyService instance: " + service.value() + " is exist");
throw new Exception("MyService instance: " + service.value() + " is exist");
}
//2 以所继承的接口为 key
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> interClazz : interfaces) {
ioc.put(interClazz.getName(), clazz.newInstance());
} } else if (clazz.isAnnotationPresent(MyResponseAdvice.class)) {
if (clazz.isAssignableFrom(ResponseBodyHandler.class)) {
if (null != responseBodyHandler) {
continue;
}
responseBodyHandler = (ResponseBodyHandler) clazz.newInstance();
} else {
logger.error("class+'" + clazz.getName() + "' must implement ResponseBodyHandler");
throw new Exception("class+'" + clazz.getName() + "' must implement ResponseBodyHandler");
}
} else {
continue;
} } catch (Exception e) {
e.printStackTrace();
continue;
}
}
} /**
* 把字符串的首字母小写
*
* @param name
* @return
*/
private String toFirstWordLower(String name) {
char[] charArray = name.toCharArray();
charArray[0] += 32;
return String.valueOf(charArray);
} }

TestController:

import cn.lyh.mySpring.annotation.*;
import cn.lyh.mySpringTest.domain.User;
import cn.lyh.mySpringTest.service.TestService; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*; @MyController
@MyRequestMapping("/test")
public class TestController {
@MyAutowired
private TestService testService; @MyRequestMapping("test1")
public String test1(@MyRequestParam("name") String name,
@MyRequestParam("sex") Integer sex,
HttpServletRequest request,
HttpServletResponse response) throws IOException { return "name=" + name + "sex=" + sex;
} @MyRequestMapping("test2")
public void test2() { } @MyRequestMapping("test3")
@MyResponseBody
public Map<String, Object> test3(@MyRequestParam("name") String name,
@MyRequestParam("sex") Integer sex,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
Map<String, Object> result = new HashMap<>();
result.put("name", name);
result.put("sex", name); return result;
} @MyRequestMapping("test4")
@MyResponseBody
public User test4(@MyRequestParam("name") String name,
@MyRequestParam("sex") Integer sex,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
User user = new User();
user.setName(name);
user.setId(sex); return user;
} @MyRequestMapping("test5")
@MyResponseBody
public List test5(@MyRequestParam("name") String name,
@MyRequestParam("sex") Integer sex,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
List list = new ArrayList();
User user = new User();
user.setName(name);
user.setId(sex);
list.add(user); return list;
} @MyRequestMapping("test6")
@MyResponseBody
public List test5(HttpServletRequest request,
HttpServletResponse response) throws IOException {
List list = new ArrayList();
User user = new User();
user.setName(null);
user.setId(1);
list.add(user); return list;
} }

pom文件依赖:

 <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
<scope>compile</scope>
</dependency>

最后附上源码地址(MySpring Moudle)

最新文章

  1. JS常用正则表达式和JS控制输入框输入限制(数字、汉字、字符)
  2. ubuntu 常见问题
  3. September 24th 2016 Week 39th Saturday
  4. Coursera台大机器学习课程笔记11 -- Nonlinear Transformation
  5. MFC六大核心机制之二:运行时类型识别(RTTI)
  6. oracle切割字符串后以单列多行展示
  7. $.each()方法详解
  8. jvm GC
  9. Node.js使用supervisor遭遇‘supervisor’不是内部或外部命令,如果解决?
  10. Java(18) 集合框架
  11. Linux - 文件和目录常用命令
  12. mysql 导入sql 2006 - mysql server has gone away 导入
  13. JavaScript原型与闭包相关
  14. TCP/IP 笔记 - 域名解析和域名系统
  15. 26-Python3 面向对象
  16. table可拖拽改变宽度
  17. HDU 5245 Joyful(期望)
  18. JQuery Mobile - 处理图片加载失败!
  19. 20172301 《Java软件结构与数据结构》实验二报告
  20. 视图控制器生命周期中各个重要的方法(Swift) (Important Methods during the Lifecycle of a View Controller)

热门文章

  1. python 模块——os 模块
  2. kbmmw 5.08 正式发布
  3. 2T以上磁盘格式化
  4. Spring RestTemplate get post 请求 携带 headers
  5. Stanford CS20学习笔记
  6. IE兼容问题 动态生成的节点IE浏览器无法触发
  7. spring BeanWrapperImpl方便的嵌套属性(list)操作
  8. python 递归实现汉诺塔算法
  9. Astrology PHP 框架
  10. jQuery事件学习