手写SpringMVC
程序员文章站
2022-07-15 11:21:57
...
/**
前端控制器也是用java语言编写,主要用来处理网络请求
势必会集成HttpServlet j2ee规范
https://v.qq.com/x/page/c0393ws95u5.html
@WebServlet注解将DispatcherServlet(*控制器)交给容器进行管理,servlet3.0的注解
*/
@WebServlet(“/DispatcherServlet”)
public class DispatcherServlet extends HttpServlet {
//放扫描我们基包下面的bean的权限定类名
private List packNames = new ArrayList();
//将注解参数信息和实例一一对应 注册到容器
private Map<String,Object> instanceMaps = new HashMap<String,Object>();
//构建方法链容器,这里说明spring比struts更加轻量级,因为struts是基于类级别的,而spring拿到url在方法上执行。
private Map<String,Method> handlerMaps = new HashMap<String,Object>();
public void init() throws ServletException {
//拿到spring.xml配置全包扫描的基础包 Resource
try {
String basePackName = confiUtils.getBasePackgName("E/**/spring.xml");
System.out.println("basePackName" + basePackName);
//全自动扫描基包功能实现
scanBase(basePackName);
//这里就是找每个Bean的实例,注册到我们的容器上下文
foundBeansInstance();
//注入实例, 通过Spring 定义的注解注入实例
springIoc();
//handlerMapping
handlerMapping();
} catch(Exception e) {}
}
//处理方法执行链
private void handlerMapping() throws Exception {
if(instanceMaps.size() == 0 ){
return;
}
//对url请求,然后找到相应的handler进行处理
for(Map.Entry<String,Object> entry : instanceMaps.entrySet()) {
if(entry.getValue().getClass.isAnnotationPresent(Controller.class)) {
Controller controllerAnnotation = entry.getValue().getClass.isAnnotationPresent(Controller.class);
//执行方法链接classUrl/MethodUrl
String classUrl = controllerAnnotation.value();
//通过字节码对象里面方法对象拿到方法对象上面的注解参数
Method [] methods = entry.getValue().getClass.getMethods();
for(Method method : methods) {
if(method.isAnnotationPresent(RequestMapping.class )) {
String methodUrl = (RequestMapping)method.getAnnotation(RequestMapping.class).value();
handlerMaps.put("/"+ classUrl + "/" + methodUrl, method);
} else {
continue;
}
}
}
}
}
//将上下文实例注入到bean对象中,代码耦合完全分离开
private void springIoc() throws Exception {
if(instanceMaps.size() == 0 ){
return;
}
for(Map.Entry<String,Object> entry : instanceMaps.entrySet()) {
Field [] fieldNames = entry.getValue().getClass().getDeclaredFields();
for(Field fieldName : fieldNames) {
if(fieldName.isAnnotationPresent(Qualifier.class)) {
String qualiferParamString = ((Qualifier)fieldName.getAnnotation(Qualifier.class )).value();
//让私有化的属性也能注入实例
field.setAccessible(true);
field.set(entry.getValue(), instanceMaps.get(qualiferParamString));
} else {
continue;
}
}
}
}
/**
*将扫描到bean实例注册到上下文中
*/
private void foundBeansInstance(){
if(packNames.size() == 0 ){
return;
}
//className 文件名称 带有文件扩展名.class
for(String className : packNames) {
//反射拿到字节码对象 然后拿到实例
Class ccName = Class.forName(className.replace(".class",""))
//思想 是拿业务Bean 实例 判断字节码对象是否含有Controller类型
if(ccName.isAnnotationPresent(Controller.class)) {
//拿到控制层的注解对象
Controller controllerAnnotationObject =(Controller)ccName.getAnnotation(Controller.class);
String controllerParmString = controllerAnnotationObject.value();
//拿控制层的实例
Object controllerInstance = ccName.newInstance();
//找到实例并注册到容器
instanceMaps.put(controllerParmString, controllerInstance);
} else if(ccName.isAnnotationPresent(Service.class)) {
//拿到server的注解对象
Service serverAnnotationObject =(Service)ccName.getAnnotation(Service.class);
String serverParmString = serverAnnotationObject.value();
//拿server的实例
Object serverInstance = ccName.newInstance();
//找到server实例并注册到容器
instanceMaps.put(serverParmString, serverInstance);
} else {
continue;
}
}
}
//全自动扫描基包功能实现,源于源码
private void scanBase(String basePackName) {
//basePackName: com.dongnao=>com/dongnao
URL url = this.getClass().getClassLoader().getResource("/"+replacePath(basePackName));
String pathFile = url.getFile();
File file = new File(pathFile);
String [] files = file.list();
for(String path : files) {
File eachFile = new File(pathFile+path);
//代表eachFile只是一个目录
if(eachFile.isDirectory()) {
//递归 以com.dongnao.annotation为条件
scanBase(basePackName+"."+eachFile.getName());
} else if(eachFile.isFile()) {
packNames.add(basePackName+"."+eachFile.getName());
System.out.println("spring容器扫描到的类有:"+basePackName+"."+eachFile.getName());
}
}
}
private String replacePath(String basePackName) {
return basePackName.replaceAll("\\.","/");
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) thorws ServletExceptoin, IOException {
doPost(req, resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) thorws ServletExceptoin, IOException {
String uri = req.getRequestURI();
String projectName = req.getContextPath();
//这里拿到请求链接 classUrl + MethodUrl
String methodUriString = uri.replace(projectName,"");
Method method = handlerMaps.get(methodUrl);
PrintWriter outPrintWriter = resp.getWriter();
if(method == null ){
outPrintWriter.writer("您访问的资源不存在,请检查访问路径!");
}
//localhost:8000/Projectname/dongnao/insert
String className = uri.split("/")[2];
DongNaoController dnObj = (DongNaoController)instanceMaps.get(className);
//aop
try{
method.invoke(obj,new Object[]{req,resp,null})
}catch(Exception e) {}
}
}
上一篇: 2
下一篇: SpringMVC手写