最近在看Spring的源码,开始的时候看的没有头绪,自己大脑都是乱麻;自己就在网上找资料,自己慢慢的看,到现在只是刚刚开始,把自己总结的SpringMVC的个人心得分享个大家,很多都是在网上找的资料,现在开始....
首先展示目录结构:
现在开始正文:
创建注解,可以仿照Spring的源码中的注解
@Controller
package com.stone.annotation;
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;
/**
*
* @ClassName:Controller
* @Description:controller控制器注解
* @author: stone
* @date:2018年2月26日 下午1:34:54
*
*/
@Target({ElementType.TYPE})//在类上的注解
@Retention(RetentionPolicy.RUNTIME)//这是代表运行的时候启动
@Documented
public @interface Controller {
String value() default "";
}
@RequestMapping
package com.stone.annotation;
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;
@Target({ ElementType.TYPE, ElementType.METHOD}) // 在类和方法上的注解
@Retention(RetentionPolicy.RUNTIME) // 这是代表运行的时候启动
@Documented
public @interface RequestMapping {
String value() default "";
}
@RequestParam
package com.stone.annotation;
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;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
String value();
}
@Resource
package com.stone.annotation;
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;
/**
*
* @ClassName:Quatifier
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: stone
* @date:2018年2月26日 下午1:36:39
*
*/
@Target({ ElementType.FIELD }) // 代表注解的注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Resource {
String value() default "";
}
@Service
package com.stone.annotation;
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;
/**
*
* @ClassName:Service
* @Description:服务注解
* @author: stone
* @date:2018年2月26日 下午1:37:21
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value() default "";
}
以上就是项目中要是使用的注解。
接下来重头戏DsiparcherServlet
package com.stone.servlet;
import java.io.File;
import java.io.IOException;
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.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.stone.annotation.Controller;
import com.stone.annotation.Resource;
import com.stone.annotation.RequestMapping;
import com.stone.annotation.Service;
import com.stone.controller.MymvcController;
import com.stone.handlerAdapter.HandlerAdapter;
/**
* @ClassName:DispatcherServlet
* @Description:总控制器
* @author: stone
* @date:2018年2月26日 下午1:50:05
*
*/
public class DispatcherServlet extends HttpServlet {
/**
* 存放扫描的包+类.class
* 例:com.stone.annotation.Controller.class 有.class后缀
*/
List<String> packageNames = new ArrayList<String>();
/**
* 所有类的实例 key是注解的value, value是所有类的实例
* 例:stone = com.stone.controller.SpringmvcController@7a141541
*/
Map<String, Object> instanceMap = new HashMap<String, Object>();
/**
* 请求地址和实例方法
* 例:/stone/select = public java.lang.String com.stone.controller.SpringmvcController.select(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
*/
Map<String, Object> handlerMap = new HashMap<String, Object>();
public DispatcherServlet() {
super();
}
/**
* @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
*/
private static final long serialVersionUID = 1L;
/**
* 系统启动初始化工作
* <p>Title:init</p>
* <p>Description: </p>
* @see Servlet#init(ServletConfig)
* @param config
* @throws ServletException
* @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
*/
@Override
public void init(ServletConfig config) throws ServletException {
// 1、包扫描,获取包中的文件
scanPackage(config.getInitParameter("scanPackage"));
// 2、过滤得到Cotroller,并实例化
try {
filterAndInstance();
} catch (Exception e) {
e.printStackTrace();
}
// 3、建立映射关系
handlerMap();
// 4、实现注入
ioc();
}
/**
* @Title:scanPackage
* @Description:扫描指定包下的文件(类)
* @param:@param basePackage
* @return: void
* @throws
*/
private void scanPackage(String basePackage) {
URL url=this.getClass().getClassLoader().getResource("/"+replaceTo(basePackage));
String pathfile=url.getFile();
File file=new File(pathfile);
String[] files=file.list();
for (String path : files) {
File eachFile= new File(pathfile+path);
if(eachFile.isDirectory()){
scanPackage(basePackage+"."+eachFile.getName());
}else{
// com.stone.annotation.Controller.class
packageNames.add(basePackage+"."+eachFile.getName());
}
}
}
/**
* @Title:replaceTo
* @Description:将所有.转义获取对应的路径
* @param:@param path com.stone
* @param:@return
* @return:String
* @throws
*/
private String replaceTo(String path) {
return path.replaceAll("\\.","/");
}
/**
* @Title:filterAndInstance
* @Description:过滤得到Cotroller,并实例化
* @param:@throws Exception
* @return: void
* @throws
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private void filterAndInstance() throws Exception {
if(packageNames.size()<=0){
return;
}
for (String classname : packageNames) {
Class ccName=Class.forName(classname.replace(".class",""));
if(ccName.isAnnotationPresent(Controller.class)){// 判断类是否有@Controller注解
Object instance= ccName.newInstance();
Controller an= (Controller)ccName.getAnnotation(Controller.class);
String key=an.value();
instanceMap.put(key,instance);
}else if(ccName.isAnnotationPresent(Service.class)){// 判断类是否有@Service注解
Object instance= ccName.newInstance();
Service an= (Service) ccName.getAnnotation(Service.class);
String key=an.value();
instanceMap.put(key,instance);
}else{
continue;
}
}
}
/**
* @Title:handlerMap
* @Description:建立映射关系
* @param:
* @return: void
* @throws
*/
private void handlerMap() {
if(instanceMap.size()<=0)
return;
for(Map.Entry<String, Object> entry:instanceMap.entrySet()){
if(entry.getValue().getClass().isAnnotationPresent(Controller.class)){
Controller controller=(Controller)entry.getValue().getClass().getAnnotation(Controller.class);
String ctvalue= controller.value();
Method[] methods=entry.getValue().getClass().getMethods();
for(Method method:methods){
if(method.isAnnotationPresent(RequestMapping.class)){
RequestMapping rm= (RequestMapping)method.getAnnotation(RequestMapping.class);
String rmvalue=rm.value();
// /stone/update,public java.lang.String com.stone.controller.SpringmvcController.select(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
handlerMap.put("/"+ctvalue+"/"+rmvalue,method);
}else{
continue;
}
}
}else{
continue;
}
}
}
private void ioc() {
if(instanceMap.isEmpty())return;
for(Map.Entry<String, Object> entry:instanceMap.entrySet()){
//拿到类里面的属性
Field[] fields= entry.getValue().getClass().getDeclaredFields();
for (Field field : fields) {
// 由于变量的修饰符是private,需要这个操作
field.setAccessible(true);
if(field.isAnnotationPresent(Resource.class)){
Resource qf=(Resource)field.getAnnotation(Resource.class);
String value= qf.value();
field.setAccessible(true);
try {
field.set(entry.getValue(), instanceMap.get(value));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
@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 {
// /MyMvc/update.ht
String url= req.getRequestURI();
// /MyMvc
String context=req.getContextPath();
// /update.ht
String path=url.replace(context,"");
Method method =(Method) handlerMap.get(path);
MymvcController controller=(MymvcController) instanceMap.get(path.split("/")[1]);
HandlerAdapter handlerAdapter = (HandlerAdapter)instanceMap.get("MymvcHandlerAdepter");
Object[] args = handlerAdapter.hand(req, resp, method, instanceMap);
try {
method.invoke(controller, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
在编码DispacherServlet的过程中,主要还是对于反射有很深入的理解,建议可以多看看,细嚼慢咽,相信大家会有收获。
下面就是Service和Controller:
MymvcServie接口
package com.stone.service;
public interface MymvcServie {
void insert();
void delete();
void update();
void select();
}
MymvcServiceImpl接口的实现类
package com.stone.service.impl;
import com.stone.annotation.Service;
import com.stone.service.MymvcServie;
@Service("MymvcServiceImpl")
public class MymvcServiceImpl implements MymvcServie {
@Override
public void insert() {
System.out.println("MymvcServiceImpl:insert");
}
@Override
public void delete() {
System.out.println("MymvcServiceImpl:delete");
}
@Override
public void update() {
System.out.println("MymvcServiceImpl:update");
}
@Override
public void select() {
System.out.println("MymvcServiceImpl:select");
}
}
MymvcController控制器
package com.stone.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.stone.annotation.Controller;
import com.stone.annotation.RequestMapping;
import com.stone.annotation.RequestParam;
import com.stone.annotation.Resource;
import com.stone.service.MymvcServie;
@Controller("stone")
public class MymvcController {
@Resource("MymvcServiceImpl")
private MymvcServie mymvcServie;
@RequestMapping("insert")
public void insert(HttpServletRequest request, HttpServletResponse response,@RequestParam("name") String name) {
System.out.println(name);
mymvcServie.insert();
}
@RequestMapping("delete")
public void delete(HttpServletRequest request, HttpServletResponse response) {
mymvcServie.delete();
}
@RequestMapping("update")
public void update(HttpServletRequest request, HttpServletResponse response) {
mymvcServie.update();
}
@RequestMapping("select")
public void select(HttpServletRequest request, HttpServletResponse response) {
mymvcServie.select();
}
}
修改Web.xml,添加DispacherServlet
<?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_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>MyMvc</display-name>
<!-- spring mvc 入口 -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>com.stone.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>scanPackage</param-name>
<param-value>com.stone</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
到现在为止,基本上可以使用了,效果如下:
刚开始自己走到了这里,又看了相关资料,添加以下配置
HandlerAdapter参数适配器接口
package com.stone.handlerAdapter;
import java.lang.reflect.Method;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface HandlerAdapter {
public Object[] hand(HttpServletRequest request, HttpServletResponse response, Method method,Map<String, Object> instanceMap);
}
接口的实现
package com.stone.handlerAdapter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.stone.annotation.Service;
import com.stone.argumentResolver.ArgumentResolver;
@Service("MymvcHandlerAdepter")
public class MymvcHandlerAdepter implements HandlerAdapter {
@Override
public Object[] hand(HttpServletRequest request, HttpServletResponse response, Method method, Map<String, Object> instanceMap) {
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] args = new Object[parameterTypes.length];
Map<String, Object> ArgumentResolverbeans = getBeansOfType(instanceMap,ArgumentResolver.class);
int paramIndex = 0;
int i = 0;
for (Class<?> parmclazz : parameterTypes) {
for (Map.Entry<String, Object> bean : ArgumentResolverbeans.entrySet()) {
ArgumentResolver argumentResolver =(ArgumentResolver)bean.getValue();
if (argumentResolver.support(parmclazz, paramIndex, method)) {
args[i++] = argumentResolver.argumentResolver(request, response, parmclazz, paramIndex, method);
}
}
paramIndex++;
}
return args;
}
/**
*
* @Title:getBeansOfType
* @Description:取得实现了intfType接口的实现类
* @param:@param beans
* @param:@param intfType
* @param:@return
* @return:Map<String,Object>
* @throws
*/
private Map<String, Object> getBeansOfType(Map<String, Object> beans,Class<?> intfType) {
Map<String, Object> resultBeans = new HashMap<>();
for(Map.Entry<String, Object> entry : beans.entrySet()){
Class<?>[] interfaces = entry.getValue().getClass().getInterfaces();
if (interfaces != null && interfaces.length > 0 ) {
for (Class<?> class1 : interfaces) {
if(class1.isAssignableFrom(intfType)){
resultBeans.put(entry.getKey(), entry.getValue());
}
}
}
}
return resultBeans;
}
}
还有就是ArgumentResolver,通过策略模式,配置参数类型
接口
package com.stone.argumentResolver;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface ArgumentResolver {
public boolean support(Class<?> type, int paramIndex, Method method);
public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
int paramIndex, Method method);
}
相关的实现类
package com.stone.argumentResolver;
import java.lang.reflect.Method;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.stone.annotation.Service;
@Service("HttpServletRequestArgumentResolver")
public class HttpServletRequestArgumentResolver implements ArgumentResolver {
@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
return ServletRequest.class.isAssignableFrom(type);
}
@Override
public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
int paramIndex, Method method) {
return request;
}
}
package com.stone.argumentResolver;
import java.lang.reflect.Method;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.stone.annotation.Service;
@Service("HttpServletResponseArgumentResolver")
public class HttpServletResponseArgumentResolver implements ArgumentResolver {
@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
return ServletResponse.class.isAssignableFrom(type);
}
@Override
public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
int paramIndex, Method method) {
return response;
}
}
package com.stone.argumentResolver;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.stone.annotation.RequestParam;
import com.stone.annotation.Service;
@Service("StringArgumentResolver")
public class StringArgumentResolver implements ArgumentResolver {
@Override
public boolean support(Class<?> type, int paramIndex, Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Annotation[] paramans = parameterAnnotations[paramIndex];
for (Annotation annotation : paramans) {
if (RequestParam.class.isAssignableFrom(annotation.getClass())) {
return true;
}
}
return false;
}
@Override
public Object argumentResolver(HttpServletRequest request, HttpServletResponse response, Class<?> type,
int paramIndex, Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Annotation[] paramans = parameterAnnotations[paramIndex];
for (Annotation annotation : paramans) {
if (RequestParam.class.isAssignableFrom(annotation.getClass())) {
RequestParam requestParam = (RequestParam)annotation;
String value = requestParam.value();
return request.getParameter(value);
}
}
return null;
}
}