java的类加载机制默认情况下是采用委托模型:当加载某个类时JVM会首先尝试用当前类加载器的父类加载器加载该类,若父类加载器加载不到再由当前类加载器来加载,因此这种模型又叫做“父优先”模型。
但是在实际项目中我们可能会要求先从当前类加载加载再从父类加载器加载,如项目中的某类的版本可能和container中的不一致的时候,若还从container加载就会报jar包冲突的异常,实际上jar包冲突的问题在实际开发过程中是经常会遇到的。如我们在开发Loong时就遇到了类似问题。
解决方案是通过扩展自定义的ClassLoader,重写loadClass方法,先从当前类加载器加载再从父类加载器加载。
- public class MCFClassLoader extends URLClassLoader {
- public MCFClassLoader(URL[] urls) {
- super(urls);
- }
- public MCFClassLoader(URL[] urls, ClassLoader parent) {
- super(urls, parent);
- }
- public MCFClassLoader(URL[] urls, ClassLoader parent,
- URLStreamHandlerFactory factory) {
- super(urls, parent, factory);
- }
- public Class<?> loadClass(String name) throws ClassNotFoundException {
- Class c = findLoadedClass(name);
- if (c == null) {
- try {
- c = findClass(name);
- } catch (ClassNotFoundException e) {
- return super.loadClass(name);
- }
- }
- return c;
- }
- }
通过上面的ClassLoader就解决了我们遇到的问题。
思考:通过扩展URLClassLoader可以实现好多有趣的功能,如支持多父、支持加载顺序配置等等。
作为补充给出一个使用上面的ClassLoader的示例代码:
- public ClassLoader getDSClassLoader(String moudleName) {
- if (DSClassLoader == null) {
- try {
- DSClassLoader = new MCFClassLoader(
- new URL[] {
- new URL("......xxx.jar"),
- new URL("......yyy.jar")},
- ConnectorConfigurationParserServiceImpl.class
- .getClassLoader());
- } catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- return DSClassLoader;
- }
上面的例子说明当xxx.jar或yyy.jar中有需要加载的类时就从这些jar包里加载,即使所在的container里有同样的类,这样可在一定程度上避免jar包版本冲突的问题!
相关推荐
当一个类加载器接收到加载类的请求时,它首先会委托其父类加载器去尝试加载,如果父类加载器无法加载,再由当前加载器尝试。这个过程一直向上,直到Bootstrap类加载器,如果Bootstrap也无法加载,再回退到原始的类...
目录<br><br>前言<br>1. 一般信息<br>1.1. 关于本手册<br>1.2. 本手册采用的惯例<br>1.3. MySQL AB概述<br>1.4. MySQL数据库管理系统概述<br>1.4.1. MySQL的历史<br>1.4.2. MySQL的的主要特性<br>1.4.3. MySQL稳定性...
- **拦截器配置**:拦截器通过`<interceptors>`元素定义。例如: ```xml <interceptors> <interceptor name="myCustomInterceptor" class="com.example.MyCustomInterceptor"/> </interceptors> ``` - **默认...
在Java中,类加载器按照层次结构进行组织,包括引导类加载器、扩展类加载器和应用程序类加载器,每个都有特定的职责。 1. **引导类加载器(Bootstrap ClassLoader)**:这是最基础的类加载器,由JVM本身实现,主要...
2. Extension类加载器:Extension类加载器是负责加载JDK中的扩展类的类加载器。 3. Application类加载器:Application类加载器是负责加载应用程序中的类的类加载器。 类加载顺序 当多个Jar包中包含相同的包名和...
<param-value>/WEB-INF/applicationContext-hibernate.xml, /WEB-INF/applicationContext-service.xml</param-value> </context-param> ``` 5. **获取ApplicationContext引用**: 在Web应用中,你可以通过`...
使用`<mime-mapping>`元素定义文件扩展名与其对应的MIME类型,如`<mime-mapping><extension>pdf</extension><mime-type>application/pdf</mime-type></mime-mapping>`。 13. **定位TLD** `<taglib>`元素用于指定...
系统类加载器在加载类时,会先尝试让扩展类加载器加载,如果扩展类加载器无法加载,则再由系统类加载器自己尝试加载。这样的设计是为了保证核心类库的唯一性和安全性,避免用户自定义的类覆盖了 JDK 内置的核心类。 ...
扩展类加载器的父加载器是引导类加载器,尽管在Java中它表现为`null`。 3. **系统类加载器(Application ClassLoader)**:也称为应用类加载器,同样由Java编写,主要负责加载应用的类,即用户代码所在的`CLASSPATH...
- `<load-on-startup>`:设置容器加载Servlet的顺序。数字越小,优先级越高。这里设置为1表示容器启动时即加载该Servlet。 2. **配置URL映射** ```xml <servlet-mapping> <servlet-name>roadrantz</servlet-...
类加载机制遵循双亲委派模型,即一个类加载请求会首先交给父加载器处理,只有当父加载器无法加载时,才会由当前加载器尝试。这样设计可以避免类的重复加载,保证核心类的一致性。 3. **类的生命周期** 类的生命...
- `<listener>`节点定义的监听器类实例随后被创建。监听器允许开发者在Web应用程序的生命周期事件(如启动、关闭)中执行自定义代码。 - `<context-param>`的值可以在监听器的`contextInitialized...
JVM采用**父类委托机制**来加载类,这意味着当一个类加载器接收到加载请求时,它首先会委托给其父类加载器尝试加载,直到达到Bootstrap类加载器(顶级加载器)。如果父类加载器找不到所需类,那么请求会回溯到子类...
Struts2框架的配置文件加载顺序是: 1. `struts-default.xml` 2. `struts-plugin.xml` 3. `struts.xml` 4. `struts.properties` 5. `web.xml` 在这个顺序中,配置文件的加载和解析遵循从上到下的顺序,后面的配置会...
类加载器遵循双亲委派模型,这意味着当一个类加载器尝试加载类时,它首先会将请求委托给其父类加载器,直到到达顶层的Bootstrap ClassLoader,如果父类加载器无法找到该类,子类加载器才会尝试自己加载。 在Tomcat...
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 设置局部参数,加载springmvc的配置文件 --> <init-param> <param-name>contextConfigLocation</param-name> <param-...
* -bootclasspath<pathlist>:覆盖由引导类加载器加载的类文件位置 * -verbose:打印堆栈大小,方法的局部变量和参数的数目 二、Java 字节代码是怎样使程序避免程序的内存错误 Java 字节码可以帮助开发者避免程序...