目录
1 应用spring的流程
2 梳理设计思路
3 coding spring实战
核心流程:
Step1 配置依赖(仅仅依赖servlet-api包)
Step2 定义一个核心控制器
Step3 自定义一些类spring的注解
Step4 配置容器启动时的初始化
Step5 执行请求,请求分发
Step6 启动
Step7 验证功能
4 源码?just do it 动手实践吧
公众号搜索:DeanKano
企鹅群号: 561932405
javax.servlet
servlet-api
2.4
DkDispatcherServlet extends HttpServlet {...}
在web.xml配置核心控制器
dkDispatcher
com.dean.framework.DkDispatcherServlet
contextConfigLocation
classpath:application.properties
1
dkDispatcher
/*
@DkController
@DkService
@DkAutowired
@DkRequestMapping
@DkRequestParam
// 启动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 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 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);
}
}
}
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 reqParams = req.getParameterMap();
for (Map.Entry 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);
一 直接运行maven 插件 jetty:run
二 命令行启动,在cmd窗口执行:
`$mvn jetty:run`
启动日志:
...
[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
源码地址: https://github.com/lingqibaobei/rangers-framework-spring