一简介
相较于2.0版本,3.0版本更接近SpringMVC的源码,更符合开闭原则,最少知识原则。
二.废话少说,上代码
改变的地方
一.Controller层
二.DispatcherServlet类(核心)
public class DDispatcherServlet3 extends HttpServlet {
/*保存Properties中的内容*/
private Properties contextConfig=new Properties();
/*保存扫描到的所有类名*/
private List<String> classNames=new ArrayList<>();
/* 准备IOC容器*/
private Map<String,Object> ioc=new ConcurrentHashMap<>();
/*url映射容器*/
private List<HandlerMapping> handlerMapping=new ArrayList<>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//6.调用,运行阶段
try {
doDispatcher(req,resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500"+Arrays.toString(e.getStackTrace()));
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//6.调用,运行阶段
try {
doDispatcher(req,resp);
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("500"+Arrays.toString(e.getStackTrace()));
}
}
private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) throws IOException, InvocationTargetException, IllegalAccessException {
HandlerMapping hasHandler= getHandler(req);
if (null==hasHandler){
resp.getWriter().write("404");
}
//获得形参列表
Class<?>[] paramTypes = hasHandler.getParamTypes();
Object[] paramValues=new Object[paramTypes.length];
Map<String, String[]> params = req.getParameterMap();
for (Map.Entry<String, String[]> param : params.entrySet()) {
String methodName = convert(param.getKey());
if (!hasHandler.getParamIndexMap().containsKey(methodName)){
continue;
}
Integer index = hasHandler.getParamIndexMap().get(param.getKey());
String[] value = param.getValue();
String newValue = convert(value);
paramValues[index] =convert(paramTypes[index],newValue);
}
if(hasHandler.getParamIndexMap().containsKey(HttpServletRequest.class.getName())) {
int reqIndex = hasHandler.getParamIndexMap().get(HttpServletRequest.class.getName());
paramValues[reqIndex] = req;
}
if(hasHandler.getParamIndexMap().containsKey(HttpServletResponse.class.getName())) {
int respIndex = hasHandler.getParamIndexMap().get(HttpServletResponse.class.getName());
paramValues[respIndex] = resp;
}
Method method = hasHandler.getMethod();
method.setAccessible(true);
Object returnValue = method.invoke(hasHandler.getController(),paramValues);
if(returnValue == null || returnValue instanceof Void){ return; }
resp.getWriter().write(returnValue.toString());
}
private HandlerMapping getHandler(HttpServletRequest req) {
String url = req.getRequestURI();
//处理成相对路径
String contextPath = req.getContextPath();
url=url.replaceAll(contextPath,"").replaceAll("/+","/");
for (int i = 0; i < handlerMapping.size(); i++) {
if (url.equals(handlerMapping.get(i).getUrl())){
return handlerMapping.get(i);
}
}
return null;
}
/**
* url都是字符串
*/
private Object convert(Class<?> type,String value){
value = value.replaceAll("\\[|\\]","")
.replaceAll("\\s",",");
if (Integer.class==type){
return Integer.valueOf(value);
}
return value;
}
private String convert(String... value){
String newValue = Arrays.toString(value).replaceAll("\\[|\\]", "")
.replaceAll("\\s", ",");
return newValue;
}
/**
* 初始化阶段
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
//1.加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
// 2.扫描相关类
doScanner(contextConfig.getProperty("scanPackage"));
//3.初始化扫描到的类,并放入ioc中
DoInstance();
//4.完成依赖注入
doAutoWired();
//5.初始化HandlerMapping
initHandlerMapping();
System.out.println("D Spring frame is init");
}
/**
* 初始化url和Method的一对一关系
*/
private void initHandlerMapping() {
if (ioc.isEmpty()){
return;
}
Set<Map.Entry<String, Object>> entries = ioc.entrySet();
for (Map.Entry<String, Object> entry : entries) {
Class<?> clazz = entry.getValue().getClass();
if (!clazz.isAnnotationPresent(DController.class)){
continue;
}
//保存写在类上的url
String baseUrl="/";
if (clazz.isAnnotationPresent(DController.class)){
DRequestMapping requestMapping = clazz.getAnnotation(DRequestMapping.class);
baseUrl += requestMapping.value();
}
//获取所有public的方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (!method.isAnnotationPresent(DRequestMapping.class)){
continue;
}
DRequestMapping methodMapping = method.getAnnotation(DRequestMapping.class);
//如果出现多个斜杆,替换成一个
String url=(baseUrl+"/"+methodMapping.value()).replaceAll("/+","/");
//放入映射容器
handlerMapping.add(new HandlerMapping(url,method,entry.getValue()));
System.out.println("url:"+url+":"+method.toString());
}
}
}
private void doAutoWired() {
if (ioc.isEmpty()){
return;
}
Set<Map.Entry<String, Object>> entries = ioc.entrySet();
for (Map.Entry<String, Object> entry : entries) {
//获得一个对象的所有方法
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(DAutowired.class)){
DAutowired autowired = field.getAnnotation(DAutowired.class);
String beanName = autowired.value().trim();
//如果注解默认值为空,则根据类型注入
if ("".equals(beanName)){
beanName=field.getType().getName();
}
//赋值
try {
field.setAccessible(true);
field.set(entry.getValue(),ioc.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
private void DoInstance() {
//初始化,为DI做准备
if (classNames.isEmpty()){return;}
for (String className : classNames) {
try {
Class<?> clazz = Class.forName(className);
//加了注解的类需要初始化,这里只举例几个注解
if (clazz.isAnnotationPresent(DController.class)){
Object instance = clazz.getDeclaredConstructor().newInstance();
//类名首字母小写
String beanName = toLowerFirstCase(clazz.getSimpleName());
ioc.put(beanName,instance);
}else if (clazz.isAnnotationPresent(DService.class)){
DService service = clazz.getAnnotation(DService.class);
//1.自定义beanName
// 获得该注解的默认值
String beanName = service.value();
//2.默认类名首字母小写
if ("".equals(beanName.trim())){
beanName = toLowerFirstCase(clazz.getSimpleName());
}
Object instance = clazz.getDeclaredConstructor().newInstance();
//3.根据类型自动注入,扫描该类的所有接口
for (Class<?> i:clazz.getInterfaces()){
//防止使用相同key名
if (ioc.containsKey(i.getName())){
throw new Exception(i.getName()+"该类实例已存在,请更换名字");
}
ioc.put(i.getName(),instance);
}
}else {
continue;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private String toLowerFirstCase(String simpleName) {
char[] chars = simpleName.toCharArray();
//大小写字母ASCII码相差32
if (chars[0]>=65&&chars[0]<=90){
//说明是一个大写字母
chars[0] +=32;
}
return String.valueOf(chars);
}
//扫描相关类
private void doScanner(String scanPackage) {
//转化成文件路径:classpath,注意双亲委派机制
URL url = this.getClass().getClassLoader().getResource(scanPackage.replaceAll("\\.","/"));
File classpath = new File(url.getFile());
File[] files = classpath.listFiles();
for (File file : files) {
if (file.isDirectory()){
doScanner(scanPackage+"."+file.getName());
}else {
if (!file.getName().endsWith(".class")){continue;}
//得到完整的类名
String className=(scanPackage+"."+file.getName().replace(".class",""));
//保存到容器中
classNames.add(className);
}
}
}
/**
* 加载配置文件
* @param contextConfigLocation
*/
private void doLoadConfig(String contextConfigLocation) {
InputStream fis=null;
//直接从类路径下找到Spring主配置文件所在路径
//将properties文件放到Properties对象中
fis=this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
try {
contextConfig.load(fis);
} catch (IOException e) {
e.printStackTrace();
}finally {
if (null!=fis){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
三.HandlerMapping类
public class HandlerMapping {
private String url;
private Method method;
private Object controller;
private Class<?>[] paramTypes;
/**
* 保存参数的名称和索引
*/
private Map<String,Integer> paramIndexMap;
public HandlerMapping(String url, Method method, Object controller) {
this.url = url;
this.method = method;
this.controller = controller;
//初始化参数类型
this.paramTypes= method.getParameterTypes();
paramIndexMap=new HashMap<>();
putParamIndexMap(method);
}
public Map<String, Integer> getParamIndexMap() {
return paramIndexMap;
}
private void putParamIndexMap(Method method) {
//拿到方法上的参数注解,一个字段可以有多个注解
Annotation[][] annotations = method.getParameterAnnotations();
for (int i = 0; i < annotations.length; i++) {
for (Annotation annotation:annotations[i]){
//获取参数上的注解
DRequestParam requestParam = (DRequestParam) annotation;
if (requestParam instanceof DRequestParam){
String paramName = requestParam.value();
if (!"".equals(paramName.trim())){
paramIndexMap.put(paramName,i);
}
}
}
}
//提取方法中的request和response参数
Class<?> [] paramsTypes = method.getParameterTypes();
for (int i = 0; i < paramsTypes.length ; i ++) {
Class<?> type = paramsTypes[i];
if(type == HttpServletRequest.class ||
type == HttpServletResponse.class){
paramIndexMap.put(type.getName(),i);
}
}
}
public Class<?>[] getParamTypes() {
return paramTypes;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object getController() {
return controller;
}
public void setController(Object controller) {
this.controller = controller;
}
}
其他地方没有做改变,参考2.0版本
手写SpringMVC2.0版本