纯手写Spring

所有的操作都以注释的形式添加到了代码中

项目结构如下:

 

annotation包下类为:

package com.dc.annotation;

import java.lang.annotation.*;

/**
* 注解在字段上使用
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DcAutowried {

String value() default "";

}

package com.dc.annotation;

import java.lang.annotation.*;

/**
* 注解在类使用
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DcController {

String value() default "";

}


package com.dc.annotation;

import java.lang.annotation.*;

/**
* 注解在类和方法上使用
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DcRequestBody {

String value() default "";

}


package com.dc.annotation;

import java.lang.annotation.*;

/**
* 注解在类和方法上使用
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DcRequestMapping {

String value() default "";

}


package com.dc.annotation;

import java.lang.annotation.*;

/**
* 注解在类和方法上使用
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DcRequestParam {

String value() default "";

}



package com.dc.annotation;

import java.lang.annotation.*;

/**
* 注解在类使用
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DcService {

String value() default "";

}

controller包下:
package com.dc.controller;

import com.dc.annotation.DcAutowried;
import com.dc.annotation.DcController;
import com.dc.annotation.DcRequestMapping;
import com.dc.service.UserService;

@DcController
@DcRequestMapping("user")
public class UserController {

@DcAutowried
private UserService userService;

@DcRequestMapping("/insertUser")
public void insertUser() {
userService.insertUser();
}

}


service包下为:
package com.dc.service;

public interface UserService {

int insertUser();

}

package com.dc.service.impl;

import com.dc.annotation.DcService;
import com.dc.service.UserService;

@DcService
public class UserServiceImpl implements UserService {

public int insertUser() {
System.out.println("insert user success");
return 1;
}
}

servlet包下为:
package com.dc.servlet;

import com.dc.annotation.DcAutowried;
import com.dc.annotation.DcController;
import com.dc.annotation.DcRequestMapping;
import com.dc.annotation.DcService;

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.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* MVC的入口
*/
public class DcDispatcherServlet extends HttpServlet {
/**
* 存储读取的配置
*/
private Properties contextConfig = new Properties();
/**
* 项目中所有的bean
*/
private Map<String, Object> beanMap = new ConcurrentHashMap<>(256);
/**
* bean名称列表
*/
private List<String> classNames = new ArrayList<>();
/**
* 保存url和方法的映射关系
*/
private Map<String, Method> handleMapping = new ConcurrentHashMap<>(512);

private static final String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
try {
doDispatch(req, resp);
}catch (Exception e) {
e.printStackTrace();
}
}

private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
if (handleMapping.isEmpty()) {
return;
}
String url = req.getRequestURL().toString();
String contextPath = req.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
if (!handleMapping.containsKey(url)) {
resp.getWriter().write("404 Not Found");
return;
}
Method method = handleMapping.get(url);
// 获取方法的参数类型列表
Class<?>[] paramTypes = method.getParameterTypes();
// 获取请求参数
Map<String, String[]> params = req.getParameterMap();
// 保存参数值
Object[] paramValues = new Object[paramTypes.length];
// 方法的参数列表
for (int index = 0; index < paramTypes.length; index++) {
// 根据参数类型
Class paramType = paramTypes[index];
if (paramType == HttpServletRequest.class) {
paramValues[index] = req;
continue;
}
if (paramType == HttpServletResponse.class) {
paramValues[index] = resp;
continue;
}
if (paramType == String.class) {
for (Map.Entry<String, String[]> entry : params.entrySet()) {
String value = Arrays.toString(entry.getValue())
.replaceAll("\\[|\\]", "")
.replaceAll("\\s", ",");
paramValues[index] = value;
}
}
}
String beanName = convertFirstWordToLower(method.getDeclaringClass().getSimpleName());
// 反射机制调用
method.invoke(beanMap.get(beanName), paramValues);
}

@Override
public void init(ServletConfig config) {
// SpringIOC容器的初始化过程;1:定位;2:加载;3:注册
// 定位配置文件
doLocation(config.getInitParameter(CONTEXT_CONFIG_LOCATION));
// 加载配置文件
doLoad(contextConfig.getProperty("scanPackage"));
// 注册
doRegister();
// 依赖注入(DI);在spring中是通过调用getBean()方法触发依赖注入
doAutowired();
// 在SpringMVC中,会有一个HandleMapping
initHandleMapping();
}

/**
* 初始化url的controller.method的映射关系
*/
private void initHandleMapping() {
if (beanMap.isEmpty()) {
return;
}
for (Map.Entry<String, Object> entry : beanMap.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
if (!clazz.isAnnotationPresent(DcController.class)) {
continue;
}
String baseUrl = "";
// 获取Controller上的DcRequestMapping的值
if (clazz.isAnnotationPresent(DcRequestMapping.class)) {
DcRequestMapping dcRequestMapping = clazz.getAnnotation(DcRequestMapping.class);
baseUrl = dcRequestMapping.value();
}
// 获取Method上的DcRequestMapping的值
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (!method.isAnnotationPresent(DcRequestMapping.class)) {
continue;
}
DcRequestMapping dcRequestMapping = method.getAnnotation(DcRequestMapping.class);
String url = ("/" + baseUrl + "/" + dcRequestMapping.value()).replaceAll("/+", "/");
handleMapping.put(url, method);
}
}
}

private void doAutowired() {
if (beanMap.isEmpty()) {
return;
}
String beanName;
for (Map.Entry<String, Object> entry : beanMap.entrySet()) {
// 获取当前类的所有属性
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(DcAutowried.class)) {
continue;
}
DcAutowried dcAutowried = field.getAnnotation(DcAutowried.class);
beanName = dcAutowried.value();
if ("".equals(beanName)) {
beanName = field.getType().getName();
}
field.setAccessible(true);
try {
field.set(entry.getValue(), beanMap.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}

private void doRegister() {
if (classNames.isEmpty()) {
return;
}
String beanName;
try {
for (String className : classNames) {
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(DcController.class)) {
beanName = convertFirstWordToLower(clazz.getSimpleName());
// 在spring中,这个阶段是不会存放实例的,put的是BeanDefinition
// BeanDefinition:将Bean的定义信息存储到BeanDefinition相应的属性中,后面对Bean的操作就直接对BeanDefinition进行
// 例如拿到BeanDefinition后,可以根据里面的类名、构造函数、构造函数参数,使用反射进行对象创建。
beanMap.put(beanName, clazz.newInstance());
} else if (clazz.isAnnotationPresent(DcService.class)); {
DcService dcService = clazz.getAnnotation(DcService.class);
beanName = dcService.value();
if ("".equals(beanName)) {
beanName = convertFirstWordToLower(clazz.getSimpleName());
}
Object instance = clazz.newInstance();
beanMap.put(beanName, instance);
// 该类实现的所有接口,实例统一为该对象
Class<?>[] inters = clazz.getInterfaces();
for (Class<?> inter : inters) {
beanMap.put(inter.getName(), instance);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 加载,扫描当前包下的所有class文件
* @param packageName 包名
*/
private void doLoad(String packageName) {
// 将包路径转换为文件路径
URL url = getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
File classDir = new File(url.getFile());
for (File file : classDir.listFiles()) {
if (file.isDirectory()) {
doLoad(packageName + "." + file.getName());
} else {
// 将当前文件夹下的所有类文件以全路径名的形式存储到List当中
classNames.add(packageName + "." + file.getName().replace(".class", ""));
}
}
}

/**
* 定位
* 在spring中是通过Reader去定位
* @param location 属性文件的位置
*/
private void doLocation(String location) {
InputStream is = getClass().getClassLoader().getResourceAsStream(location.replace("classpath:", ""));
try {
contextConfig.load(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

/**
* 首字母小写
* @return
*/
private String convertFirstWordToLower(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}


}




application.properties配置文件为:
scanPackage=com.dc
htmlRoot=html


web.xml配置为:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

<display-name>dc spring application</display-name>

<servlet>
<servlet-name>dcmvc</servlet-name>
<servlet-class>com.dc.servlet.DcDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dcmvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

</web-app>


 

posted @ 2019-10-16 16:17  dc_xgs  阅读(144)  评论(0编辑  收藏  举报