1. Annotation
UVAutowired:
/*
* @author uv
* @date 2018/9/29 10:00
* 注入
*/
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 UVAutowried {
}
UVController
/*
* @author uv
* @date 2018/9/29 9:58
*
*/
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)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UVController {
String value() default "";
}
UVRequestMapping
/*
* @author uv
* @date 2018/9/29 9:59
*
*/
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 UVRequestMapping {
String value() default "";
}
UVResponseBody
/*
* @author uv
* @date 2018/9/30 14:06
*
*/
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.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UVResponseBody {
}
UVService
/*
* @author uv
* @date 2018/9/29 9:57
*
*/
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)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UVService {
String value() default "";
}
2. core
MethodHandler
/*
* @author uv
* @date 2018/9/30 10:33
*
*/
import java.lang.reflect.Method;
import java.util.List;
import lombok.Data;
@Data
public class MethodHandler {
//方法所在的類
private Object object;
private Method method;
//參數順序
private List<String> params;
}
3. servlet
/*
* @author uv
* @date 2018/9/28 19:51
* 調度中心,分發請求,IOC
*/
import com.alibaba.fastjson.JSON;
import com.spring.annotation.UVAutowried;
import com.spring.annotation.UVController;
import com.spring.annotation.UVRequestMapping;
import com.spring.annotation.UVResponseBody;
import com.spring.annotation.UVService;
import com.spring.core.MethodHandler;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
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 org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import org.reflections.scanners.MethodParameterNamesScanner;
public class UVDispatcherServlet extends HttpServlet {
//spring配置文件
private Properties properties = new Properties();
//存放所有帶註解的類
private List<String> classNameList = new ArrayList<>();
//IOC容器,通過類型注入
private Map<String, Object> IOCByType = new HashMap<>();
//當通過類型找不到對應實例時,通過名稱注入(名稱相同時會覆蓋之前的值,這裏就不處理了)
private Map<String, Object> IOCByName = new HashMap<>();
//url 到controller方法的映射
private Map<String, MethodHandler> urlHandler = new HashMap<>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//6、處理請求,執行相應的方法
doHandler(req, resp);
}
@Override
public void init() throws ServletException {
System.out.println("servlet開始初始化");
//1、加載配置文件 spring-config.properties,獲取掃描路徑
doLoadConfig();
//2、掃描配置的路徑下的帶有註解的類
doScanner(properties.getProperty("basepackage"));
//3、初始化所有的類,被放入到IOC容器中
doPutIoc();
//4、實現@UVAutowried自動注入
doAutowried();
//5、初始化HandlerMapping,根據url映射不同的controller方法
doMapping();
System.out.println("servlet初始化完成");
}
//1、加載配置文件 spring-config.properties,獲取掃描路徑
private void doLoadConfig() {
//ServletConfig:代表當前Servlet在web.xml中的配置信息
ServletConfig config = this.getServletConfig();
String configLocation = config.getInitParameter("contextConfigLocation");
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(configLocation);
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//2、掃描配置的路徑下的帶有註解的類
private void doScanner(String path) {
//java文件
if (path.endsWith(".class")) {
//獲取到帶有包路徑的類名
String className = path.substring(0, path.lastIndexOf(".class"));
//掃描的類
classNameList.add(className);
return;
}
URL url = this.getClass().getClassLoader().getResource("/" + path.replaceAll("\\.", "/"));
//是包路徑,繼續迭代
File file = new File(url.getFile());
File[] files = file.listFiles();
for (File f : files) {
doScanner(path + "." + f.getName());
}
}
//3、初始化所有的類,被放入到IOC容器中
private void doPutIoc() {
if (classNameList.isEmpty()) {
return;
}
try {
for (String className : classNameList) {
//反射獲取實例對象
Class<?> clazz = Class.forName(className);
//IOC容器key命名規則:1.默認類名首字母小寫 2.使用用戶自定義名,如 @UVService("abc") 3.如果service實現了接口,可以使用接口作爲key
//controller,service註解類
if (clazz.isAnnotationPresent(UVController.class)) {
UVController uvController = clazz.getAnnotation(UVController.class);
String beanName = uvController.value().trim();
//如果用戶沒有定義名稱,使用名首字母小寫
if (StringUtils.isBlank(beanName)) {
beanName = lowerFirstCase(clazz.getSimpleName());
}
//byName
Object instance = clazz.newInstance();
IOCByName.put(beanName, instance);
//byType
IOCByType.put(clazz.getName(), instance);
} else if (clazz.isAnnotationPresent(UVService.class)) {
UVService uvService = clazz.getAnnotation(UVService.class);
String beanName = uvService.value().trim();
//如果用戶沒有定義名稱,使用名首字母小寫
if (StringUtils.isBlank(beanName)) {
beanName = lowerFirstCase(clazz.getSimpleName());
}
//byName
Object instance = clazz.newInstance();
IOCByName.put(beanName, instance);
//byType
IOCByType.put(clazz.getName(), instance);
//如果service實現了接口,可以使用接口作爲key
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> interf : interfaces) {
IOCByName.put(lowerFirstCase(interf.getSimpleName()), instance);
IOCByType.put(interf.getName(), instance);
}
} else {
continue;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
//4、實現@UVAutowried自動注入
private void doAutowried() {
if (IOCByName.isEmpty() && IOCByType.isEmpty()) {
return;
}
for (Entry<String, Object> entry : IOCByType.entrySet()) {
//獲取變量
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for (Field field : fields) {
//private、protected修飾的變量可訪問
field.setAccessible(true);
if (!field.isAnnotationPresent(UVAutowried.class)) {
continue;
}
Object instance = null;
String beanName = field.getType().getName();
String simpleName = lowerFirstCase(field.getType().getSimpleName());
//首先根據Type注入,沒有實例時根據Name,否則拋出異常
if (IOCByType.containsKey(beanName)) {
instance = IOCByType.get(beanName);
} else if (IOCByName.containsKey(simpleName)) {
instance = IOCByName.get(simpleName);
} else {
throw new RuntimeException("not find class to autowire");
}
try {
//向obj對象的這個Field設置新值value,依賴注入
field.set(entry.getValue(), instance);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
//5、初始化HandlerMapping,根據url映射不同的controller方法
private void doMapping() {
if (IOCByType.isEmpty() && IOCByName.isEmpty()) {
return;
}
for (Entry<String, Object> entry : IOCByType.entrySet()) {
Class<?> clazz = entry.getValue().getClass();
//判斷是否是controller
if (!clazz.isAnnotationPresent(UVController.class)) {
continue;
}
String startUrl = "/";
//判斷controller類上是否有UVRequestMapping註解,如果有則拼接url
if (clazz.isAnnotationPresent(UVRequestMapping.class)) {
UVRequestMapping requestMapping = clazz.getAnnotation(UVRequestMapping.class);
String value = requestMapping.value();
if (!StringUtils.isBlank(value)) {
startUrl += value;
}
}
//遍歷controller類中UVRequestMapping註解修飾的方法,添加到urlHandler中,完成url到方法的映射
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (!method.isAnnotationPresent(UVRequestMapping.class)) {
continue;
}
UVRequestMapping annotation = method.getAnnotation(UVRequestMapping.class);
String url = startUrl + "/" + annotation.value().trim();
//解決多個/重疊的問題
url = url.replaceAll("/+", "/");
MethodHandler methodHandler = new MethodHandler();
//放入方法
methodHandler.setMethod(method);
try {
//放入方法所在的controller
methodHandler.setObject(entry.getValue());
} catch (Exception e) {
e.printStackTrace();
}
//放入方法的參數列表
List<String> params = doParamHandler(method);
methodHandler.setParams(params);
urlHandler.put(url, methodHandler);
}
}
}
//6、處理請求,執行相應的方法
private void doHandler(HttpServletRequest request, HttpServletResponse response) throws IOException {
boolean jsonResult = false;
String uri = request.getRequestURI();
PrintWriter writer = response.getWriter();
//沒有映射的url,返回404
if (!urlHandler.containsKey(uri)) {
writer.write("404 Not Found");
return;
}
//獲取url對應的method包裝類
MethodHandler methodHandler = urlHandler.get(uri);
//處理url的method
Method method = methodHandler.getMethod();
//method所在的controller
Object object = methodHandler.getObject();
//method的參數列表
List<String> params = methodHandler.getParams();
//如果controller或這個方法有UVResponseBody修飾,返回json
if (object.getClass().isAnnotationPresent(UVResponseBody.class) || method.isAnnotationPresent(UVResponseBody.class)) {
jsonResult = true;
}
List<Object> args = new ArrayList<>();
for (String param : params) {
//從request中獲取參數,然後放入參數列表
String parameter = request.getParameter(param);
args.add(parameter);
}
try {
//執行方法,反射處理,返回結果
Object result = method.invoke(object, args.toArray());
//返回json(使用阿里的fastJson)
if (jsonResult) {
writer.write(JSON.toJSONString(object));
} else { //返回視圖
doResolveView((String) result, request, response);
}
} catch (Exception e) {
e.printStackTrace();
//方法執行異常,返回500
writer.write("500 Internal Server Error");
return;
}
}
//8、視圖解析,返回視圖
private void doResolveView(String indexView, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//視圖前綴
String prefix = properties.getProperty("view.prefix");
//視圖後綴
String suffix = properties.getProperty("view.suffix");
String view = (prefix + indexView + suffix).trim().replaceAll("/+", "/");
request.getRequestDispatcher(view).forward(request, response);
}
//處理字符串首字母小寫
private String lowerFirstCase(String str) {
char[] chars = str.toCharArray();
//ascii碼計算
chars[0] += 32;
return String.valueOf(chars);
}
/**
* 在Java 8之前的版本,代碼編譯爲class文件後,方法參數的類型是固定的,但參數名稱卻丟失了, 這和動態語言嚴重依賴參數名稱形成了鮮明對比。 現在,Java 8開始在class文件中保留參數名,給反射帶來了極大的便利。 使用reflections包,jdk7和jdk8都可用
**/
//處理method的參數
private List<String> doParamHandler(Method method) {
//使用reflections進行參數名的獲取
Reflections reflections = new Reflections(new MethodParameterNamesScanner());
//參數名與順序對應
List<String> paramNames = reflections.getMethodParamNames(method);
return paramNames;
}
}
4. Controller
import com.spring.annotation.UVAutowried;
import com.spring.annotation.UVController;
import com.spring.annotation.UVRequestMapping;
import com.spring.annotation.UVResponseBody;
import com.uv.entity.User;
import com.uv.service.UserService;
/*
* @author uv
* @date 2018/9/29 10:46
*
*/
@UVController
@UVRequestMapping("user")
public class UserController {
@UVAutowried
private UserService userService;
@UVRequestMapping("user")
@UVResponseBody
public User getUser() {
return userService.getUser();
}
@UVRequestMapping("hello")
public String hello(String name) {
return "hello";
}
}
User
import lombok.AllArgsConstructor;
import lombok.Data;
/*
* @author uv
* @date 2018/9/29 10:39
*
*/
@Data
@AllArgsConstructor
public class User {
private String id;
private String name;
private int age;
}
UserSerive 和 UserServiceImpl
import com.uv.entity.User;
/*
* @author uv
* @date 2018/9/29 10:38
*
*/
public interface UserService {
public User getUser();
}
import com.spring.annotation.UVService;
import com.uv.entity.User;
import com.uv.service.UserService;
/*
* @author uv
* @date 2018/9/29 10:38
*
*/
@UVService
public class UserServiceImpl implements UserService{
public User getUser() {
User user = new User("1", "Tom",18);
return user;
}
}
spring-config.properties
#指定掃描路徑
basepackage=com.uv
#視圖解析器
view.prefix=/WEB-INF/jsp/
view.suffix=.jsp
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--啓動時加載的servlet,servlet爲單實例多線程-->
<servlet>
<servlet-name>myspring</servlet-name>
<servlet-class>com.spring.servlet.UVDispatcherServlet</servlet-class>
<!-- 指定Spring的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
spring-config.properties
</param-value>
</init-param>
<!--啓動後立即加載servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--配置映射到servlet的路徑-->
<servlet-mapping>
<servlet-name>myspring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Hello Tom!</h1>
</body>
</html>