Maven、Gradle
优点:
特性:
约定大于配置
比如src是约定好的代码目录
插件机制
Gradle比起Maven的优点:
引入jar包(Tomcat Embed Core)
Code:
public class TomcatServer {
private Tomcat tomcat;
private String[] args;
public TomcatServer(String[] args) {
this.args = args;
}
public void startServer() throws LifecycleException {
tomcat = new Tomcat();
tomcat.setPort(6699);
tomcat.start();
Context context = new StandardContext();
context.setPath("");
context.addLifecycleListener(new Tomcat.FixContextListener());
DispatcherServlet servlet = new DispatcherServlet();
Tomcat.addServlet(context, "dispatcherServlet", servlet).setAsyncSupported(true);
// "/":映射所有的url
context.addServletMappingDecoded("/", "dispatcherServlet");
tomcat.getHost().addChild(context);
Thread awaitThread = new Thread("tomcat_await_thread"){
@Override
public void run() {
//内部类调用外部类的实例成员变量
//这行代码会阻塞,作用难道是让tomcat不关闭?
TomcatServer.this.tomcat.getServer().await();
}
};
awaitThread.setDaemon(false);
awaitThread.start();
}
}
前端请求经由http协议发送到tomcat监听的端口上,tomcat将请求经由解码、反序列化等操作封装成ServletRequest对象,然后会调用DispatcherServlet的service()
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
for (MappingHandler mappingHandler : HandlerManager.mappingHandlerList) {
try {
if (mappingHandler.handle(req, res)) {
return;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
可以看到代码中只有一个操作:遍历mappingHandlerList
对请求url进行匹配,寻找对应的函数进行处理
mappingHandlerList保存的是mappingHandler,mappingHandler中存储了请求path和对应执行函数等信息
(ps:由于path很少,代码中没有用map,而是直接遍历了)
我们先看建立mappingHandlerList的建立过程,它先遍历出注解了@controller
的类,再遍历@RequestMapping
对应的方法,最后建立MappingHandler对象,将其加入list中
public class HandlerManager {
public static List<MappingHandler> mappingHandlerList = new ArrayList<>();
//项目初始化时,这个静态方法会被调用
public static void resolveMappingHandler(List<Class<?>> classList) {
for (Class<?> cls : classList) {
if (cls.isAnnotationPresent(Controller.class)) {
parseHandlerFromController(cls);
}
}
}
private static void parseHandlerFromController(Class<?> cls) {
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
//寻找加了@RequestMapping的函数
if (!method.isAnnotationPresent(RequestMapping.class)) {
continue;
}
String uri = method.getDeclaredAnnotation(RequestMapping.class).value();
List<String> paramNameList = new ArrayList<>();
for (Parameter parameter : method.getParameters()) {
if (parameter.isAnnotationPresent(RequestParam.class)) {
paramNameList.add(parameter.getDeclaredAnnotation(RequestParam.class).value());
}
}
String[] params = paramNameList.toArray(new String[paramNameList.size()]);
MappingHandler mappingHandler = new MappingHandler(uri, method, cls, params);
HandlerManager.mappingHandlerList.add(mappingHandler);
}
}
}
@Controller,@RequestMapping,@RequestParam
注解定义的代码暂且省略。
好了,请求来到了mappingHandler:
public class MappingHandler {
private String uri;
private Method method;
private Class<?> controller;
private String[] args; //这个是添加了@RequestParam的参数的参数列表
public boolean handle(ServletRequest req, ServletResponse res) throws IllegalAccessException, InstantiationException, InvocationTargetException, IOException {
String requestUri = ((HttpServletRequest) req).getRequestURI();
if (!uri.equals(requestUri)) {
return false;
}
Object[] parameters = new Object[args.length];
for (int i=0;i<args.length;i++) {
parameters[i] = req.getParameter(args[i]);
}
Object ctl = BeanFactory.getBean(controller);
Object response = method.invoke(ctl, parameters);
//将返回结果写入ServletResponse对象
res.getWriter().println(response.toString());
return true;
}
MappingHandler(String uri, Method method, Class<?> cls, String[] args) {
this.uri = uri;
this.method = method;
this.controller = cls;
this.args = args;
}
}
写入了数据的ServletResponse对象会转成字节发到前端,这个流程就结束了
为啥我要最后再讲初始化,,似乎更好理解?
回想我们使用spring的时候都会有一个Application类,就是下面这个熟悉的东西:
public class Application {
public static void main(String[] args) {
MiniApplication.run(Application.class, args);
}
}
我们来看看MiniApplication.run(Application.class, args)
public static void run(Class<?> cls, String[] args) {
System.out.println("Hello mini-spring!");
TomcatServer tomcatServer = new TomcatServer(args);
try {
//1、启动服务器
tomcatServer.startServer();
//2、扫描src中的类文件
List<Class<?>> classList = ClassScanner.scanClasses(cls.getPackage().getName());
//3、初始化BeanFactory
BeanFactory.initBean(classList);
//4、建立mappingHandlerList
HandlerManager.resolveMappingHandler(classList);
//5、打印类信息
classList.forEach(it-> System.out.println(it.getName()));
} catch (Exception e) {
e.printStackTrace();
}
}
其中第2步需要细说一下:
先说一个注意点,我们传入的参数是:cls.getPackage().getName()
就是说只会去扫描该包下的类文件,也就是说为什么我们要把Application.java文件放在最外面
public class ClassScanner {
public static List<Class<?>> scanClasses(String packageName) throws IOException, ClassNotFoundException {
List<Class<?>> classList = new ArrayList<>();
String path = packageName.replace(".", "/");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
if (resource.getProtocol().contains("jar")) {
JarURLConnection jarURLConnection = (JarURLConnection) resource.openConnection();
String jarFilePath = jarURLConnection.getJarFile().getName();
classList.addAll(getClassesFromJar(jarFilePath, path));
}else {
// todo
}
}
return classList;
}
private static List<Class<?>> getClassesFromJar(String jarFilePath, String path) throws IOException, ClassNotFoundException {
List<Class<?>> classes = new ArrayList<>();
JarFile jarFile = new JarFile(jarFilePath);
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String entryName = jarEntry.getName();// com/mooc/zbs/test/Test.class
if (entryName.startsWith(path) && entryName.endsWith(".class")) {
String classFullName = entryName.replace("/", ".").substring(0, entryName.length() - 6);
classes.add(Class.forName(classFullName));
}
}
return classes;
}
}
借助了classLoader可以访问文件资源的特性
具体代码没有细读,就不说了。
原文:https://www.cnblogs.com/lnu161403214/p/11062198.html