简化版SpringMVC
web.xml
xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Web Application</display-name>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>com.aop.mvc.action.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>application.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
pom.xml
<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>com.aop.demo</groupId>
<artifactId>SpringAop-Demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringAop-Demo</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>${artifactId}</finalName>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
<exclude>**/*.class</exclude>
</excludes>
</resource>
</resources>
</build>
</project>
application.properties
scanPackage=com.aop.mvc
com.aop.mvc.annotaion
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.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoWirted {
String value() default "";
}
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
String value() default "";
}
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
String value() default "";
}
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
String value() default "";
}
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value() default "";
}
DemoService.java
package com.aop.mvc.servlet.impl;
import com.aop.mvc.annotaion.Service;
import com.aop.mvc.servlet.IDemoService;
@Service
public class DemoService implements IDemoService {
public String get(String name) {
return "My name is " + name;
}
}
package com.aop.mvc.servlet;
public interface IDemoService {
String get(String name);
}
DispatcherServlet.java
package com.aop.mvc.action;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
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 java.util.Map.Entry;
import java.util.Properties;
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.aop.mvc.annotaion.AutoWirted;
import com.aop.mvc.annotaion.Controller;
import com.aop.mvc.annotaion.RequestMapping;
import com.aop.mvc.annotaion.Service;
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/** 资源文件 */
private Properties contextConfig = new Properties();
/** 扫描到的所有类 */
private List<String> classNames = new ArrayList<String>();
/** 实例化类集合 */
private Map<String, Object> ioc = new HashMap<String, Object>();
/** url ==> 优化:List handlerMapping */
private Map<String, Method> handlerMapping = new HashMap<String, Method>();
@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 {
try {
// 6.等待请求
doDispatch(req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
// 判读HandlerMapping中有返回调用, 没有就404
if (!handlerMapping.containsKey(url)) {
resp.getWriter().write("404 Not Found!");
return;
}
Method me = handlerMapping.get(url);
// me.invoke(req.getParameterMap(), ???);
System.out.println(me);
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("======================Begin========================");
// 1.加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
// 2.扫描到所有的相关类
doScanner(contextConfig.getProperty("scanPackage"));
// 3.初始化刚刚扫描到的类
doInstance();
// 4.实现依赖注入
doAutowired();
// 5.初始化HadlerMapping
initHandlerMapping();
System.out.println("=============== Spring is init OK!");
}
private void initHandlerMapping() {
if (ioc.isEmpty())
return;
// 对Controller进行处理
for (Entry<String, Object> entry : ioc.entrySet()) {
Class clazz = entry.getValue().getClass();
// 判断有没有加@Controller注解的
if (!clazz.isAnnotationPresent(Controller.class))
continue;
String baseUtl = "";
if (clazz.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestParam = clazz.getAnnotation(RequestMapping.class);
baseUtl = requestParam.value();
}
Method[] method = clazz.getMethods();
for (Method meth : method) {
if (meth.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestParam = meth.getAnnotation(RequestMapping.class);
String url = requestParam.value();
url = (baseUtl + url);
handlerMapping.put(url, meth);
System.out.println("Mapped:" + url + "," + method);
}
}
}
}
private void doAutowired() {
if (ioc.isEmpty())
return;
for (Entry<String, Object> entry : ioc.entrySet()) {
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field : fields) {
// 授权, 只要加了Autowired的
if (!field.isAnnotationPresent(AutoWirted.class))
continue;
AutoWirted autoWirted = field.getAnnotation(AutoWirted.class);
String beanName = autoWirted.value().trim();
if ("".equals(beanName)) {
beanName = field.getType().getName();
}
// 执行强制授权
field.setAccessible(true);
// 进行赋值操作
try {
field.set(entry.getValue(), ioc.get(beanName));
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
private void doInstance() {
// 将扫描到的类初始化
if (classNames.isEmpty())
return;
// 通过反射初始化
try {
for (String className : classNames) {
Class clazz = Class.forName(className);
// 有注解的类初始化
if (clazz.isAnnotationPresent(Controller.class)) {
Object obj = clazz.newInstance();
// 初始化后放入ioc容器中
// 默认是类名的首字母小写
String beanName = lowerFirstCase(clazz.getSimpleName());
ioc.put(beanName, obj);
} else if (clazz.isAnnotationPresent(Service.class)) {
// 1.默认首字母小写
// 2.如果是接口, 要把他的实现类赋值给它
// 3.如果自定义,就优先用自定义的名字
Service service = clazz.getAnnotation(Service.class);
String beanName = service.value();
if ("".equals(beanName.trim())) {
// 如果自定义名字为空,取默认值
beanName = lowerFirstCase(clazz.getSimpleName());
}
Object instance = clazz.newInstance();
ioc.put(beanName, instance);
// 解决子类引用赋值父类的问题
Class[] interfaces = clazz.getInterfaces();
for (Class i : interfaces) {
ioc.put(i.getName(), instance);
}
} else {
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void doScanner(String scanPackage) {
URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
File classDir = new File(url.getFile());
// 递归扫描指定文件下的类
for (File file : classDir.listFiles()) {
if (file.isDirectory()) {// 判断是否文件夹
doScanner(scanPackage + "." + file.getName());
} else {// 如果不是文件夹
String className = scanPackage + "." + file.getName().replace(".class", "");
classNames.add(className);
}
}
}
private void doLoadConfig(String contextConfigLocation) {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
try {
contextConfig.load(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/** 自定义首字母小写 */
private String lowerFirstCase(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}
DemoAction.java
package com.aop.mvc.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.aop.mvc.annotaion.AutoWirted;
import com.aop.mvc.annotaion.Controller;
import com.aop.mvc.annotaion.RequestMapping;
import com.aop.mvc.annotaion.RequestParam;
import com.aop.mvc.servlet.IDemoService;
/**
* @Theme 纯手写实现SpringMVC
* @author http://localhost:8080/SpringAop-Demo/demo/query.json
*/
@Controller
@RequestMapping("/demo")
public class DemoAction {
@AutoWirted
private IDemoService demoService;
@RequestMapping("/query.json")
public void query(HttpServletRequest req, HttpServletResponse resp, @RequestParam("name") String name) {
String result = demoService.get(name);
try {
resp.getWriter().write(result);
} catch (Exception e) {
// TODO: handle exception
}
}
@RequestMapping("/add.json")
public void add(HttpServletRequest req, HttpServletResponse resp, @RequestParam("a") Integer a, @RequestParam("b") Integer b) {
try {
resp.getWriter().write(a + "+" + b + "=" + (a + b));
} catch (Exception e) {
// TODO: handle exception
}
}
@RequestMapping("/remove.json")
public void remove(HttpServletRequest req, HttpServletResponse resp, @RequestParam("id") Integer id) {
try {
} catch (Exception e) {
// TODO: handle exception
}
}
}