web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>dispatcher</servlet-name>
<!--定義MyDispatcherServlet類-->
<servlet-class>com.panda.servlet.MyDispatcherServlet</servlet-class>
<!--設置爲1後,httpServlet初始化調用init方法-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<!--攔截所有請求 /*-->
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
註解類
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
String value() default "";
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
}
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestParam {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}
entity/service/controller類
public class User {
private String id;
private String username;
private String password;
public User(String id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
public interface UserService {
public String get(String name);
}
@MyService("userService")
public class UserServiceImpl implements UserService {
@Override
public String get(String name) {
return "查詢到姓名爲:" + name;
}
}
@MyController
public class UserController {
@MyAutowired
private UserService userService;
@MyRequestMapping("/index")
public String index(HttpServletRequest request, HttpServletResponse response,
@MyRequestParam("name") String name) throws IOException {
String res = userService.get(name);
System.out.println(name + "=>" + res);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(res);
return "index";
}
}
DispathServlet
public class MyDispatcherServlet extends HttpServlet {
//類名列表
private List<String> classNames = new ArrayList<String>();
//ioc容器,Map<類名,類實例>
private Map<String, Object> ioc = new HashMap<String, Object>();
private List<Handler> handlerMapping = new ArrayList<Handler>();
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("init...");
//1.掃描包,將包內所有對象類名存儲到list中
doScanner("com.panda.web");
System.out.println("========第一步:掃描文件包==========");
classNames.forEach(value -> System.out.println("保存類名:" + value));
//2.IOC實現,單例模式,new出對象,放入Map中
doInstance();
System.out.println("========第二步:IOC==========");
ioc.forEach((key, value) -> System.out.println("IOC名稱:" + key + ":" + value));
//3.DI實現,依賴注入。實現註釋MyAutowired的類,進行賦值
doAutoWired();
//4.將requestMapping註釋的method方法,放入到Arraylist中
initHandlerMapping();
}
private void doScanner(String packageName) {
//1.獲取當前class的文件路徑下的com.panda.web下的文件路徑,
URL resource =
this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
File classDir = new File(resource.getFile());
for (File classFile : classDir.listFiles()) {
if (classFile.isDirectory()) {
//2.遞歸,如果遇到文件夾,遞歸掃描此文件夾下的class
doScanner(packageName + "." + classFile.getName());
} else {
//3.文件,直接獲取文件名稱,存放到List中,形式爲com.panda.web.controller.UserController
String className = (packageName + "." + classFile.getName()).replace(".class", "");
classNames.add(className);
}
}
}
private void doInstance() {
if (classNames.isEmpty()) {
return;
}
try {
//循環所有掃描出來的類名,將其實例化,並放入ioc容器中
for (String className : classNames) {
//類反射機制,獲取clazz
Class<?> clazz = Class.forName(className);
//如果有MyController註解,說明爲controller類,可初始化
if (clazz.isAnnotationPresent(MyController.class)) {
//ioc的beanId的格式爲類名,且首字母小寫
String beanName = lowerFirstCase(clazz.getSimpleName());
ioc.put(beanName, clazz.newInstance());
//如果有MyService註解,說明爲service類,可初始化
} else if (clazz.isAnnotationPresent(MyService.class)) {
//1.如果自己起了名字,優先使用自己的
//2.如果沒起名字,使用首字母小寫
//3.如果自動注入的爲接口,使用接口的全稱
MyService service = clazz.getAnnotation(MyService.class);
String beanName = service.value();
if ("".equals(beanName)) {
beanName = lowerFirstCase(clazz.getSimpleName());
}
Object instance = clazz.newInstance();
ioc.put(beanName, instance);
//service註解的時候,如實現接口時,再put一次
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> i : interfaces) {
ioc.put(i.getName(), instance);
}
} else {
//如無註解,無需初始化。
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void doAutoWired() {
if (ioc.isEmpty()) {
return;
}
//注入就是對類中定義的一些屬性,進行賦值
//不管是公有的還是私有的,都需要賦值
for (Map.Entry<String, Object> entry : ioc.entrySet()) {
//getDeclaredFields獲取類中,所有的屬性值
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field : fields) {
//如果屬性上,無註解,直接循環下一次。如有MyAutowired才進行操作
if (!field.isAnnotationPresent(MyAutowired.class)) {
continue;
}
MyAutowired autowired = field.getAnnotation(MyAutowired.class);
String beanName = autowired.value();
if ("".equals(beanName)) {
//如果beanName是空,使用默認接口注入
beanName = field.getType().getName();
}
//開始賦值,setAccessible - 強制訪問
field.setAccessible(true);
//通過反射機制,強制賦值。將ioc初始化實例後的對象賦值到MyAutowired屬性值上
try {
field.set(entry.getValue(), ioc.get(beanName));
} catch (IllegalAccessException e) {
e.printStackTrace();
continue;
}
}
}
}
private void initHandlerMapping() {
if (ioc.isEmpty()) {
return;
}
for (Map.Entry<String, Object> entry : ioc.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
//如果類的註解不是MyController,則繼續循環,此方法只處理controller層
if (!clazz.isAnnotationPresent(MyController.class)) {
continue;
}
String baseUrl = "";
//如果類註解有MyRequestMapping,說明定義了根路徑,將此路徑存儲起來
if (clazz.isAnnotationPresent(MyRequestMapping.class)) {
MyRequestMapping requestMapping = clazz.getAnnotation(MyRequestMapping.class);
baseUrl = requestMapping.value();
}
//獲取controller類的所有方法,並變量
Method[] methods = clazz.getMethods();
for (Method method : methods) {
//如方法無註解,則繼續循環,目的獲取到所有MyRequestMapping註解的方法
if (!method.isAnnotationPresent(MyRequestMapping.class)) {
continue;
}
//獲取MyRequestMapping註解的路徑,並與根路徑進行拼接
MyRequestMapping requestMapping = method.getAnnotation(MyRequestMapping.class);
String url = (baseUrl + requestMapping.value()).replaceAll("/+", "/");
Pattern pattern = Pattern.compile(url);
//url和method的方法,封裝到handler類中
handlerMapping.add(new Handler(pattern, entry.getValue(), method));
System.out.println("mapped:" + url + "=>" + method);
}
}
}
private String lowerFirstCase(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
//內部類
private class Handler {
protected Object controller;//保存controller的實例對象
protected Method method;//保存controller類的method方法
protected Pattern pattern;//url正則表達是
protected Map<String, Integer> paramIndexMapping;//param註解的map存儲
protected Handler(Pattern pattern, Object controller, Method method) {
this.pattern = pattern;
this.controller = controller;
this.method = method;
paramIndexMapping = new HashMap<String, Integer>();
putParamIndexMapping(method);
}
private void putParamIndexMapping(Method method) {
Annotation[][] pa = method.getParameterAnnotations();
for (int i = 0; i < pa.length; i++) {
for (Annotation a : pa[i]) {
if (a instanceof MyRequestParam) {
String paramName = ((MyRequestParam) a).value();
if (!"".equals(paramName)) {
paramIndexMapping.put(paramName, i);
}
}
}
}
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
Class<?> type = paramTypes[i];
if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
paramIndexMapping.put(type.getName(), i);
}
}
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
this.doPost(req, res);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doDispatcher(req, res);
}
public void doDispatcher(HttpServletRequest req, HttpServletResponse res) {
try {
//獲取request中的url訪問路徑和參數,從ArrayList的handlerMapping中查找。找到後,執行method方法
Handler handler = getHandler(req);
if (handler == null) {
res.getWriter().write("404 not found.");
return;
}
Class<?>[] paramTypes = handler.method.getParameterTypes();
Object[] paramValues = new Object[paramTypes.length];
//獲取訪問鏈接中的params,並對其循環
Map<String, String[]> params = req.getParameterMap();
for (Map.Entry<String, String[]> param : params.entrySet()) {
String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "");
if (!handler.paramIndexMapping.containsKey(param.getKey())) {
continue;
}
int index = handler.paramIndexMapping.get(param.getKey());
paramValues[index] = convert(paramTypes[index], value);
}
int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName());
paramValues[reqIndex] = req;
int resIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName());
paramValues[resIndex] = res;
//method方法執行
handler.method.invoke(handler.controller, paramValues);
} catch (Exception e) {
e.printStackTrace();
}
}
//通過request的url鏈接,尋找handler對象中是否有對應的method
private Handler getHandler(HttpServletRequest req) {
if (handlerMapping.isEmpty()) {
return null;
}
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
for (Handler handler : handlerMapping) {
Matcher matcher = handler.pattern.matcher(url);
if (!matcher.matches()) {
continue;
}
//url有對應的method,返回handler
return handler;
}
//url無對應的method,返回null
return null;
}
private Object convert(Class<?> type, String value) {
if (Integer.class == type) {
return Integer.valueOf(value);
}
return value;
}
}
碼雲地址:[https://gitee.com/xumiaofeng/springmvc]