- 浏览: 842458 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
renzhengzhi:
请教一下楼主,公有云和私有云的开发,具体要做哪些工作呢?我拿到 ...
4,云的4 种模式 -
SangBillLee:
我用了solr5.5,用SolrQuery查询,没法高亮,不知 ...
solr5.x快速入门 -
lw900925:
这翻译读起来真是别扭。
solr in action翻译-第一章1.1 -
springjpa_springmvc:
spring mvc demo教程源代码下载,地址:http: ...
Spring MVC性能提升 -
h416373073:
正遇到了此问题不知如何解决, 多谢分享
solr错误
库(repository)和源(resources)。库表示加载器查找的地方,源表示加载器中的DirContext对象,它的文档基(document base)指向了上下文的文档基。
一个servlet容器需要一个定制的容器,而不是简单的使用系统的加载器
如果使用系统的加载器来加载servlet和其他需要的类,这样servlet就可以进入Java虚拟机CLASSPATH环境下面的任何类和类库,这会带来安全隐患
在Catalina中,加载器使用org.apache.catalina.Loader接口表示
Tomcat需要一个自己的加载器的另一个原因是它需要支持在WEB-INF/classes或者是WEB-INF/lib目录被改变的时候会重新加载
要支持类的自动加载功能,一个加载器类必须实现org.apache.catalina.loader.Reloader接口
Java的类加载机制
在每次创建一个Java类的实例时候,必须先将该类加载到内存中
Java虚拟机(JVM)使用类加载器来加载类。Java加载器在Java核心类库和CLASSPATH环境下面的所有类中查找类。
如果需要的类找不到,会抛出java.lang.ClassNotFoundException异常。
JVM使用了三种类加载器:bootstrap类加载器、extension类加载器和systen类加载器。
这三个加载器是父子关系,其中bootstrap类加载器在顶端,而system加载器在结构的最底层。
其中bootstrap类加载器用于引导JVM,一旦调用java.exe程序,bootstrap类加载器就开始工作。因此,它必须使用本地代码实现,然后加载JVM需要的类到函数中。
另外,它还负责加载所有的Java核心类,例如java.lang和java.io包。另外bootstrap类加载器还会查找核心类库如rt.jar、i18n.jar等,这些类库根据JVM和操作系统来查找。
extension类加载器负责加载标准扩展目录下面的类。这样就可以使得编写程序变得简单,只需把JAR文件拷贝到扩展目录下面即可,类加载器会自动的在下面查找。
不同的供应商提供的扩展类库是不同的,Sun公司的JVM的标准扩展目录是/jdk/jre/lib/ext。
system加载器是默认的加载器,它在环境变量CLASSPATH目录下面查找相应的类。
JVM使用哪个类加载器?答案在于委派模型(delegation model),这是出于安全原因
每次一类需要加载,system类加载器首先调用。但是,它不会马上加载类。相反,它委派该任务给它的父类-extension类加载器。extension类加载器也把任务委派给它的父类bootstrap类加载器
因此,bootstrap类加载器总是首先加载类。如果bootstrap类加载器不能找到所需要的类的extension类加载器会尝试加载类。
如果扩展类加载器也失败,system类加载器将执行任务。如果系统类加载器找不到类,一个java.lang.ClassNotFoundException异常。
为什么需要这样的往返模式?
委派模型对于安全性是非常重要的。如你所知,可以使用安全管理器来限制访问某个目录。
现在,恶意的意图有人能写出一类叫做java.lang.Object,可用于访问任何在硬盘上的目录。
因为JVM的信任java.lang.Object类,它不会关注这方面的活动。因此,如果自定义java.lang.Object被允许加载的安全管理器将很容易瘫痪。
工作原理。
当自定义java.lang.Object类在程序中被调用的时候,system类加载器将该请求委派给extension类加载器,然后委派给bootstrap类加载器。
这样bootstrap类加载器先搜索的核心库,找到标准java.lang.Object并实例化它。
这样,自定义java.lang.Object类永远不会被加载
java.lang.ClassLoader抽象类来扩展自己的类加载器。
-------------------------------------------
Tomcat的需求自定义自己的类加载器原因包括以下内容
· 要制定类加载器的某些特定规则
· 缓存以前加载的类
· 事先加载类以预备使用
Loader接口
一个Tomcat类加载器表示一个Web应用程序加载器,而不是一个类加载器。
一个加载器必须实现org.apache.catalina.Loader接口。
加载器的实现使用定制的类加载器org.apache.catalina.loader.WebappClassLoader。
可以使用Loader接口的getClassLoader方法获取一个网络加载器ClassLoader。
Loader接口的addReposity方法用于添加一个库,findRepositories方法用于返回一个所有库的队列。
一个Tomcat的加载器通常跟一个上下文相关联,Loader接口的和getContainer及setContainer方法是建立此关联。
一个加载器还可以支持重新加载,如果在上下文中的一个或多个类已被修改。这样,一个servlet程序员可以重新编译servlet或辅助类,新类将被重新加载而不需要不重新启动Tomcat加载。
为了达到重新加载的目的,Loader接口有修改方法。在加载器的实现中,如果在其库中一个或多个类别已被修改,modeify方法必须返回true,因此需要重新加载。
setReloadable和getReloadable,用于确定加载器中是否可以使用重加载。
默认情况下,在标准的上下文实现中(org.apache.catalina.core.StandardContext类)重载机制并未启用。
因此,要使得上下文启动重载机制,需要在server.xml文件添加一些元素如下: <Context path="/myApp" docBase="myApp" debug="0" reloadable="true"/>
另外,一个加载器的实现可以确定是否委派给父加载器类。为了实现这一点,Loader接口提供了getDelegate和setDelegate方法。
public interface Loader { public ClassLoader getClassLoader(); public Container getContainer(); public void setContainer(Container container); public DefaultContext getDefaultContext(); public void setDefaultContext(DefaultContext defaultContext); public boolean getDelegate(); public void setDelegate(boolean delegate); public String getInfo(); public boolean getReloadable(); public void setReloadable(boolean reloadable); public void addPropertyChangeListener(PropertyChangeListenerlistener); public void addRepository(String repository); public String[] findRepositories(); public boolean modified(); public void removePropertyChangeListener(PropertyChangeListenerlistener); }
Catalina提供了org.apache.catalina.loader.WebappLoader作为Load接口的实现。
WebappLoader对象包含一个org.apache.catalina.loader.WebappClassLoader类的实例,该类扩展了Java.netURLClassLoader类。
Loader接口和它的实现类的结构图
Reloader接口
要支持自动重新加载,一个加载器的实现必须实现org.apache.catalina.loader.Reloader接口
public interface Reloader { public void addRepository(String repository); public String[] findRepositories (); public boolean modified(); }
Reloader接口里最重要的方法是modified方法,如果在web应用程序中的servlet任何支持类被修改的时候该方法返回true。
addRepository方法用于添加一个库而findRepositories方法用于返回实现了Reloader接口的加载器的所有的库。
WebappLoader类
org.apache.catalina.loader.WebappLoader类是Loader接口的实现,它表示一个web应用程序的加载器,负责给web应用程序加载类。
WebappLoader创建一个org.apache.catalina.loader.WebappClassLoader类的实例作为它的类加载器。
像其他的Catalina组件一样,WebappLoader实现了org.apache.catalina.Lifecycle接口,可有由关联容器启动和停止。
WebappLoader类还实现了java.lang.Runnable接口,所以可以通过一个线程来重复的调用modified方法,如果modified方法返回true,WebappLoader实例同志它的关联容器。
WebappLoader类的start方法被调用的时候,将会完成下面几项重要任务:
创建一个类加载器
设置库
设置类路径
设置访问权限
开启一个新线程用来进行自动重载
创建类加载器
WebappLoader使用一个内部类加载器来加载类。可以回头看Loader接口,该接口提供了getClassLoader方法但是并没有setClassLoader方法。
因此,不能通过传递一个WebappLoader来初始化它
private WebappClassLoader createClassLoader() throws Exception { Class clazz = Class.forName(loaderClass); WebappClassLoader classLoader = null; if (parentClassLoader == null) { classLoader = (WebappClassLoader) clazz.newInstance(); }else { Class[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; Constructor constr = clazz.getConstructor(argTypes); classLoader = (WebappClassLoader) constr.newInstance(args); } return classLoader; }
设置库
WebappLoader的start方法会调用setRepositories方法来给类加载器添加一个库。
WEB-INF/classes目录传递给加载器addRepository方法,而WEB-INF/lib传递给加载器的setJarPath方法。
这样,类加载器能能从WEB-INF/classes 目录下面和WEB-INF/lib目录下面部署的类库里加载类。
设置类路径
该任务由start方法调用setClassPath方法完成,setClassPath方法会给servlet上下文分配一个String类型属性保存Jasper JSP编译的类路径,
设置访问权限
如果Tomcat使用了安全管理器,setPermissions给类加载器给必要的目录添加访问权限,例如WEB-INF/classes和WEB-INF/lib。如果不使用管理器,该方法马上返回
开启自动重载线程
WebappLoader支持自动重载,如果WEB-INF/classes或者WEB-INF/lib目录被重新编译过,在不重启Tomcat的情况下必须自动重新载入这些类。
为了实现这个目的,WebappLoader有一个单独的线程每个x秒会检查源的时间戳。
x的值由checkInterval变量定义,它的默认值是15,也就是每隔15秒会进行一次检查是否需要自动重载。
该类还提供了两个方法getCheckInterval和setCheckInterval方法来访问或者设置checkInterval的值。
WebappClassLoader类
WebappClassLoader表示在一个web应用程序中使用的加载器。WebappClassLoader类继承了java.net.URLClassLoader类
缓存
缓存由WebappClassLoader类实例自己管理。另外,java.lang.ClassLoader维护了一个Vector,可以避免前面加载过的类被当做垃圾回收掉。
每一个可以被加载的类(放在 WEB-INF/classes目录下的类文件或者 JAR 文件)都被当做一个源。
一个源被org.apache.catalina.loader.ResourceEntry类表示。一个ResourceEntry实例保存一个byte类型的数组表示该类、最后修改的数据或者副本等等。
public class ResourceEntry { public long lastModifled = -1; public byte[] binaryContent = null; public Class loadedClass = null; public URL source = null; public URL CodeBase = null; public Manifest manifest = null; public Certificate[] certificates = null; }
所有缓存的源被存放在一个叫做resourceEntries的HashMap中,键值为源名,所有找不到的源都被放在一个名为notFoundResources的HashMap中。
加载类
当加载一个类的时候,WebappClassLoader类遵循以下规则:
· 所有加载过的类都要进行缓存,所以首先需要检查本地缓存。
· 如果无法再本地缓存找到类,使用java.langClassLoader类的findLoaderClass方法在缓存查找类、
· 如果在两个缓存中都无法找到该类,使用系统的类加载器避免从J2EE类中覆盖来的web应用程序。
· 如果使用了安全管理器,检查该类是否允许加载,如果该类不允许加载,则抛出ClassNotFoundException异常。
· 如果要加载的类使用了委派标志或者该类属于trigger包中,使用父加载器来加载类,如果父加载器为null,使用系统加载器加载。
· 从当前的源中加载类
· 如果在当前的源中找不到该类并且没有使用委派标志,使用父类加载器。如果父类加载器为null,使用系统加载器
· 如果该类仍然找不到,抛出ClassNotFoundException异常
例子
public static void main(String[] args) { System.setProperty("catalina.base", System.getProperty("user.dir")); Connector connector = new HttpConnector(); Wrapper wrapper1 = new SimpleWrapper(); wrapper1.setName("test1"); wrapper1.setServletClass("test1Servlet"); Wrapper wrapper2 = new SimpleWrapper(); wrapper2.setName("test2"); wrapper2.setServletClass("test2Servlet"); Context context = new StandardContext(); context.setPath("/myapp"); context.setDocBase("myapp"); context.addChild(wrapper1); context.addChild(wrapper2); context.addServletMapping("/test1", "test1"); context.addServletMapping("/test2", "test2"); LifecycleListener listener = new SimpleContextConfig(); ((Lifecycle)context).addLifecycleListener(listener); Loader loader = new WebappLoader(); context.setLoader(loader); connector.setContainer(context); try{ connector.initialize(); ((Lifecycle)connector).start(); ((Lifecycle)context).start(); WebappClassLoader classLoader= (WebappClassLoader)loader.getClassLoader(); String[] repositories = classLoader.findRepositories(); for(int i=0;i<repositories.length;i++){ System.out.println("--------------------"); } System.in.read(); ((Lifecycle)context).stop(); }catch(Exception e){ e.printStackTrace(); } }
public class SimpleContextConfig implements LifecycleListener { public void lifecycleEvent(LifecycleEvent event) { if(Lifecycle.START_EVENT.equals(event.getType())){ System.out.println("---------------------"); } } }
public class SimplePipeline implements Pipeline, Lifecycle { protected Valve basic = null; protected Container container = null; protected Valve[] valves = new Valve[0]; public void addValve(Valve valve) { Valve results[] = new Valve[valves.length + 1]; System.arraycopy(valves, 0, results, 0, valves.length); results[valves.length] = valve; valves = results; } protected class StandardPipelineValveContext implements ValveContext { protected int stage = 0; public String getInfo() { return null; } public void invokeNext(Request request, Response response) throws IOException, ServletException { int subscript = stage; stage = stage + 1; // Invoke the requested Valve for the current request thread if (subscript < valves.length) { valves[subscript].invoke(request, response, this); } else if ((subscript == valves.length) && (basic != null)) { basic.invoke(request, response, this); } else { throw new ServletException("No valve"); } } } // end of inner class public Valve getBasic() { return null; } public Valve getFirst() { // TODO Auto-generated method stub return null; } public Valve[] getValves() { // TODO Auto-generated method stub return null; } public void removeValve(Valve arg0) { // TODO Auto-generated method stub } public void setBasic(Valve arg0) { // TODO Auto-generated method stub } public void addLifecycleListener(LifecycleListener arg0) { // TODO Auto-generated method stub } public LifecycleListener[] findLifecycleListeners() { // TODO Auto-generated method stub return null; } public void removeLifecycleListener(LifecycleListener arg0) { // TODO Auto-generated method stub } public void start() throws LifecycleException { // TODO Auto-generated method stub } public void stop() throws LifecycleException { // TODO Auto-generated method stub } }
public class SimpleWrapper implements Wrapper, Pipeline, Lifecycle { private Servlet instance = null; private String servletClass; private Loader loader; private String name; protected LifecycleSupport lifecycle = new LifecycleSupport(this); private SimplePipeline pipeline = new SimplePipeline(); protected Container parent = null; protected boolean started = false; public SimpleWrapper(){} }
发表评论
-
21,tomcat关闭钩子
2012-11-22 20:35 6646在很多环境下,在关闭应用程序的时候需要做一些清理工作。问题在于 ... -
20,tomcat的XML解析---digester
2012-11-22 20:07 1558tomcat使用server.xml配置属性信息Tomcat使 ... -
19tomcat的服务器和服务
2012-11-20 20:10 1076Server服务器 Server接口表示整个Catalina ... -
18,tomcat的主机(host)和引擎
2012-11-16 09:13 2350如果需要在一个Tomcat部署中部署多个上下文,需要使用一个主 ... -
附,listener、 filter、servlet 加载顺序及其详解
2012-11-15 09:10 985一、 1、启动一个WEB项 ... -
17,tomcat中StandardContext
2012-11-15 08:59 5043一个上下文容器(Context)代表一个web应用,每一个上下 ... -
16,tomcat中StandardWrapper实现
2012-11-14 18:28 3889Wrapper接口在Catalina中的标准实现Standar ... -
15,tomcat安全
2012-11-14 09:02 1201有些web应用程序的内容是有限制的,只允许有权限的用户在提供正 ... -
14,tomcat session管理
2012-11-14 09:01 1104Catalina通过一个叫管理器的组建来完成Session的管 ... -
12,tomcat日志处理
2012-11-13 13:15 1248日志系统是一个记录信息的组件。在Catalina中,日志系统是 ... -
附:JAVA事件处理--观察者模式
2012-11-12 10:33 1001简单地说,观察者模式 ... -
11.tomcat生命周期
2012-11-12 10:26 987Catalina由多个组件组成,当Catalina启动的 ... -
10.容器
2012-11-12 10:12 1351容器是一个处理用户servlet请求并返回对象给we ... -
9.Tomcat的默认连接器
2012-11-12 08:52 1179Tomcat连接器是一个可以插入servlet容器的独立模块, ... -
8.连接器
2012-11-12 08:46 939一个可以创建更好的请 ... -
7,Facade外观模式
2012-11-08 11:28 950外观模式:为子系统中的一组接口提供了一个一致的界面,此模式定义 ... -
6,一个简单的servlet容器
2012-11-08 11:10 855总的来说,一个全功能的servlet容器会为servlet的每 ... -
5.javax.servlet.Servlet接口
2012-11-08 09:18 951javax.servlet.Servlet接口Servlet编 ... -
4,一个简单的tomcat
2012-11-07 18:10 946流程图如下 -
3.ServerSocket 与 Socket的区别
2012-11-07 16:56 11861.1 ServerSocket类创建 ...
相关推荐
4. **日志查看**:插件提供了一个内置的日志查看器,使得开发者能够在Eclipse中直接查看Tomcat服务器的日志,帮助诊断问题。 5. **调试支持**:提供强大的调试工具,允许开发者设置断点,步进执行代码,检查变量值...
这个"DevLoader.zip"文件可能包含与Tomcat自定义类加载器相关的资料,特别是名为"DevLoader"的类加载器,这可能是Tomcat为开发者提供的一种特殊加载器。 首先,我们来理解一下类加载器的基本概念。在Java中,类加载...
3. **性能优化**:与Apache Commons Logging相比,Juli避免了类加载器问题,减少了类查找的时间,从而提高了整体性能。 三、配置Juli 在Tomcat中,Juli的配置主要通过两个文件来完成: - **`conf/logging....
下面我们将深入探讨Java类加载器以及Tomcat中的类加载器。 在Java中,类加载器主要分为三个层次:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader。Bootstrap ClassLoader负责加载JDK的核心库,如rt...
JVM、OSGI(Open Service Gateway Initiative)和Tomcat等容器都涉及到了类加载器的概念,理解它们的工作原理对优化应用性能和解决依赖冲突至关重要。 1. JVM类加载器: - **父类加载器**:在Java中,类加载器之间...
另一种是在`conf/server.xml`中配置Context元素,指定应用的文档基础和类加载器设置。 5. **访问web应用**:一旦应用被部署,用户可以通过浏览器访问`http://localhost:8080/应用名`来访问应用,假设默认端口8080未...
当Tomcat加载类时,它遵循以下顺序: - 使用Bootstrap类加载器尝试加载。 - 使用System类加载器尝试加载。 - 使用Webapp类加载器加载`WEB-INF/classes`下的类。 - 使用Webapp类加载器加载`WEB-INF/lib`中的jar...
这是一个常见的Linux软件分发格式,用于在不依赖任何其他软件包管理器的情况下进行手动安装。 **Apache Tomcat 8.5.59详解** Apache Tomcat 8.5.59是Tomcat服务器的稳定版本,它提供了许多改进和修复,以增强性能...
3-7Tomcat中自定义类加载器的使用与源码实现(1).mp4
解决方法通常是使用Maven或Gradle等构建工具进行依赖管理,确保每个应用都有其独立的类加载器或者使用统一的jar版本。 2. **缺失的jar**:如果在运行Tomcat时出现“找不到类”的错误,可能是因为缺少了必要的jar。...
首先,Tomcat的类加载器层次结构由Bootstrap类加载器、Common类加载器、Shared类加载器和Web应用程序类加载器组成。Bootstrap类加载器是JVM启动时的第一个加载器,负责加载JDK的核心类库。Tomcat使用Bootstrap类加载...
Tomcat作为Servlet和JSP的容器,负责加载、实例化和管理Servlet,以及将JSP转换成Servlet并执行。 2. **版本号**:“9.0.86”代表了Tomcat的主要版本和次要版本号,其中“9.0”表示主版本,而“86”是次版本。每个...
- 在此文件中,我们定义了一个负载均衡控制器`controller`,以及两个Tomcat实例`tomcat1`和`tomcat2`。每个Tomcat实例都有自己的AJP端口(`worker.tomcatX.port`),主机名(`worker.tomcatX.host`),类型(`worker....
这个连接器,通常称为 mod_jk 或 ajp (Apache Jserv Protocol),允许两个服务协同工作,使得 Apache 能够处理静态内容,而 Tomcat 处理动态 Java 应用程序,实现高效、灵活的Web服务器架构。 Apache HttpServer 是...
Tomcat作为Servlet容器,负责加载、执行并管理Servlet实例。 2. **JSP**:JSP是一种基于Java的动态网页技术,允许开发者将静态HTML与动态Java代码混合编写。在Tomcat中,JSP文件会被编译成Servlet类,然后由Tomcat...
在Tomcat中,我们可以通过配置`catalina.properties`文件和`server.xml`文件来调整类加载策略,例如设置自定义的类加载顺序或启用共享类加载器。 此外,Tomcat还支持热部署,即在不重启服务器的情况下更新Web应用的...
4. **Tomcat配置**: 需要在每个Tomcat实例的server.xml文件中开启AJP监听器,例如: ```xml ``` **负载均衡策略** mod_jk支持多种负载均衡策略,如轮询(round-robin)、优先级(priority)、最少连接(least ...
在Tomcat中,Servlets被加载到内存中并由容器管理,以处理客户端请求。 **JavaServer Pages (JSP)** 是一种用于创建动态Web内容的技术,它将HTML代码与Java代码分离,使得开发者可以专注于页面逻辑而无需关注底层...