SpringMVC大致原理
目录结构
pom文件
< project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns: xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
< modelVersion> 4.0 .0 < / modelVersion>
< groupId> org. example< / groupId>
< artifactId> CustomSpringMvc< / artifactId>
< version> 1.0 - SNAPSHOT< / version>
< packaging> war< / packaging>
< name> CustomSpringMvc Maven Webapp< / name>
< ! -- FIXME change it to the project's website -- >
< url> http: / / www. example. com< / url>
< properties>
< project. build. sourceEncoding> UTF- 8 < / project. build. sourceEncoding>
< maven. compiler. source> 11 < / maven. compiler. source>
< maven. compiler. target> 11 < / maven. compiler. target>
< / properties>
< dependencies>
< dependency>
< groupId> junit< / groupId>
< artifactId> junit< / artifactId>
< version> 4.11 < / version>
< scope> test< / scope>
< / dependency>
< dependency>
< groupId> javax. servlet< / groupId>
< artifactId> javax. servlet- api< / artifactId>
< version> 3.1 .0 < / version>
< scope> provided< / scope>
< / dependency>
< dependency>
< groupId> org. apache. commons< / groupId>
< artifactId> commons- lang3< / artifactId>
< version> 3.9 < / version>
< / dependency>
< / dependencies>
< build>
< finalName> CustomSpringMvc< / finalName>
< plugins>
< plugin>
< groupId> org. apache. maven. plugins< / groupId>
< artifactId> maven- compiler- plugin< / artifactId>
< version> 3.1 < / version>
< configuration>
< source> 11 < / source>
< target> 11 < / target>
< encoding> utf- 8 < / encoding>
< ! -- 告诉编译器,编译的时候记录下形参的真实名称-- >
< compilerArgs>
< arg> - parameters< / arg>
< / compilerArgs>
< / configuration>
< / plugin>
< plugin>
< groupId> org. apache. tomcat. maven< / groupId>
< artifactId> tomcat7- maven- plugin< / artifactId>
< version> 2.2 < / version>
< configuration>
< port> 8080 < / port>
< path> / < / path>
< / configuration>
< / plugin>
< / plugins>
< / build>
< / project>
mvc.properties
scanPackage= mvcdemo. demo
注解
Controller
@Retention ( RetentionPolicy. RUNTIME)
@Target ( ElementType. TYPE)
@Documented
public @interface Controller {
String value ( ) default "" ;
}
Service
@Retention ( RetentionPolicy. RUNTIME)
@Target ( ElementType. TYPE)
@Documented
public @interface Service {
String value ( ) default "" ;
}
Autowired
@Retention ( RetentionPolicy. RUNTIME)
@Target ( ElementType. FIELD)
@Documented
public @interface Autowired {
String value ( ) default "" ;
}
RequestMapping
@Retention ( RetentionPolicy. RUNTIME)
@Target ( { ElementType. TYPE, ElementType. METHOD} )
@Documented
public @interface RequestMapping {
String value ( ) default "" ;
}
Controller
@Controller
@RequestMapping("/testController")
public class TestController {
@Autowired
private TestService testService;
@RequestMapping("/test")
public void test(String name){
testService.query(name);
}
}
Service
public interface TestService {
void query(String name);
}
Impl
@Service
public class TestServiceImpl implements TestService {
@Override
public void query(String name) {
System.out.println("姓名:"+name);
}
}
Handler
public class Handler {
private Object controller;
private Method method;
// url
private Pattern pattern;
// 存放参数的位置,标记是参数顺序
private Map<String,Integer> paramIndexMapping;
public Handler(Object controller, Method method, Pattern pattern){
this.controller=controller;
this.method=method;
this.pattern=pattern;
this.paramIndexMapping=new HashMap<>();
}
}
DispatherServlet
public class DispatherServlet extends HttpServlet {
private Properties properties=new Properties();
private List<String> classNameList=new ArrayList();
private Map<String,Object> IOC=new HashMap<>();
private List<Handler> handlerMapping=new ArrayList<>();
@Override
public void init(ServletConfig config) throws ServletException {
// 加载配置文件 mvc.properties
String contextConfigLocation = config.getInitParameter("contextConfigLocation");
doLoadConfig(contextConfigLocation);
// 扫描类,扫描注解
doScan(properties.getProperty("scanPackage"));
// 初始化Bean对象
doInstance();
// 依赖注入
doAutowired();
// 构造一个handlerMapping处理器映射器,将配置好的url和method建立映射关系
intiHandlerMapping();
System.out.println("初始化完成!");
}
// url和method映射关系
private void intiHandlerMapping() {
if (IOC == null) {
return;
}
for (Map.Entry<String,Object> entry:IOC.entrySet()){
// 获取class
Class<?> aClass = entry.getValue().getClass();
// 判断是否是controller
if(!aClass.isAnnotationPresent(Controller.class)){
continue;
}
// RequestMapping
if (aClass.isAnnotationPresent(RequestMapping.class)) {
RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);
// 获取url
String value = annotation.value();
Method[] methods = aClass.getMethods();
for (int i = 0; i < methods.length; i++) {
if(methods[i].isAnnotationPresent(RequestMapping.class)){
RequestMapping annotationMethod = methods[i].getAnnotation(RequestMapping.class);
String annMethValue = annotationMethod.value();
// url路径
String path = value+annMethValue;
// 封装为一个handler
Handler handler = new Handler(entry.getValue(), methods[i], Pattern.compile(path));
// 获取参数的位置信息
Parameter[] parameters = methods[i].getParameters();
for (int j = 0; j < parameters.length; j++) {
Parameter parameter = parameters[j];
String name = parameter.getName();
handler.addParamIndexMapping(name,j);
}
handlerMapping.add(handler);
}
}
}
}
}
// 依赖注入
private void doAutowired() {
if(IOC.size()==0){
return;
}
// 遍历ico
for(Map.Entry<String,Object> entry: IOC.entrySet()){
Object value = entry.getValue();
// 获取对象属性
Field[] declaredFields = value.getClass().getDeclaredFields();
for (int i = 0; i <declaredFields.length; i++) {
// 属性是否使用Autowired注解
if (declaredFields[i].isAnnotationPresent(Autowired.class)) {
Object o = IOC.get(declaredFields[i].getType().getName());
if (null!=o) {
// 打开强制赋值权限
declaredFields[i].setAccessible(true);
try {
declaredFields[i].set(value,o);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
// 实例化对象
private void doInstance() {
if (classNameList.size()==0){
return;
}
for (String className:classNameList){
// 反射
try {
Class<?> aClass = Class.forName(className);
// Controller
if (aClass.isAnnotationPresent(Controller.class)) {
String simpleName = aClass.getSimpleName();
Object o = aClass.newInstance();
IOC.put(simpleName,o);
}
// Service
if (aClass.isAnnotationPresent(Service.class)) {
Service service = aClass.getAnnotation(Service.class);
Object o = aClass.newInstance();
// 判断Service是否设置value,如果设置了value,key为value
if(!"".equals(service.value())){
IOC.put(service.value(),o);
}
// 如果该类实现了接口,将接口全限定名称设置为key
Class<?>[] interfaces = aClass.getInterfaces();
if(interfaces.length>0){
for (int i = 0; i < interfaces.length; i++) {
Class<?> anInterface = interfaces[i];
String name = anInterface.getName();
IOC.put(name,o);
}
}
// 将实现类的名称开头小写设置为key
String simpleName = aClass.getSimpleName();
String s = lowerFirst(simpleName);
IOC.put(s,o);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
private String lowerFirst(String simpleName) {
char[] chars = simpleName.toCharArray();
if('A' <= chars[0] && chars[0] <= 'Z') {
chars[0] += 32;
}
return String.valueOf(chars);
}
// 扫描类
private void doScan(String scanPackage) {
// 将路径转换为磁盘上的路径 mvcdemo.demo ——> mvcdemo/demo
String path = Thread.currentThread().getContextClassLoader().getResource("").getPath() + scanPackage.replaceAll("\\.", "/");
// 获取文件
File file = new File(path);
File[] files = file.listFiles();
// 遍历获取包下所有类的全限定类名
for (File fe:files){
// 子包
if(fe.isDirectory()){
// 递归
doScan(scanPackage+"."+fe.getName());
}else if(fe.getName().endsWith(".class")){
String name = fe.getName().replaceAll(".class", "");
String className = scanPackage + "." + name;
classNameList.add(className);
}
}
}
// 加载配置文件
private void doLoadConfig(String contextConfigLocation) {
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
try {
properties.load(resourceAsStream);
} catch (IOException 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 {
// 根据url获取当前请求的handler
Handler handler = getHandler(req);
if(handler==null){
resp.getWriter().write("404 not found");
return;
}
// 获取参数类型数组和参数数组的长度
Class<?>[] parameterTypes = handler.getMethod().getParameterTypes();
// 根据数组长度创建一个数组
Object[] paramValues = new Object[parameterTypes.length];
// 获取传递过来的参数
Map<String, String[]> parameterMap = req.getParameterMap();
// 遍历request中的参数
for (Map.Entry<String,String[]> entry:parameterMap.entrySet()){
// 将参数[1,2] 转换为 1,2
String[] value = entry.getValue();
String join = StringUtils.join(value, ",");
// 如果匹配就填充数据
if(!handler.getParamIndexMapping().containsKey(entry.getKey())){
continue;
}
// 找到参数对应的位置,赋值
Integer integer = handler.getParamIndexMapping().get(entry.getKey());
paramValues[integer]=join;
}
try {
handler.getMethod().invoke(handler.getController(),paramValues);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private Handler getHandler(HttpServletRequest rfq) {
if (handlerMapping.isEmpty()) {
return null;
}
String requestURI = rfq.getRequestURI();
for (Handler handler : handlerMapping) {
if (null != handler.getPattern()) {
Matcher matcher = handler.getPattern().matcher(requestURI);
if (matcher.matches()) {
return handler;
}
}
}
return null;
}
}
WEB.xml
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>mvcdemo.servlet.DispatherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>properties/mvc.properties</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
测试结果