原创

手写spring代码

package mvcframework.servlet;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;

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 GPDispatcherServlet extends HttpServlet {

private Properties contextConfig = new Properties();

private List<String> classNmmes = new ArrayList<>();

private Map<String,Object> ioc = new HashMap<>();

private Map<String,Method> handlerMapping = new HashMap<>();

@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.执行,调度
try {
doDispatch(req,resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500 Exception Detail : " + Arrays.toString(e.getStackTrace()));
}
}

private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception{
String uri = req.getRequestURI();
String contextPath = req.getContextPath();
uri = uri.replaceAll(contextPath,"").replaceAll("/+","/");

if(!this.handlerMapping.containsKey(uri)){
resp.getWriter().write("404 Not Found!!");
}

Method method = this.handlerMapping.get(uri);

Map<String, String[]> params = req.getParameterMap();

String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());

Object bean = ioc.get(beanName);

method.invoke(bean, new Object[]{req,resp,params.get("name")});
}

@Override
public void init(ServletConfig config) throws ServletException {

//1.加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));

//2.扫描包路径,提取相关的类
doScanner(contextConfig.getProperty("scanPackage"));

//3.初始化ioc,并且将扫描到的所有的类实例化放入到ioc容器之中
doInstance();

//4.完成依赖注入
doAutowired();

//5.初始化HandlerMapper,建立URL和Controller映射
doInitHandlerMapping();

System.out.println("GP Spring framework is init...");
}

private void doInitHandlerMapping() {
if(ioc.isEmpty()){
return;
}

for (Map.Entry<String, Object> entry : ioc.entrySet()) {
//获取所有的Public方法
Method[] methods = entry.getValue().getClass().getMethods();
//判断是否是controller注解
if(!entry.getValue().getClass().isAnnotationPresent(Controller.class)){
continue;
}
//类上面的requestmapping
String baseUrl = "";
if (entry.getValue().getClass().isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = entry.getValue().getClass().getAnnotation(RequestMapping.class);
baseUrl = requestMapping.value()[0];
}

for (Method method : methods) {
if(!method.isAnnotationPresent(RequestMapping.class)){
continue;
}

RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
//替换多的斜杠,只保留一个斜杠
String url = ("/" + baseUrl + "/" + requestMapping.value()[0]).replace("/+","/");
if(handlerMapping.containsKey(url)){
try {
throw new Exception("url already exists..");
} catch (Exception e) {
e.printStackTrace();
}
}
handlerMapping.put(url,method);

System.out.println("Mapped " + url + "," + method);
}
}
}

private void doAutowired() {
if(ioc.isEmpty()){
return;
}

for (Map.Entry<String, Object> entry : ioc.entrySet()) {
//得到所有对象的属性字段,获取所有的字段包含private(Declared)
Field[] fields = entry.getValue().getClass().getDeclaredFields();
//扫描,编码规范,尽量不要超过三层嵌套
for (Field field : fields) {
if(!field.isAnnotationPresent(Autowired.class)){
continue;
}
Autowired autowired = field.getAnnotation(Autowired.class);
String beanName = autowired.toString();
if("".equals(beanName)){
//获取字段的类型的名称
beanName = field.getType().getName();
}
//私有的field进行强制访问
field.setAccessible(true);
try {
//用的是反射
//xx = ioc.get(beanName);
field.set(entry.getValue(),ioc.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
continue;
}


}
}
}

private void doInstance() {
if (classNmmes.isEmpty()) {
return;
}

try{
for (String classNmme : classNmmes) {
Class<?> clazz = Class.forName(classNmme);
//此处的controller和service是可以自己些aop的,教程里面是老师自己写的
if(clazz.isAnnotationPresent(Controller.class)) {
String beanName = toLowerFirstCase(clazz.getSimpleName());
Object instance = clazz.newInstance();
ioc.put(beanName,instance);
}else if(clazz.isAnnotationPresent(Service.class)){

//1:默认是类名首字母小写
String beanName = toLowerFirstCase(clazz.getSimpleName());

//2.不同包 下类名相同,注解派上用场,自定义类名
Service service = clazz.getAnnotation(Service.class);
if("".equals(service.value())){
beanName = service.value() ;
}
Object instance = clazz.newInstance();
ioc.put(beanName, instance);

//3.根据接口类型,要实例化接口的实现类
for (Class<?> i : clazz.getInterfaces()) {
if(ioc.containsKey(i.getName())){
throw new Exception("The beanName is exists!");
}
ioc.put(i.getName(),instance);
}
}else{
continue;
}
}
}catch (Exception e){
e.printStackTrace();
}
}
//首字母大写转换小写
private String toLowerFirstCase(String simpleName) {
char [] chars = simpleName.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}

private void doScanner(String scanPackage) {
URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
File classpath = new File(url.getFile());

for (File file : classpath.listFiles()) {
if(file.isDirectory()){
doScanner(scanPackage + "." + file.getName());
}else{
//等会儿可以使用Class.forName()方法可有找到下一层
if(!file.getName().endsWith(".class")){
continue;
}
String className = (scanPackage + "." + file.getName()).replace(".class", "");
classNmmes.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();
}
}
}

}
}

自己记录使用

此代码未经过测试,仅仅限于思路

正文到此结束
本文目录