一、框架解读:
二、源码:
#web.xml
Jason Web Application
jasonmvc
com.jason.spring.framework.webmvc.JasonDispatchServlet
contextConfigLocation
application.properties
1
jasonmvc
/*
package com.jason.spring.framework.webmvc;
import com.jason.spring.framework.annoation.*;
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.Method;
import java.net.URL;
import java.util.*;
/**
* @program: Jason-spring-1.0-ioc
* @description
* @author: 大龄程序猿
* @create: 2020-04-10 20:47
**/
public class JasonDispatchServlet extends HttpServlet {
private Properties contextConfig=new Properties();
public List classNameList=new ArrayList<>();
public Map ioc=new HashMap<>();
public Map handleMapping=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、委派 根据URL隐射对应的handleMapping
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 url=req.getRequestURI();
String contextPath=req.getContextPath();
url=url.replaceAll(contextPath,"").replaceAll("/+","/");
if(!handleMapping.containsKey(url)){
resp.getWriter().write("404 Not Found!!!");
return;
}
Map params=req.getParameterMap();
Method method=handleMapping.get(url);
//获取形参列表
Class> [] parameterTypes = method.getParameterTypes();
Object [] paramValues = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
Class paramterType = parameterTypes[i];
if(paramterType == HttpServletRequest.class){
paramValues[i] = req;
}else if(paramterType == HttpServletResponse.class){
paramValues[i] = resp;
}else if(paramterType == String.class){
//通过运行时的状态去拿到你
Annotation[] [] pa = method.getParameterAnnotations();
for (int j = 0; j < pa.length ; j ++) {
for(Annotation a : pa[i]){
if(a instanceof JasonRequestParam){
String paramName = ((JasonRequestParam) a).value();
if(!"".equals(paramName.trim())){
String value = Arrays.toString(params.get(paramName))
.replaceAll("\\[|\\]","")
.replaceAll("\\s+",",");
paramValues[i] = value;
}
}
}
}
}
}
//暂时硬编码
String beanName = toLowerFirsCase(method.getDeclaringClass().getSimpleName());
//赋值实参列表
System.out.println("ioc.get("+beanName+")="+ioc.get(beanName));
System.out.println("paramValues="+paramValues);
method.invoke(ioc.get(beanName),paramValues);
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("Jason Spring framework init start!");
//1.加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
//2、扫描相关的类
doScanner(contextConfig.getProperty("scanPackage"));
/**********************IOC*******************************/
//3、初始化IOC容器,将扫描到的类相关实例,保存到IOC容器
doInstance();
/**********************AOP*******************************/
//新生成的代理对象,需要在DI之前
/**********************DI*******************************/
//4、完成依赖注入
doAutoWired();
/**********************MVC*******************************/
//5、初始化handlerMapping
doInitHandlerMapping();
System.out.println("Jason Spring framework init finished!");
}
private void doInitHandlerMapping() {
if(ioc.isEmpty())
{
return;
}
//只取public方法
for(Map.Entry entry:ioc.entrySet())
{
Class> clazz=entry.getValue().getClass();
if(!clazz.isAnnotationPresent(JasonController.class))
{
continue;
}
String baseUrl="";
if(clazz.isAnnotationPresent(JasonRequestMapping.class))
{
baseUrl=clazz.getAnnotation(JasonRequestMapping.class).value().trim();
}
for(Method method:clazz.getMethods())
{
if(!method.isAnnotationPresent(JasonRequestMapping.class))
{
continue;
}
JasonRequestMapping jasonRequestMapping=method.getAnnotation(JasonRequestMapping.class);
String url = ("/" + baseUrl + "/" + jasonRequestMapping.value()).replaceAll("/+","/");
handleMapping.put(url,method);
System.out.println("初始化handleMapping方法隐射:"+url+"---"+method);
}
}
}
private void doAutoWired() {
if(ioc.isEmpty())
{
return;
}
for(Map.Entry entry:ioc.entrySet())
{
//获取private,public,default所有的属性
for(Field field:entry.getValue().getClass().getDeclaredFields())
{
if(!field.isAnnotationPresent(JasonAutowired.class))
{
continue;
}
String beanName=field.getAnnotation(JasonAutowired.class).value();
if("".equals(beanName.trim()))
{
beanName=field.getType().getName();
}
System.out.println("doAutoWired="+beanName);
field.setAccessible(true);
try {
field.set(entry.getValue(),ioc.get(beanName));
System.out.println("ioc.get("+beanName+")="+ioc.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private void doInstance() {
if(classNameList.isEmpty()){
return;
}
for(String className:classNameList)
{
try
{
Class> clazz=Class.forName(className);
if(clazz.isAnnotationPresent(JasonController.class))
{
Object obj=clazz.newInstance();
String beanName=toLowerFirsCase(clazz.getSimpleName());
ioc.put(beanName,obj);
}else if(clazz.isAnnotationPresent(JasonService.class))
{
//1.在多个包路径下,同名service,只能自己起一个全局唯一的名称@JasonService("AService") @JasonService("BService")
String beanName=clazz.getAnnotation(JasonService.class).value();
if("".equals(beanName.trim()))
{
//2.默认的类首字母小写
beanName=toLowerFirsCase(clazz.getSimpleName());
}
Object obj=clazz.newInstance();
ioc.put(beanName,obj);
//3.如果是接口,判断有多少个实现类,如果有多个实现类,则抛出异常。如果只有一个,则默认就是实现类。
for(Class> i:clazz.getInterfaces())
{
if(ioc.containsKey(i.getName()))
{
throw new Exception("The "+i.getName()+" is Exists!!");
}
ioc.put(i.getName(),obj);
}
}else
{
continue;
}
}catch (Exception e)
{
e.printStackTrace();
}
}
System.out.println("IOC容器初始化结果:"+ioc);
}
private String toLowerFirsCase(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("\\.","/"));
System.out.println("url.getFile="+url.getFile());
File classPath=new File(url.getFile());
for(File file:classPath.listFiles())
{
if(file.isDirectory())
{
doScanner(scanPackage+"."+file.getName());
}else
{
if(!file.getName().endsWith(".class")) {continue;}
classNameList.add(scanPackage+"."+file.getName().replace(".class",""));
}
}
}
private void doLoadConfig(String contextConfigLocation) {
System.out.println("contextConfigLocation="+contextConfigLocation);
InputStream inputStream=this.getClass().getClassLoader().getResourceAsStream("application.properties");
System.out.println("inputStream="+inputStream);
try {
contextConfig.load(inputStream);
System.out.println("初始化,读取配置文件:--------------"+contextConfig.getProperty("scanPackage"));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(inputStream!=null)
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、测试类:
package com.jason.demo.action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jason.demo.service.IDemoService;
import com.jason.spring.framework.annoation.JasonAutowired;
import com.jason.spring.framework.annoation.JasonController;
import com.jason.spring.framework.annoation.JasonRequestMapping;
import com.jason.spring.framework.annoation.JasonRequestParam;
//虽然,用法一样,但是没有功能
@JasonController
@JasonRequestMapping("/demo")
public class DemoAction {
@JasonAutowired
private IDemoService demoService;
@JasonRequestMapping("/query")
public void query(HttpServletRequest req, HttpServletResponse resp,
@JasonRequestParam("name") String name){
System.out.println("---------------------"+demoService);
String result = demoService.get(name);
System.out.println(result);
try {
resp.getWriter().write(result);
} catch (IOException e) {
e.printStackTrace();
}
}
@JasonRequestMapping("/add")
public void add(HttpServletRequest req, HttpServletResponse resp,
@JasonRequestParam("a") Integer a, @JasonRequestParam("b") Integer b){
try {
resp.getWriter().write(a + "+" + b + "=" + (a + b));
} catch (IOException e) {
e.printStackTrace();
}
}
@JasonRequestMapping("/sub")
public void add(HttpServletRequest req, HttpServletResponse resp,
@JasonRequestParam("a") Double a, @JasonRequestParam("b") Double b){
try {
resp.getWriter().write(a + "-" + b + "=" + (a - b));
} catch (IOException e) {
e.printStackTrace();
}
}
@JasonRequestMapping("/remove")
public String remove(@JasonRequestParam("id") Integer id){
return "" + id;
}
}
四、浏览器测试: