一直没时间来写一写关于springmvc源码的分析,今天晚上心血来潮就写一段关于springmvc实现的东西给大家分享哈
附一张网上的原理图
首先看一看这个demo的包的架构
这个demo是由注解实现springmvc的,现在流行的方式,简单方便,xml的配置的太繁琐了
注解类:Controller
package com.springmvc.annotion;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Administrator
*
*/
@Target(ElementType.TYPE)//指定注解作用在我们(TYPE)类上/(FIELD)变量上/(METHOD)方法上
@Retention(RetentionPolicy.RUNTIME)//用来描述我们自定义注解的生命周期,(RUNTIME)运行时时期,(SOURCE)源文件时间,(CLASS)编译时期
@Documented //工具文档化,将注释生成api
public @interface Controller {
String value() default "";
}
注解类:
Qualifier
package com.springmvc.annotion;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 此注解用来将使用该注解的Bean变量,实例注入进去
* @author Administrator
*
*/
@Target(ElementType.FIELD)//指定注解作用在我们的类上/FIELD变量上/方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Qualifier {
String value() default "";
}
注解类: RequestMapping
package com.springmvc.annotion;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Administrator
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
String value() default "";
}
注解类:
Service
package com.springmvc.annotion;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author Administrator
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value() default "";
}
核心控制类 DispatcherServlet
package com.springmvc.servlet;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.springmvc.annotion.Controller;
import com.springmvc.annotion.Qualifier;
import com.springmvc.annotion.RequestMapping;
import com.springmvc.annotion.Service;
/**
* 核心控制类
* @author Administrator
*
*/
@WebServlet("/DispatcherServlet")
public class DispatcherServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
//将基础包中的类的类名放入集合中
private List<String> packeNames=new ArrayList<String>();
//注解属性对应各层对象实例MAP
private Map<String,Object> InstanceMaps=new HashMap<String, Object>();
//请求Url对应的Method对象
private Map<String,Method> hanlderMaps=new HashMap<String, Method>();
@Override
public void init() throws ServletException {
/**
* 扫描包下含有注解的类
* 扫描基础包后拿到权限命名包+类名
* com/springmvc/annotion/Controller.java
* 替换/和.java
* com.springmvc.annotion.Controller
*/
//扫描全包
scanBase("com.springmvc");
//找到实例
try {
fileterAndInstance();
//注入springIoc,各层的调用的实体
springIoc();
//注入对应的方法
halderMaps();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 扫描基包
*/
private void scanBase(String basePackage){
URL url=this.getClass().getClassLoader().getResource("/"+replacePath(basePackage));
//拿到路径下的文件夹以及文件
String pathFile=url.getFile();
//通过路径生成file
File files=new File(pathFile);
String[] filesString=files.list();
for (String path : filesString) {
//再次构成一个file
File eachFile=new File(pathFile +path);
if(eachFile.isDirectory()){
//递归引用scanBase
scanBase(basePackage+"."+eachFile.getName());
}else if(eachFile.isFile()){
System.out.println("正在装载:"+basePackage+"."+eachFile.getName());
//表示扫描到的是一个文件
packeNames.add(basePackage+"."+eachFile.getName());
}
}
}
/**
* 替换成路径
*/
private String replacePath(String path){
return path.replaceAll("\\.", "/");
}
/**
* 拦截方法请求然后对应请求地址到对应的handler实例
* @throws Exception
*/
private void fileterAndInstance() throws Exception{
//判断集合里面是否有实例
if(packeNames.size()<=0){
return;
}
for(String className:packeNames){
Class ccName=Class.forName(className.replace(".class", ""));
if(ccName.isAnnotationPresent(Controller.class)){
Object instance=ccName.newInstance();
//将实例装入Map key
Controller cortollerAnController=(Controller)ccName.getAnnotation(Controller.class);
//通过注解对象访问属性值
String key=cortollerAnController.value();
//通过注解的key找到对应bean的实例
InstanceMaps.put(key, instance);
//放入Map
}else if(ccName.isAnnotationPresent(Service.class)){
Object instance=ccName.newInstance();
//将实例装入Map key
Service serviceAncontroller=(Service)ccName.getAnnotation(Service.class);
//通过注解对象拿到属性值
String key=serviceAncontroller.value();
//通过注解的key找到对应bean的实例
InstanceMaps.put(key, instance);
//放入Map
}else{
//没有找到注解
continue;
}
}
}
//将实例注入到spring容器里
private void springIoc() throws IllegalArgumentException, IllegalAccessException {
if(InstanceMaps.size()<=0){
return;
}
for(Map.Entry<String, Object> entry :InstanceMaps.entrySet()){
Field[] fields=entry.getValue().getClass().getDeclaredFields();
for(Field field:fields){
if(field.isAnnotationPresent(Qualifier.class)){
//注入
String qualifierValueString=((Qualifier)field.getAnnotation(Qualifier.class)).value();
field.setAccessible(true);
field.set(entry.getValue(),InstanceMaps.get(qualifierValueString));
}else{
continue;
}
}
}
}
//通过url找到相应的method对象进行处理
private void halderMaps() throws Exception {
if(InstanceMaps.size()<=0){
return;
}
//存的实例是有控制层的和service层
for(Map.Entry<String, Object> entry :InstanceMaps.entrySet()){
if(entry.getValue().getClass().isAnnotationPresent(Controller.class)){
Controller controllerAncontroller=(Controller)entry.getValue().getClass().getAnnotation(Controller.class);
String baseUrl=controllerAncontroller.value();
Method[] controllerMethods=entry.getValue().getClass().getMethods();
for(Method controllerMethod:controllerMethods){
if(controllerMethod.isAnnotationPresent(RequestMapping.class)){
//@RequestMapping注解的方法
String methodUrl=((RequestMapping)controllerMethod.getAnnotation(RequestMapping.class)).value();
hanlderMaps.put("/"+baseUrl+"/"+methodUrl, controllerMethod);
}else{
continue;
}
}
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//请求url
String url=req.getRequestURI();
//工程路径
String projectName=req.getContextPath();
//完整路径
String path=url.replace(projectName, "").split("\\.")[0];
//方法对象
Method method=hanlderMaps.get(path);
PrintWriter outPrintWriter=resp.getWriter();
if(method==null){
outPrintWriter.write("您访问的资源找不到,请检查您的访问地址!");
return;
}
//localhost:8080/SpringMvc/mvcContro/insert
String className=url.split("/")[2];
try {
method.invoke(InstanceMaps.get(className), new Object[]{req,resp});
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
服务层接口 MvcService.java
package com.springmvc.service;
import java.util.Map;
public interface MvcService {
int insert(Map map);
int delete(Map map);
int update(Map map);
int select(Map map);
}
服务层实现 MvcServiceImpl.java
package com.springmvc.service.impl;
import java.util.Map;
import com.springmvc.annotion.Service;
import com.springmvc.service.MvcService;
@Service("mvcServiceImpl")
public class MvcServiceImpl implements MvcService{
@Override
public int insert(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的Insert方法");
return 0;
}
@Override
public int delete(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的delete方法");
return 0;
}
@Override
public int update(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的update方法");
return 0;
}
@Override
public int select(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的select方法");
return 0;
}
}
控制层 MvcController.java
package com.springmvc.service.impl;
import java.util.Map;
import com.springmvc.annotion.Service;
import com.springmvc.service.MvcService;
@Service("mvcServiceImpl")
public class MvcServiceImpl implements MvcService{
@Override
public int insert(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的Insert方法");
return 0;
}
@Override
public int delete(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的delete方法");
return 0;
}
@Override
public int update(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的update方法");
return 0;
}
@Override
public int select(Map map) {
// TODO Auto-generated method stub
System.out.println("调用这个服务类的select方法");
return 0;
}
}
配置tomcat 启动运行核心控制类 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringMvc</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置编码格式 -->
<!-- 配置SpringMVC启动的servlet -->
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>com.springmvc.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<!-- 设置session的有效时间 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>