1.dispatcher
继承HttpServlet ,重写 init() , doGet() ,doPost()方法,主要通过 反射
package org.com.dispatcherservlet;
import org.com.annotation.*;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
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.annotation.Annotation;
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.*;
import java.util.regex.Pattern;
/**
* @Author: zx
* @Date:
*/
public class MyDsipatcherServlet extends HttpServlet {
private Properties properties = new Properties();
private static final String LOCATION = "contextConfigLocation";
private ServletConfig config;
/**
* 存放类名
*/
private List<String> classNames = new ArrayList<String>();
/**
* ioc
*/
private Map<String , Object> iocMap = new HashMap<>();
/**
* url 映射 到控制器
*/
private Map<String , Handler> mapping = new HashMap<>();
/**
* 控制器
*/
private class Handler{
protected Object controller; //保存方法对应的实例
protected Method method; //保存映射的方法
protected Pattern pattern; //路径
protected Map<String,Integer> paramIndexMapping; //参数顺序 基本传入参数
public Handler(Object controller, Method method, Pattern pattern) {
this.controller = controller;
this.method = method;
this.pattern = pattern;
paramIndexMapping = new HashMap<String,Integer>();
this.putParamIndexMapping(method);
}
private void putParamIndexMapping(Method method) {
//所有参数列
Parameter[] parameters = method.getParameters();
//spring自带 查class文件 拿到 入参名称
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = u.getParameterNames(method);
//参数的名称
Class<?>[] parameterTypes = method.getParameterTypes();
int num = 0;
for (Parameter parameter : parameters) {
Annotation[] annotations = parameter.getDeclaredAnnotations();
if(annotations != null && annotations.length > 0 ){
for (Annotation annotation : annotations) {
Class<? extends Annotation> aClass = annotation.annotationType();
//指定参数 并且有设置value
if(aClass == MyRequestParam.class){
String paramName = ((MyRequestParam) annotation).value();
if("" != paramName) paramIndexMapping.put(paramName , num);
}
}
}else{
paramIndexMapping.put(parameterNames[num], num);
}
num++;
}
}
public Object invoke(Object...args) throws InvocationTargetException, IllegalAccessException {
return method.invoke(this.controller , args);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req , resp);
return;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//开始始匹配到对应的方方法
try {
doDispatch(req , resp);
}catch (Exception e){
e.printStackTrace();
resp.getWriter().write("500 error");
}
return;
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
if(mapping.isEmpty()){ return;}
Handler handler = doHandler(req, resp);
if(handler==null){
resp.getWriter().write("404 Not page");
return;
}
try {
//获取方法的参数列表
Map<String, Integer> paramIndexMapping = handler.paramIndexMapping;
//保存所有需要自动赋值的参数值
Object [] paramValues = new Object[paramIndexMapping.size()];
//获取方法的参数类型列表
Class<?> [] paramTypes = handler.method.getParameterTypes();
//request参数
Map<String,String[]> params = req.getParameterMap();
for (Map.Entry<String, String []> param : params.entrySet()) {
String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
//如果找到匹配的对象,则开始填充参数值
if(!handler.paramIndexMapping.containsKey(param.getKey())){continue;}
int index = handler.paramIndexMapping.get(param.getKey());
paramValues[index] = convert(paramTypes[index] , value);
}
if(paramIndexMapping.containsKey("request")){
Integer reqIndex = paramIndexMapping.get("request");
paramValues[reqIndex] = req;
}
if(paramIndexMapping.containsKey("response")){
Integer respIndex = paramIndexMapping.get("response");
paramValues[respIndex] = resp;
}
Object invoke = handler.invoke(paramValues);
resp.getWriter().write(invoke.toString());
return;
}catch (Exception e){
e.printStackTrace();
resp.getWriter().write("500 error");
return;
}
}
private Object convert(Class<?> paramType, String value) {
if(int.class == paramType){
return Integer.valueOf(value);
}
return value;
}
/**
* 获取handler
*/
public Handler doHandler(HttpServletRequest req, HttpServletResponse resp){
String url = req.getRequestURI();
//上下文路径
String contextPath = req.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
if(mapping.containsKey(url)){
return mapping.get(url);
}
return null;
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.config = servletConfig;
//加载配置文件
loadConfig(servletConfig.getInitParameter(LOCATION));
//扫描类
scanPackage(properties.getProperty("scanPackage"));
//初始化扫描到的类
doInstance();
//完成依赖注入
doAutoWired();
//初始化HandlerMapping
initHandlerMapping();
super.init();
System.out.println("初始化完成-----------------------------------");
}
private void initHandlerMapping() {
//初始化 url映射关系
for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
//controller组装映射
Class<?> aClass = entry.getValue().getClass();
MyController annotation = aClass.getDeclaredAnnotation(MyController.class);
if(annotation != null){
MyRequestMapping baseMapping = aClass.getDeclaredAnnotation(MyRequestMapping.class);
String baseUrl = baseMapping.value();
//获取类 url 配置
//获取Method的url配置
Method [] methods = aClass.getMethods();
for (Method method : methods) {
//没有加RequestMapping注解的直接忽略
if(!method.isAnnotationPresent(MyRequestMapping.class)){ continue; }
//映射URL
MyRequestMapping methodtMapping = method.getDeclaredAnnotation(MyRequestMapping.class);
if(methodtMapping!=null){
// 组装url:/baseUrl/methodUrl
String regex = ("/" + baseUrl + "/" + methodtMapping.value()).replaceAll("/+", "/");
if(!mapping.containsKey(regex)){
mapping.put(regex , new Handler(entry.getValue() , method , Pattern.compile(regex)));
}else{
throw new RuntimeException("500 requestMapping conflict");
}
}
}
}
}
}
private void doAutoWired(){
if(iocMap.isEmpty()){return;}
for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
//获取所有字段
Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();
System.out.println(declaredFields.length);
for (Field field : declaredFields) {
//判断字段是否需要注入
if(!field.isAnnotationPresent(MyAutowired.class)){continue;}
MyAutowired declaredAnnotation = field.getDeclaredAnnotation(MyAutowired.class);
String beanName = declaredAnnotation.value();
if(declaredAnnotation != null){
if("".equals(beanName)){
beanName = field.getType().getName();
}
}
try {
field.setAccessible(true);
field.set(entry.getValue() , iocMap.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private void doInstance() {
//初始化ioc容器
if(classNames == null || classNames.size() == 0){return;}
classNames.stream().forEach(e ->{
try {
Class<?> aClass = Class.forName(e);
if(aClass.isAnnotationPresent(MyController.class)){
//controller 注解
Object iocObject = aClass.newInstance();
String beanName = toLowerFirstCase(e);
iocMap.put(beanName , iocObject);
}else if(aClass.isAnnotationPresent(MyService.class)){
//controller 注解
Object iocObject = aClass.newInstance();
//看是否设置service名称
MyService service = aClass.getAnnotation(MyService.class);
String beanName = service.value();
if("" == beanName.trim() ){
beanName = toLowerFirstCase(e);
iocMap.put(beanName , iocObject);
}else{
//如果自己没设,就按接口类型创建一个实例
Class<?>[] interfaces = aClass.getInterfaces();
for (Class<?> i : interfaces) {
beanName = toLowerFirstCase(e);
iocMap.put(i.getName(), iocObject);
}
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
});
System.out.println();
}
private String toLowerFirstCase(String e) {
char[] chars = e.toCharArray();
//大小写字母相差32
chars[0] += 32;
return String.valueOf(chars);
}
private void scanPackage(String scanPackage) {
//获取编译后
URL resource = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
File dir = new File(resource.getFile());
File[] files = dir.listFiles();
for (File f : files) {
if(f.isDirectory()){
scanPackage(scanPackage + '.' + f.getName() );
}else{
String className = f.getName();
if(className.endsWith(".class")){
classNames.add( scanPackage + "." + className.replace(".class" , "").trim());
}
}
}
}
private void loadConfig(String initParameter) {
InputStream in = null;
try {
in = this.getClass().getClassLoader().getResourceAsStream(initParameter);
properties.load(in);
}catch (Exception e){
e.printStackTrace();
}finally{
try {
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
2.注解
package org.com.annotation;
import java.lang.annotation.*;
/**
* @author zx
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
String value() default "";
}
/**
* @author zx
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
String value() default "";
}
/**
* @author zx
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
}
/**
* @author zx
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestParam {
String value() default "";
}
/**
* @author zx
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}
3.controller
/**
* @Author: zx
* @Date:
*/
@MyRequestMapping(value = "/hellow")
@MyController
public class HellowController {
@MyAutowired
private HellowService hellowService;
@MyRequestMapping(value = "/getHellowList")
public String getHellow(HttpServletRequest request , HttpServletResponse response , @MyRequestParam(value = "name") String name , int age){
return "My zx";
}
}