仿写一个简陋的 IOC/AOP 框架 mini-spring (2)

下面指定了 jar 包的打包设置,首先使用 manifest 设置主类,否则生成的 jar 包找不到主类清单,会无法运行。还使用了 from 语句来设置打包范围,这是固定句式,用来收集所有的 java 类文件。

framework 实现流程

如下图:

仿写一个简陋的 IOC/AOP 框架 mini-spring

启动 tomcat 服务 public void startServer() throws LifecycleException { tomcat = new Tomcat(); tomcat.setPort(8080); tomcat.start(); // new 一个标准的 context 容器并设置访问路径; // 同时为 context 设置生命周期监听器。 Context context = new StandardContext(); context.setPath(""); context.addLifecycleListener(new Tomcat.FixContextListener()); // 新建一个 DispatcherServlet 对象,这个是我们自己写的 Servlet 接口的实现类, // 然后使用 `Tomcat.addServlet()` 方法为 context 设置指定名字的 Servlet 对象, // 并设置为支持异步。 DispatcherServlet servlet = new DispatcherServlet(); Tomcat.addServlet(context, "dispatcherServlet", servlet) .setAsyncSupported(true); // Tomcat 所有的线程都是守护线程, // 如果某一时刻所有的线程都是守护线程,那 JVM 会退出, // 因此,需要为 tomcat 新建一个非守护线程来保持存活, // 避免服务到这就 shutdown 了 context.addServletMappingDecoded("http://www.likecs.com/", "dispatcherServlet"); tomcat.getHost().addChild(context); Thread tomcatAwaitThread = new Thread("tomcat_await_thread") { @Override public void run() { TomcatServer.this.tomcat.getServer().await(); } }; tomcatAwaitThread.setDaemon(false); tomcatAwaitThread.start(); }

这里看代码注释,结合下面这张 tomcat 架构图就可以理解了。

仿写一个简陋的 IOC/AOP 框架 mini-spring

图片来自

如果暂时不理解也没关系,不影响框架学习,我只是为了玩一玩内嵌 tomcat,完全可以自己实现一个乞丐版的网络服务器的。

这里使用的是我们自定义的 Servlet 子类 DispatcherServlet 对象,该类重写了 service() 方法,代码如下:

@Override public void service(ServletRequest req, ServletResponse res) throws IOException { for (MappingHandler mappingHandler : HandlerManager.mappingHandlerList) { // 从所有的 MappingHandler 中逐一尝试处理请求, // 如果某个 handler 可以处理(返回true),则返回即可 try { if (mappingHandler.handle(req, res)) { return; } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } res.getWriter().println("failed!"); }

HandlerManager 和 MappingHandler 处理器后面会讲,这里先不展开。至此,tomcat 服务器启动完成;

扫描类

扫描类是通过这句代码完成的:

// 扫描类 List<Class<?>> classList = ClassScanner.scannerCLasses(cls.getPackage().getName());

ClassScanner.scannerCLasses 方法实现如下:

public static List<Class<?>> scannerCLasses(String packageName) throws IOException, ClassNotFoundException { List<Class<?>> classList = new ArrayList<>(); String path = packageName.replace(".", "http://www.likecs.com/"); // 线程上下文类加载器默认是应用类加载器,即 ClassLoader.getSystemClassLoader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // 使用类加载器对象的 getResources(ResourceName) 方法获取资源集 // Enumeration 是古老的迭代器版本,可当成 Iterator 使用 Enumeration<URL> resources = classLoader.getResources(path); while (resources.hasMoreElements()) { URL url = resources.nextElement(); // 获取协议类型,判断是否为 jar 包 if (url.getProtocol().contains("jar")) { // 将打开的 url 返回的 URLConnection 转换成其子类 JarURLConnection 包连接 JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection(); String jarFilePath = jarURLConnection.getJarFile().getName(); // getClassesFromJar 工具类获取指定 Jar 包中指定资源名的类; classList.addAll(getClassesFromJar(jarFilePath, path)); } else { // 简单起见,我们暂时仅实现扫描 jar 包中的类 // todo } } return classList; } private static List<Class<?>> getClassesFromJar(String jarFilePath, String path) throws IOException, ClassNotFoundException { // 为减少篇幅,这里完整代码就不放出来了 }

注释很详细,就不多废话了。

初始化Bean工厂

这部分是最重要的,IOC 和 AOP 都在这里实现。

代码请到在 BeanFactory 类中查看,GitHub 在线查看 BeanFactory

注释已经写的非常详细。这里简单说下处理逻辑。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpypzx.html