目錄
1 應用spring的流程
2 梳理設計思路
3 coding spring實戰
核心流程:
Step1 配置依賴(僅僅依賴servlet-api包)
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
</dependency>
Step2 定義一個核心控制器
DkDispatcherServlet extends HttpServlet {...}
在web.xml配置核心控制器
<!-- 核心控制器 -->
<servlet>
<servlet-name>dkDispatcher</servlet-name>
<servlet-class>com.dean.framework.DkDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dkDispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Step3 自定義一些類spring的註解
@DkController
@DkService
@DkAutowired
@DkRequestMapping
@DkRequestParam
Step4 配置容器啓動時的初始化
// 啓動DkDispatcherServlet做初始化
@Override
public void init(ServletConfig config) throws ServletException {
// 1 加載配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
// 2 掃描配置包路徑
doScanner(contextConfig.getProperty("scanPackage"));
// 3 反射實例化加載到IOC容器中
doInstance();
// 4 DI依賴注入,針對IOC容器中加載到的類,自動對需要賦值的屬性進行初始化操作
doAutowired();
// 5 初始化HandlerMapping
initHandlerMapping();
}
privatevoid doLoadConfig(String contextConfigLocation) {
contextConfigLocation = contextConfigLocation.replace("classpath:", EMPTY_STRING);
try (InputStream resourceAsStream = this.getClass().getClassLoader()
.getResourceAsStream(contextConfigLocation)) {
contextConfig.load(resourceAsStream);
} catch (Exception e) {
e.printStackTrace();
}
}
private void doScanner(String scanPackage) {
URL url = this.getClass().getClassLoader().getResource(
SLASH_STRING + scanPackage.replaceAll("\\.", SLASH_STRING));
if (url == null) return;
File classDir = new File(url.getFile());
for (File file : classDir.listFiles()) {
if (file.isDirectory()) {
doScanner(scanPackage + SPOT_STRING + file.getName());
} else {
String className = scanPackage + SPOT_STRING +
file.getName().replace(".class", EMPTY_STRING);
classNames.add(className);
}
}
}
private void doInstance() {
if (classNames.isEmpty()) return;
for (String className : classNames) {
try {
Class<?> clazz = Class.forName(className);
if (clazz.isInterface()) continue;
// 針對指定掃描到的包進行實例化
// 默認bean名稱是類名的首字母小寫
String beanName = getFirstLower(clazz.getName());
Object newInstance = clazz.newInstance();
if (clazz.isAnnotationPresent(DkController.class)) {
// 指定了bean名稱
DkController dkController = clazz.getAnnotation(DkController.class);
if (!EMPTY_STRING.equals(dkController.value())) {
beanName = dkController.value();
}
} else if (clazz.isAnnotationPresent(DkService.class)) {
// 指定bean名稱
DkService dkService = clazz.getAnnotation(DkService.class);
if (!EMPTY_STRING.equals(dkService.value())) {
beanName = dkService.value();
}
// 針對接口的,bean名稱用接口的名稱
Class<?>[] interfaces = clazz.getInterfaces();
if (interfaces.length == 1) {
for (Class<?> anInterface : interfaces) {
beanName = getFirstLower(anInterface.getName());
}
} else if (interfaces.length > 1) {
// TODO 多接口
}
} else {
continue;
}
ioc.put(beanName, newInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void doAutowired() {
if (ioc.isEmpty()) return;
for (Map.Entry<String, Object> entry : ioc.entrySet()) {
Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
if (!declaredField.isAnnotationPresent(DkAutowired.class)) {
continue;
}
String beanName = getFirstLower(declaredField.getType().getName());
DkAutowired annotation = declaredField.getAnnotation(DkAutowired.class);
if (!EMPTY_STRING.equals(annotation.value())) {
beanName = annotation.value();
}
try {
declaredField.setAccessible(true);
declaredField.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();
if (!clazz.isAnnotationPresent(DkController.class)) {
continue;
}
String baseUrl = EMPTY_STRING;
if (clazz.isAnnotationPresent(DkRequestMapping.class)) {
DkRequestMapping dkRequestMapping = clazz.getAnnotation(DkRequestMapping.class);
baseUrl = dkRequestMapping.value();
}
for (Method method : clazz.getMethods()) {
if (!method.isAnnotationPresent(DkRequestMapping.class)) {
continue;
}
DkRequestMapping dkRequestMapping = method.getAnnotation(DkRequestMapping.class);
String regexUrl = (SLASH_STRING + baseUrl + dkRequestMapping.value()).replaceAll("/+", SLASH_STRING);
Pattern pattern = Pattern.compile(regexUrl);
handlerMapping.add(new Handler(method, entry.getValue(), pattern));
System.out.println("Mapping: [" + regexUrl + "] ==>" + method);
}
}
}
Step5 執行請求,請求分發
private voiddoDispatcher(HttpServletRequest req, HttpServletResponse resp) throws InvocationTargetException, IllegalAccessException, IOException {
Handler handler = retrieveHandler(req);
if (handler == null) {
resp.getWriter().write("404 NOT FOUND");
return;
}
Object[] paramValues = new Object[handler.method.getParameterTypes().length];
// String[]可能多個參數,例如:?name=tom&name=jaine
Map<String, String[]> reqParams = req.getParameterMap();
for (Map.Entry<String, String[]> stringEntry : reqParams.entrySet()) {
String paramName = stringEntry.getKey();
if (!handler.paramsIndexMapping.keySet().contains(paramName)) {
continue;
}
int paramIndex = handler.paramsIndexMapping.get(paramName);
paramValues[paramIndex] = Arrays.toString(stringEntry.getValue()).replaceAll("\\[|\\]", EMPTY_STRING);
}
int respIndex = handler.paramsIndexMapping.get(HttpServletResponse.class.getName());
int reqIndex = handler.paramsIndexMapping.get(HttpServletRequest.class.getName());
paramValues[reqIndex] = req;
paramValues[respIndex] = resp;
handler.method.invoke(handler.controller, paramValues);
}
doDispatcher(req, resp);
Step6 啓動
一 直接運行maven 插件 jetty:run
二 命令行啓動,在cmd窗口執行:
`$mvn jetty:run`
Step7 驗證功能
啓動日誌:
...
[INFO] Starting jetty 6.1.7 ...
[INFO] jetty-6.1.7
[INFO] No Transaction manager found - if your webapp requires one, please configure one.
Mapping: [/sample/query.do] ==>public void com.dean.framework.sample.UserAction.query(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
Mapping: [/sample/add.do] ==>public void com.dean.framework.sample.UserAction.addUser(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
Mapping: [/sample/remove.do] ==>public void com.dean.framework.sample.UserAction.removeUser(java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
[INFO] Started [email protected]:8080
[INFO] Started Jetty Server
請求示例:
http://localhost:8080/sample/query.do?name=Tom
4 源碼?just do it 動手實踐吧
源碼地址: https://github.com/lingqibaobei/rangers-framework-spring
公衆號搜索:DeanKano
企鵝羣號: 561932405