本发明涉及模块加载技术领域,更具体的说,涉及一种模块动态加载方法及装置。
背景技术:
在java web应用中,通常存在很多需要长时间持续运行的B/S应用,有时这些应用会需要添加或删除一些应用模块,这时就需要采用模块动态加载技术,以实现在不停止应用的情况下,动态的添加或删除应用模块。
目前,常用的模块动态加载技术是OSGi技术,OSGi技术是Java动态化模块化系统的一系列规范以及基于该规范的技术实现,是一种更细粒度上的模块动态加载技术。虽然OSGi技术可以实现对应用模块的动态加载,但是当一个项目在架构时没有采用OSGi技术,而在项目开发过程中增加了模块动态加载需求(例如对MVC模块的动态加载需求)时,可能就需要重新构建项目架构。由于OSGi技术具有较高的复杂度,因此重新构建项目架构必然会导致学习成本增加,并且还会耗费较多的人力和时间。
综上,如何提供一种模块动态加载方法及系统,以实现在保持项目架构不变的情况下仍可实现对模块的动态加载是本领域技术人员亟待解决的技术问题。
技术实现要素:
有鉴于此,本发明公开一种模块动态加载方法及装置,以实现在保持项目架构不变的情况下仍可实现对模块的动态加载。
一种模块动态加载方法,包括:
当需要动态加载应用模块时,构建一个新的servlet服务对象;
当接收到servlet请求时,将所述servlet请求发送给原始的servlet服务对象;
利用所述原始的servlet服务对象将所述servlet请求转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载;
当所述新的servlet服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象。
优选的,所述当需要动态加载应用模块时,构建一个新的servlet服务对象包括:
当需要动态加载应用模块时,获取所述应用模块需要加载的所有资源;
利用所述所有资源构造预先定义的类加载器ClassLoader;
调用spring请求分发器的初始化方法,对所述ClassLoader中的资源进行构建得到所述新的servlet服务对象;
将所述新的servlet服务对象的地址保存至所述原始的servlet服务对象中。
优选的,所述利用所述所有资源构造预先定义的类加载器ClassLoader包括:
将所述所有资源分为固定类资源和变化类资源;
利用统一资源定位符加载器URLClassLoader对所述固定类资源进行构造得到父加载器;
将所述父加载器作为父类,利用所述URLClassLoader对所述变化类资源进行构造得到子加载器,其中,所述父加载器和所述子加载器构成所述ClassLoader。
优选的,所述利用所述原始的servlet服务对象将所述servlet请求转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载包括:
判断所述servlet请求中是否存在属于同种类型但分属不同ClassLoader的请求;
若存在所述请求,则对所述请求对应的第一请求实体中的属性进行复制,得到所述第一请求实体的复制属性;
根据所述复制属性和预先定义的ClassLoader中的资源,得到第二请求实体,其中所述资源为所述应用模块需要加载的所有资源;
利用所述原始的servlet服务对象将所述第二请求实体转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载。
优选的,所述当所述新的servlet服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象的过程包括:
当所述新的servlet服务对象构建完成后,销毁所述上一次模块动态加载时构建的servlet服务对象中网络应用容器内的资源,并将所述网络应用容器置为空;
销毁所述上一次模块动态加载时构建的servlet服务对象中子加载器内的资源,并将所述子加载器置为空;
销毁所述上一次模块动态加载时构建的servlet服务对象。
优选的,在销毁所述上一次模块动态加载时构建的servlet服务对象之后,还包括:
采用系统垃圾回收方法对销毁所述上一次模块动态加载时构建的servlet服务对象的过程中生成的垃圾进行回收。
一种模块动态加载装置,包括:
构建单元,用于当需要动态加载应用模块时,构建一个新的servlet服务对象;
发送单元,用于当接收到servlet请求时,将所述servlet请求发送给原始的servlet服务对象;
转发单元,用于利用所述原始的servlet服务对象将所述servlet请求转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载;
销毁单元,用于当所述新的servlet服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象。
优选的,所述构建单元包括:
获取子单元,用于当需要动态加载应用模块时,获取所述应用模块需要加载的所有资源;
构造子单元,用于利用所述所有资源构造预先定义的类加载器ClassLoader;
实例化子单元,用于调用spring请求分发器的初始化方法,对所述ClassLoader中的资源进行构建得到所述新的servlet服务对象;
保存子单元,用于将所述新的servlet服务对象的地址保存至所述原始的servlet服务对象中。
优选的,所述构造子单元包括:
资源种类划分子单元,用于将所述所有资源分为固定类资源和变化类资源;
父加载器构造子单元,用于利用统一资源定位符加载器URLClassLoader对所述固定类资源进行构造得到父加载器;
子加载器构造子单元,用于将所述父加载器作为父类,利用所述URLClassLoader对所述变化类资源进行构造得到子加载器,其中,所述父加载器和所述子加载器构成所述ClassLoader。
优选的,所述转发单元包括:
判断子单元,用于判断所述servlet请求中是否存在属于同种类型但分属不同ClassLoader的请求;
复制子单元,用于在所述判断子单元判断为是的情况下,则对所述请求对应的第一请求实体中的属性进行复制,得到所述第一请求实体的复制属性;
第二请求实体获取子单元,用于根据所述复制属性和预先定义的ClassLoader中的资源,得到第二请求实体,其中所述资源为所述应用模块需要加载的所有资源;
转发子单元,用于利用所述原始的servlet服务对象将所述第二请求实体转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载。
优选的,所述销毁单元包括:
第一销毁子单元,用于当所述新的servlet服务对象构建完成后,销毁所述上一次模块动态加载时构建的servlet服务对象中网络应用容器内的资源,并将所述网络应用容器置为空;
第二销毁子单元,用于销毁所述上一次模块动态加载时构建的servlet服务对象中子加载器内的资源,并将所述子加载器置为空;
第三销毁子单元,用于销毁所述上一次模块动态加载时构建的servlet服务对象。
优选的,还包括:
垃圾回收子单元,用于在销毁所述上一次模块动态加载时构建的servlet服务对象之后,采用系统垃圾回收方法对销毁所述上一次模块动态加载时构建的servlet服务对象的过程中生成的垃圾进行回收。
从上述的技术方案可知,本发明公开了一种模块动态加载方法及装置,当需要动态加载应用模块时,构建一个新的servlet服务对象,当接收到servlet请求时,利用原始的servlet服务对象将接收到的servlet请求转发给新的servlet服务对象,以通过新的servlet服务对象实现对应用模块的动态加载,并在新的服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象。由此可知,采用本发明公开的方法无需重新构建项目架构,在每次动态加载应用模块时,只需构建新的servlet服务对象即可,因此,本发明实现了在保持项目架构不变的情况下仍可实现对模块的动态加载,不仅易于实现,而学习成本低,耗费的人力和时间较少。
附图说明
为了更清楚地说明本发明实施例或现有技术中的技术方案,下面将对实施例或现有技术描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本发明的实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据公开的附图获得其他的附图。
图1为本发明实施例公开的一种模块动态加载方法的方法流程图;
图2为本发明实施例公开的一种构建新的servlet服务对象的方法流程图;
图3为本发明实施例公开的一种销毁原始的servlet服务对象的方法流程图;
图4为本发明实施例公开的一种模块动态加载装置的结构示意图;
图5为本发明实施例公开的一种构建单元的结构示意图;
图6为本发明实施例公开的一种构建单元的结构示意图。
具体实施方式
下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。
本发明实施例公开了一种模块动态加载方法及装置,以实现在保持项目架构不变的情况下仍可实现对模块的动态加载。
参见图1,本发明实施例公开的一种模块动态加载方法的方法流程图,该方法包括步骤:
步骤S101、当需要动态加载应用模块时,构建一个新的servlet服务对象;
其中,需要动态加载的应用模块可以为MVC模块。
Servlet的全称为Java Servlet,是用Java编写的服务器端程序。
步骤S102、当接收到servlet请求时,将servlet请求发送给原始的servlet服务对象;
需要说明的是,由于新的servlet服务对象和原始的servlet服务对象分属不同的ClassLoader(类加载器),新的servlet服务对象对于服务器是不可见的,因此对于客户端发送的servlet请求,服务器仍会将其发送给原始的servlet服务对象。
步骤S103、利用所述原始的servlet服务对象将所述servlet请求转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载;
其中,为使新的servlet服务对象生效,服务器需通过原始的servlet服务对象将servlet请求转发给新的servlet服务对象,以通过新的servlet服务对象实现对应用模块的动态加载。
步骤S104、当新的servlet服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象。
需要说明的是,原始的servlet服务对象是由服务器(例如,Tomcat)构建的,所有通过服务器的请求都会发送给原始的servlet服务对象进行处理,本发明通过将发送给原始的servlet服务对象的servlet请求转发给新的servlet服务对象进行处理,实现将servlet请求从原始的servlet服务对象转发至新的servlet服务对象,以实现对应用模块的动态加载。因此,本发明中服务器中实际上有两个servlet服务对象:一个原始的servlet服务对象和一个新的servlet服务对象,新的servlet服务对象的地址保存在原始的servlet服务对象中,原始的servlet服务对象始终存在,不会被销毁。在每次新的servlet服务对象创造完成后,新的servlet服务对象就会代替上一次模块动态加载时构建的servlet服务对象,基于服务器性能的考虑,还需要销毁上一次模块动态加载时构建的servlet服务对象。
其中,本发明不对原始的servlet服务对象进行修改而是构建新的servlet服务对象的原因为:原始的servlet服务对象是由服务器(例如,Tomcat)构建的,所有通过服务器的请求都会发送给原始的servlet服务对象进行处理。若需要将客户端发送的请求转交到另外的servlet服务对象,就必须修改服务器的servlet构建机制或请求发送机制,这样就会深入至服务器的细节,对具体的服务器产生依赖,最终造成项目和服务器的高度耦合。因此,本发明并没有采用直接修改原始的servlet服务对象的技术手段,而是采用构建新的servlet服务对象,通过原始的servlet服务对象将servlet请求转发给新的servlet服务对象,实现对应用模块的动态加载,其中,该应用模块可以为新的应用模块。
综上可知,本发明在每次动态加载应用模块时,会构建一个新的servlet服务对象,然后利用原始的servlet服务对象将servlet请求转发给新的servlet服务对象,通过新的servlet服务对象实现对应用模块的动态加载。相比现有方案而言,本发明无需重新构建项目架构,在每次动态加载应用模块时,只需构建新的servlet服务对象即可,因此实现了在保持项目架构不变的情况下仍可实现对模块的动态加载,不仅易于实现,而且学习成本低,耗费的人力和时间较少。
另外,相比现有技术而言,本发明实现方案简单易行,不需要开发者对动态加载应用模块的细节进行过多的关注,方便开发者使用,且易于维护。
需要说明的是,本发明是基于轻量级的SpringMVC框架实现的。
为进一步优化上述实施例,参见图2,本发明还公开了构建新的servlet服务对象的具体过程,包括步骤:
步骤S201、当需要动态加载应用模块时,获取应用模块需要加载的所有资源;
其中,应用模块需要加载的所有资源包括:class文件、jar包、配置文件等。
步骤S202、利用所有资源构造预先定义的ClassLoader;
其中,Classloader(中文名称为:类加载器)是一种用来加载java类到Java虚拟机中的一种加载器。
由于新的servlet服务对象和原始的servlet服务对象分属不同的ClassLoader,因此,需针对新的servlet服务对象预先定义一个ClassLoader。
步骤S203、调用spring请求分发器的初始化方法,对所述ClassLoader中的资源进行构建得到新的servlet服务对象;
具体的,利用java的反射机制,调用spring请求分发器的初始化方法,对所述ClassLoader中的资源进行构建得到新的servlet服务对象。
步骤S204、将新的servlet服务对象的地址保存至原始的servlet服务对象中。
其中,将新的servlet服务对象的地址保存至原始的servlet服务对象中的目的是:使原始的servlet服务对象在接收到servlet请求后,可以通过该地址找到新的servlet服务对象,以将servlet请求转发至新的servlet服务对象。
其中,本实施例中,步骤S202具体可以包括:
首先将应用模块需要加载的所有资源分为固定类资源和变化类资源;其次利用URLClassLoader(中文名称:统一资源定位符加载器)对所述固定类资源进行构造得到父加载器;再次将父加载器作为父类,利用URLClassLoader对变化类资源进行构造得到子加载器,其中,父加载器和子加载器构成步骤S202中的ClassLoader。
需要说明的是,每次需要动态加载应用模块时,都需要重新构造子加载器,与此同时,父加载器可一直保持不变。
其中,上述实施例中,步骤S103利用原始的servlet服务对象将servlet请求转发给新的servlet服务对象进行处理,以通过新的servlet服务对象实现对所述应用模块的动态加载的过程具体包括:
首先,判断servlet请求中是否存在属于同种类型但分属不同ClassLoader的请求,若存在该请求,则对该请求对应的第一请求实体中的属性进行复制,得到第一请求实体的复制属性;然后根据复制属性和预先定义的ClassLoader中的资源(也即步骤S202中的预先定义的ClassLoader中的资源,该资源也为应用模块需要加载的所有资源),得到第二请求实体;最后利用原始的servlet服务对象将第二请求实体转发给所述新的servlet服务对象进行处理,以通过新的servlet服务对象实现对应用模块的动态加载。
需要说明的是,本实施例也即修改扩展spring的网络异步请求工具类的过程。
为进一步优化上述实施例,参见图3,本发明还公开了销毁原始的servlet服务对象的具体过程,包括步骤:
步骤S301、当新的servlet服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象中网络应用容器(WebApplicationContext)内的资源,并将所述网络应用容器置为空;
步骤S302、销毁上一次模块动态加载时构建的servlet服务对象中子加载器内的资源,并将该子加载器置为空;
步骤S303、销毁上一次模块动态加载时构建的servlet服务对象。
可以理解的是,在销毁上一次模块动态加载时构建的servlet服务对象的过程中,必然会产生很多系统垃圾,系统垃圾不仅占据系统内存,还会影响系统的运行速度,因此,本发明在销毁完上一次模块动态加载时构建的servlet之后,还会对整个销毁过程生成的垃圾进行清除。
因此,为进一步优化上述实施例,在步骤S303之后,还可以包括:
步骤S304、采用系统垃圾回收方法对销毁上一次模块动态加载时构建的servlet服务对象的过程中生成的垃圾进行回收。
其中,系统垃圾回收方法可以选用System.gc()。
与上述方法实施例相对应,本发明还公开了一种模块动态加载装置。
参见图4,本发明实施例公开的一种模块动态加载装置的结构示意图,该装置包括:
构建单元401,用于当需要动态加载应用模块时,构建一个新的servlet服务对象;
需要说明的是,由于新的servlet服务对象和原始的servlet服务对象分属不同的ClassLoader(类加载器),新的servlet服务对象对于服务器是不可见的,因此对于客户端发送的servlet请求,服务器仍会将其发送给原始的servlet服务对象。
发送单元402,用于当接收到servlet请求时,将所述servlet请求发送给原始的servlet服务对象;
转发单元403,用于利用所述原始的servlet服务对象将所述servlet请求转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载;
其中,为使新的servlet服务对象生效,服务器需通过原始的servlet服务对象将servlet请求转发给新的servlet服务对象,以通过新的servlet服务对象实现对应用模块的动态加载。
销毁单元404,用于当新的servlet服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象。
需要说明的是,原始的servlet服务对象是由服务器(例如,Tomcat)构建的,所有通过服务器的请求都会发送给原始的servlet服务对象进行处理,本发明通过将发送给原始的servlet服务对象的servlet请求转发给新的servlet服务对象进行处理,实现将servlet请求从原始的servlet服务对象转发至新的servlet服务对象,以实现对应用模块的动态加载。因此,本发明中服务器中实际上有两个servlet服务对象:一个原始的servlet服务对象和一个新的servlet服务对象,新的servlet服务对象的地址保存在原始的servlet服务对象中,原始的servlet服务对象始终存在,不会被销毁。在每次新的servlet服务对象创造完成后,新的servlet服务对象就会代替上一次模块动态加载时构建的servlet服务对象,基于服务器性能的考虑,还需要销毁上一次模块动态加载时构建的servlet服务对象。
综上可知,本发明在每次动态加载应用模块时,会构建一个新的servlet服务对象,然后利用原始的servlet服务对象将servlet请求转发给新的servlet服务对象,通过新的servlet服务对象实现对应用模块的动态加载。相比现有方案而言,本发明无需重新构建项目架构,在每次动态加载应用模块时,只需构建新的servlet服务对象即可,因此实现了在保持项目架构不变的情况下仍可实现对模块的动态加载,不仅易于实现,而且学习成本低,耗费的人力和时间较少。
另外,相比现有技术而言,本发明实现方案简单易行,不需要开发者对动态加载应用模块的细节进行过多的关注,方便开发者使用,且易于维护。
需要说明的是,本发明是基于轻量级的SpringMVC框架实现的。
为进一步优化上述实施例,参见图5,本发明实施例公开的一种构建单元的结构示意图,包括:
获取子单元501,用于当需要动态加载应用模块时,获取所述应用模块需要加载的所有资源;
其中,应用模块需要加载的所有资源包括:class文件、jar包、配置文件等。
构造子单元502,用于利用所述所有资源构造预先定义的类加载器ClassLoader;
实例化子单元503,用于调用spring请求分发器的初始化方法,对所述ClassLoader中的资源进行构建得到所述新的servlet服务对象;
保存子单元504,用于将所述新的servlet服务对象的地址保存至所述原始的servlet服务对象中。
其中,将新的servlet服务对象的地址保存至原始的servlet服务对象中的目的是:使原始的servlet服务对象在接收到servlet请求后,可以通过该地址找到新的servlet服务对象,以将servlet请求转发至新的servlet服务对象。
其中,本实施例中,构造子单元502具体可以包括:
资源种类划分子单元,用于将所述所有资源分为固定类资源和变化类资源;
父加载器构造子单元,用于利用统一资源定位符加载器URLClassLoader对所述固定类资源进行构造得到父加载器;
子加载器构造子单元,用于将所述父加载器作为父类,利用所述URLClassLoader对所述变化类资源进行构造得到子加载器,其中,所述父加载器和所述子加载器构成所述ClassLoader。
需要说明的是,每次需要动态加载应用模块时,都需要重新构造子加载器,与此同时,父加载器可一直保持不变。
其中,为进一步优化上述实施例,转发单元403具体可以包括:
判断子单元,用于判断所述servlet请求中是否存在属于同种类型但分属不同ClassLoader的请求;
复制子单元,用于在所述判断子单元判断为是的情况下,则对所述请求对应的第一请求实体中的属性进行复制,得到所述第一请求实体的复制属性;
第二请求实体获取子单元,用于根据所述复制属性和预先定义的ClassLoader中的资源,得到第二请求实体,其中所述资源为所述应用模块需要加载的所有资源;
转发子单元,用于利用所述原始的servlet服务对象将所述第二请求实体转发给所述新的servlet服务对象进行处理,以通过所述新的servlet服务对象实现对所述应用模块的动态加载。
需要说明的是,本实施例也即修改扩展spring的网络异步请求工具类的过程。
为进一步优化上述实施例,参加图6,本发明实施例公开的一种销毁单元的结构示意图,销毁单元包括:
第一销毁子单元601,用于当新的servlet服务对象构建完成后,销毁上一次模块动态加载时构建的servlet服务对象中网络应用容器(WebApplicationContext)内的资源,并将所述网络应用容器置为空;
第二销毁子单元602,用于上一次模块动态加载时构建的servlet服务对象中子加载器内的资源,并将该子加载器置为空;
第三销毁子单元603,用于销毁上一次模块动态加载时构建的servlet服务对象。
可以理解的是,在销毁上一次模块动态加载时构建的servlet服务对象的过程中,必然会产生很多系统垃圾,系统垃圾不仅占据系统内存,还会影响系统的运行速度,因此,本发明在销毁完上一次模块动态加载时构建的servlet后,还会对整个销毁过程生成的垃圾进行清除。
因此,为进一步优化上述实施例,还可以包括:
垃圾回收子单元604,用于在第三销毁子单元603销毁上一次模块动态加载时构建的servlet之后,采用系统垃圾回收方法对销毁上一次模块动态加载时构建的servlet服务对象的过程中生成的垃圾进行回收。
其中,系统垃圾回收方法可以选用System.gc()。
需要说明的是,装置实施例中各组成部分的具体工作原理请参见方法实施例对应部分,此处不再赘述。
最后,还需要说明的是,在本文中,诸如第一和第二等之类的关系术语仅仅用来将一个实体或者操作与另一个实体或操作区分开来,而不一定要求或者暗示这些实体或操作之间存在任何这种实际的关系或者顺序。而且,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、物品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、物品或者设备所固有的要素。在没有更多限制的情况下,由语句“包括一个……”限定的要素,并不排除在包括所述要素的过程、方法、物品或者设备中还存在另外的相同要素。
本说明书中各个实施例采用递进的方式描述,每个实施例重点说明的都是与其他实施例的不同之处,各个实施例之间相同相似部分互相参见即可。
对所公开的实施例的上述说明,使本领域专业技术人员能够实现或使用本发明。对这些实施例的多种修改对本领域的专业技术人员来说将是显而易见的,本文中所定义的一般原理可以在不脱离本发明的精神或范围的情况下,在其它实施例中实现。因此,本发明将不会被限制于本文所示的这些实施例,而是要符合与本文所公开的原理和新颖特点相一致的最宽的范围。