1.Spring主要分为以下几个主要的阶段
2:创建一个maven web项目(省略)
3 :添加servlet依赖
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
4.配置web.xml
<!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>testDispatcherServlet</servlet-name>
<servlet-class>com.test.mvcframework.servlet.TestDispatcherServlet</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>testDispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
5.创建注解:TestController,TestAuware,TestRequestMapping,TestRequestParam,TestService
package com.test.mvcframework.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestController {
String value() default "";
}
package com.test.mvcframework.annotation;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAuware {
String value() default "";
}
package com.test.mvcframework.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestRequestMapping {
String value() default "";
}
package com.test.mvcframework.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestRequestParam {
String value() default "";
}
package com.test.mvcframework.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestService {
String value() default "";
}
6.创建service以及实现类 TestServiceI,TestServiceImpl
package com.test.demo.service;
public interface TestServiceI {
public String get(String name);
}
package com.test.demo.service.impl;
import com.test.demo.service.TestServiceI;
import com.test.mvcframework.annotation.TestService;
@TestService
public class TestServiceImpl implements TestServiceI {
@Override
public String get(String name) {
return "myName is:"+name;
}
}
7.创建Action : TestAction
package com.test.demo.mvc.action;
import com.test.demo.service.TestServiceI;
import com.test.mvcframework.annotation.TestAuware;
import com.test.mvcframework.annotation.TestController;
import com.test.mvcframework.annotation.TestRequestMapping;
import com.test.mvcframework.annotation.TestRequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@TestController
@TestRequestMapping("/demo")
public class TestAction {
@TestAuware
private TestServiceI testService;
@TestRequestMapping("/query.json")
public void query(HttpServletRequest request, HttpServletResponse response, @TestRequestParam String name){
String s = testService.get(name);
try {
response.getWriter().write(s);
} catch (IOException e) {
e.printStackTrace();
}
}
}
8.编写核心代码:TestDispatcherServlet
package com.test.mvcframework.servlet;
import com.test.mvcframework.annotation.TestAuware;
import com.test.mvcframework.annotation.TestController;
import com.test.mvcframework.annotation.TestRequestMapping;
import com.test.mvcframework.annotation.TestService;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
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.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
public class TestDispatcherServlet 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> handlerMapping = new HashMap<String,Method>();
@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 {
try {
doDispatch(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp)throws Exception {
if(handlerMapping.isEmpty()){return;}
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replace(contextPath, "");
if(!handlerMapping.containsKey(url)){
resp.getWriter().write("404 Not Found");
return;
}
Method method = handlerMapping.get(url);
System.out.print("执行的方法名称是:"+method.getName());
//todo 最后有待完善的是doDispatch方法的invoke方法的执行
}
@Override
public void init(ServletConfig config) throws ServletException {
//1.加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
//2.扫描所有相关联的类
doScanner(contextconfig.getProperty("scanPackage"));
//3.初始化所有相关联的类,并且将其保存到IOC容器中
doInstance();
//4.实现自动化依赖注入DI
doAutoware();
//5.初始化HandlerMapping
initHandlerMapping();
}
private void initHandlerMapping() {
if(ioc.isEmpty()){return;}
for(Map.Entry<String,Object> entry :ioc.entrySet()){
Class<?> clazz = entry.getValue().getClass();
if(!clazz.isAnnotationPresent(TestController.class)){continue;}
String baseUrl = "";
if(clazz.isAnnotationPresent(TestRequestMapping.class)){
TestRequestMapping testRequestMapping = clazz.getAnnotation(TestRequestMapping.class);
baseUrl = testRequestMapping.value();
}
for(Method method :clazz.getMethods()){
if(!method.isAnnotationPresent(TestRequestMapping.class)){
return;
}
TestRequestMapping testRequestMapping = method.getAnnotation(TestRequestMapping.class);
String url = baseUrl+testRequestMapping.value();
handlerMapping.put(url,method);
}
}
}
private void doAutoware() {
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(TestAuware.class)){
return;
}
TestAuware testAuware = field.getAnnotation(TestAuware.class);
String beanName = testAuware.value().trim();
if("".equals(beanName)){
beanName = field.getType().getName();
}
field.setAccessible(true);
try {
//赋值
field.set(entry.getValue(),ioc.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private void doInstance() {
if(classNames.isEmpty()){
return;
}
for (String className :classNames){
try {
Class<?> clazz = Class.forName(className);
if(clazz.isAnnotationPresent(TestController.class)){
String beanName = lowerFirstCase(clazz.getSimpleName());
ioc.put(beanName,clazz.newInstance());
}else if(clazz.isAnnotationPresent(TestService.class)){
//key的规则 1.默认类名搜字母小写 2.自定义类名 3.以实现类的实例作为值保存下来
TestService service = clazz.getAnnotation(TestService.class);
String beanName = service.value();
if("".equals(beanName.trim())){
beanName = lowerFirstCase(clazz.getSimpleName());
}
Object instance = clazz.newInstance();
ioc.put(beanName,instance);
//接口实现类的实例
Class<?>[] interfaces = clazz.getInterfaces();
for(Class<?> i :interfaces){
ioc.put(i.getName(),instance);
}
}else {
//没有加注解的类都不需要初始化
continue;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void doScanner(String scanPackage) {
URL url = this.getClass().getClassLoader().getResource("/"+scanPackage.replaceAll("\\.","/"));
File classDir = new File(url.getFile());//com.test.demo下面的所有
for(File file :classDir.listFiles()){
if(file.isDirectory()){//如果是个文件夹就递归读下去
doScanner(scanPackage+"."+file.getName());
}else {
String className = (scanPackage +"."+file.getName().replace(".class",""));
classNames.add(className);
}
}
}
private void doLoadConfig(String contextConfigLocation) {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
try {
contextconfig.load(inputStream);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String lowerFirstCase(String str){
char[] chars = str.toCharArray();
chars[0] += 32; //大小写字母之间相差32个ASCII码值
return String.valueOf(chars);
}
}
9.最后项目验证:http://localhost:8080/demo/query.json