常熟java编程培训是什么_常熟JAVA培训
来源:教育联展网 编辑:佚名 发布时间:2018-10-24
赵艳敏高级讲师
从事设计行业多年,有着丰富的设计和动画制作经验。曾参与中国电信天翼 手机网及天翼手机DIY等多个项目的设计,动画,及As开发。项目经验丰富。曾在卡酷动画卫视下属公司担任高级动画师一职,参与多部动画片的制作 。对动画也有较高的造诣。
精通Flash、After Effects、Photoshop、Illustrator、ActionScript 2.0/3.0、Edius、CoolEdit、Axure RP、DIV CSS等相关技术。
讲课有自己的风格,思维活跃,条理清晰讲课注重细节,由简入繁。本着以 学生学会为目的,更注重理论与实践相结合。
多年Java开发从业者:首先,这个问题主要问:自学Java编程技术,如果才 能找到一份Java编程的工作。按照现在的招聘标准来看,无论你去哪个公司面试,你只需要满足他们公司的需求就可以。
找到一份Java编程工作需要掌握的内容如下 :
首先是Javase作为Java**基本的学习 内容,不在多说。
然后是掌握Java的基本原理,因为做Java 编程开发必须学会Java,用到Java非常多,但是现在很多公司是不用去写原生的Java,但是如果你想成为一个厉害的Java开发者,Java必须从理论到实 际操作中都要非常得心应手。
现在公司是必须要求会用框架的,所以取代Java的就是jQuery,这是一个非 常简易的框架,学jQuery的时候你就会觉得它比Java好用的多。所以jQuery是你必须掌握的。
还有必须学一些框架,比如SpringMVC、Spring、Mybatis、Struts、Hibernate等等,这些就会难理解一些,但是公司是需要要求你会框架的,目前国内的公司应用SSH比 较多,建议至少学三个框架,这是找到工作的基本需求。
数据库技术是Java工作者必须掌握的技能常用就是Mysql。
Javaweb的内容还有html、css、jsp、Servlet等技术,这些都是现在找Java开发必须掌握的东西。
以上就是粗略的必须掌握的技术,如果你想找到一份Java开发的工作,上述 相关技术必须熟练掌握并且应用到项目中。
流行框架
流行框架
-
01Struts2
-
1.Struts2流程
-
2.值栈与ONGL
-
3.Struts2标签库
-
4.Struts2模型驱动原理
-
5.Struts2声明式异常处理
-
6.Struts2类型转换&自定义类型转换
-
7.Struts2拦截器原理&自定义拦截器
-
8.Struts2源码分析&运行原理
-
02Hibernate
-
1.Hibernate环境搭建&配置
-
2.hibernate.cfg.xml&主键生成策略
-
3.Session核心方法
-
4.ORM映射:单向/双向1-n映射
-
5.ORM映射:基于主/外键映射&n-n
-
6.检索策略&迫切左外连接
-
7.Hibernate缓存机制
-
8.QBC、HQL
-
9.Session管理
-
03Spring
-
1.SpringIOC&DI机制
-
2.Spring配置式组件管理
-
3.Spring注解式自动装配
-
4.Spring表达式语言
-
5.SpringAOP&动态代理
-
6.SpringJDBC使用
-
7.Spring声明式事务
-
8.Spring单元测试
-
9.Spring源码分析
-
10.Spring、Struts2、Hibernate整合
-
04SpringMVC
-
1.SpringMVC配置&运行流程
-
2.SpringMVC数据绑定
-
3.模型处理&@ModelAttribute
-
4.RestFulCRUD
-
5.表单标签&静态资源处理
-
6.数据转换&格式化&JSR303数据校验
-
7.HttpMessageConverter
-
8.Ajax&国际化&文件上传**
-
9.异常处理
-
10.整合&父子容器
-
05MyBatis
-
1.MyBatis配置&查询数据
-
2.MyBatis全局配置文件
-
3.MyBatis映射文件
-
4.关联查询,动态sql
-
5.MyBatis缓存机制&整合ehcache
-
6.MyBatis逆向工程
-
7.MyBatis、Spring、SpringMVC整合
-
8.MyBatis运行原理&源码分析
-
9.MyBatis拦截器&插件开发
-
10.分页插件&存储过程调用&自定义 TypeHandler
-
06JPA
-
1.JPA技术体系
-
2.JPA注解
-
3.JPA相关API
-
4.JPA映射
-
5.JPQL
-
6.二级缓存
-
7.Spring整合JPA
-
07SpringData
-
1.SpringData快速入门
-
2.SpringData_Repository接口
-
3.Repository查询规范
-
4.@Query&@Modifying
-
5.CrudRepository
-
6.PagingAndSortingRepository
-
7.JpaRepository
-
8.JpaSpecificationExecutor
-
9.自定义Repository
-
08Maven
-
1.Maven环境搭建
-
2.Maven构建&自动化构建
-
3.本地仓库&中央仓库
-
4.maven创建web工程
-
5.pom.xml、依赖管理
-
6.坐标、依赖、生命周期等
-
7.eclipse下的maven使用
-
8.继承&聚合
-
9.maven构建SSH/SSM应用
-
10.自动部署&持续集成&持续部署
-
09SVN
-
1.SVN简介
-
2.SVN服务器搭建
-
3.SVN创建版本库
-
4.Eclipse整合svn插件
-
5.使用SVN更新提交
-
6.SVN仓库分析
-
7.SVN协同修改&冲突解决
-
8.SVN权限管理
-
9.SVN时光机
-
10.TortoiseSVN
-
10Shiro
-
1.Shiro入门
-
2.Spring集成Shiro
-
3.Shiro工作流程
-
4.权限URL配置
-
5.认证流程&认证Realm
-
6.密码比对,MD5&盐值加密
-
7.授权流程
-
8.标签&权限注解
-
9.会话管理、SessionDao
-
10.缓存
-
11.实现”记住我”
-
11Activiti5
-
1.工作流&工作流引擎
-
2.BPMN2.0规范
-
3.Activiti5框架表结构
-
4.Activiti5核心组件&服务接口
-
5.Activiti5插件安装&整合Spring
-
6.流程定义
-
7.流程实例&任务&历史
-
8.任务领取&流程变量
-
9.排他网关&并行网关
-
12WebService
-
1.WebService简介
-
2.WebService主流框架
-
3.cxf的使用
-
4.SOAP协议
-
5.WSDL讲解
-
6.JAX-WS
-
7.与Spring整合
-
8.JAXB
-
9.JAX-RS
-
10.支付接口原理
-
13Linux
-
1.Linux系统-基础
-
2.Linux网络基础
-
3.Linux在VMware下的安装
-
4.Linux下Java环境的搭建
-
5.Linux下Tomcat安装和配置
-
6.Linux下 Oracle/MySQL 安装与配置
-
7.Shell 编程
-
14Redis
-
1.NoSQL&Redis入门
-
2.Redis/memcache/MongDB对比
-
3.Redis安装&启动
-
4.分布式数据库CAP原理
-
5.Redis五大数据类型和基本操作命令
-
6.Redis总体配置Redis.conf
-
7.Redis持久化(RDB和AOF)
-
8.Redis事务控制
-
9.Redis发布和订阅
-
10.Redis(Master/Slave)主从复制
-
11.Jedis
-
15Git&Git Hub
-
1.Git安装配置
-
2.Git本地库搭建
-
3.Git常用操作命令
-
4.Github注册与配置
-
5.Github与Git协同办公
-
6.TortoiseGit安装配置
-
7.Egit操作push/pull,
-
8.Git工作流
-
9.集中式&GitFlow&Forking
-
16MySQL高级
-
1.MySQL架构组成
-
2.MySQL备份和恢复
-
3.MySQL查询和慢查询日志分析
-
4.MySQL索引优化
-
5.MySQL存储引擎优化
-
6.MySQL锁机制优化
-
7.MySQL高可用设计
-
8.MySQL集群
-
17JVM原理
-
1.JVM简析
-
2.JVM组成结构
-
3.JVM堆、栈原理
-
4.JVM-Heap三区原理
-
5.JVM垃圾收集机制
-
6.堆内存调优
-
7.GC回收策略
-
8.GC三大算法
-
18Quartz
-
1.Quartz作业调度简介
-
2.Quartz作业调度执行以及持久性
-
3.Quartz基本使用
-
4.Quartz核心类讲解
-
5.Quartz Trigger 触发器
-
6.Quartz Job&JobDetail
-
7.Quartz Calendars日历讲解
-
8.JobListener监听器和TriggerListener监听器
-
9.Spring整合Quartz
-
19Nginx
-
1.Nginx反向代理介绍
-
2.Nginx **和安装
-
3.Nginx 编译和启动、访问
-
4.在Linux下搭建Nginx集群
-
5.在Windows搭建Nginx集群
-
6.解决Session共享问题
-
20Java JUC 线程高级
-
1.volatile 关键字
-
2.内存可见性分析
-
3.原子变量与CAS (Compare And Swap) 算法分 析
-
4.ConcurrentHashMap 锁分段机制
-
5.CountDownLatch 闭锁
-
6.实现 Callable 接口
-
7.Lock 同步锁
-
8.Condition 控制线程通信
-
9.线程按序交替
class卸载、热替换和Tomcat的热部署的分析
>
原文:http://www.blogjava.net/heavensay/archive/2012/11/07/389685.html
这篇文章主要是分析Tomcat中关于热部署和jsp更新替换的原理,在此之前先介绍class的热替换和class的卸载的原理。
一 class的热替换 ClassLoader中重要的方法 loadClass ClassLoader.loadClass(...) 是ClassLoader的入口点。当一个类没有指明用什么加载器加载的时候,JVM默认采用AppClassLoader加载器加载没有加载过的class,调用的方法的入口就是loadClass(...)。如果一个class被自定义的ClassLoader加载,那么JVM也会调用这个自定义的ClassLoader.loadClass(...)方法来加载class内部引用的一些别的class文件。重载这个方法,能实现自定义加载class的方式,抛弃双亲委托机制,但是即使不采用双亲委托机制,比如java.lang包中的相关类还是不能自定义一个同名的类来代替,主要因为JVM解析、验证class的时候,会进行相关判断。 defineClass 系统自带的ClassLoader,默认加载程序的是AppClassLoader,ClassLoader加载一个class,**终调用的是defineClass(...)方法,这时候就在想是否可以重复调用defineClass(...)方法加载同一个类(或者修改过),**后发现调用多次的话会有相关错误: ... java.lang.LinkageError attempted duplicate class definition ... 所以一个class被一个ClassLoader实例加载过的话,就不能再被这个ClassLoader实例再次加载(这里的加载指的是,调用了defileClass(...)放方法,重新加载字节码、解析、验证。)。而系统默认的AppClassLoader加载器,他们内部会缓存加载过的class,重新加载的话,就直接取缓存。所与对于热加载的话,只能重新创建一个ClassLoader,然后再去加载已经被加载过的class文件。 下面看一个class热加载的例子: 代码:HotSwapURLClassLoader自定义classloader,实现热替换的关键 1 package testjvm.testclassloader; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.net.MalformedURLException; 6 import java.net.URL; 7 import java.net.URLClassLoader; 8 import java.util.HashMap; 9 import java.util.Map; 10 11 /** 12 * 只要功能是重新加载更改过的.class文件,达到热替换的作用 13 * @author banana 14 */ 15 public class HotSwapURLClassLoader extends URLClassLoader { 16 //缓存加载class文件的**后**新修改时间 17 public static Map<String,Long> cacheLastModifyTimeMap = new HashMap<String,Long>(); 18 //工程class类所在的路径 19 public static String PRojectClassPath = "D:/Ecpworkspace/ZJob-Note/bin/"; 20 //所有的测试的类都在同一个包下 21 public static String packagePath = "testjvm/testclassloader/"; 22 23 private static HotSwapURLClassLoader hcl = new HotSwapURLClassLoader(); 24 25 public HotSwapURLClassLoader() { 26 //设置ClassLoader加载的路径 27 super(getMyURLs()); 28 } 29 30 public static HotSwapURLClassLoader getClassLoader(){ 31 return hcl; 32 } 33 34 private static URL[] getMyURLs(){ 35 URL url = null; 36 try { 37 url = new File(projectClassPath).toURI().toURL(); 38 } catch (MalformedURLException e) { 39 e.printStackTrace(); 40 } 41 return new URL[] { url }; 42 } 43 44 /** 45 * 重写loadClass,不采用双亲委托机制("java."开头的类还是会由系统默认ClassLoader加载) 46 */ 47 @Override 48 public Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException { 49 Class clazz = null; 50 //查看HotSwapURLClassLoader实例缓存下,是否已经加载过class 51 //不同的HotSwapURLClassLoader实例是不共享缓存的 52 clazz = findLoadedClass(name); 53 if (clazz != null ) { 54 if (resolve){ 55 resolveClass(clazz); 56 } 57 //如果class类被修改过,则重新加载 58 if (isModify(name)) { 59 hcl = new HotSwapURLClassLoader(); 60 clazz = customLoad(name, hcl); 61 } 62 return (clazz); 63 } 64 65 //如果类的包名为"java."开始,则有系统默认加载器AppClassLoader加载 66 if(name.startsWith("java.")){ 67 try { 68 //得到系统默认的加载cl,即AppClassLoader 69 ClassLoader system = ClassLoader.getSystemClassLoader(); 70 clazz = system.loadClass(name); 71 if (clazz != null) { 72 if (resolve) 73 resolveClass(clazz); 74 return (clazz); 75 } 76 } catch (ClassNotFoundException e) { 77 // Ignore 78 } 79 } 80 81 return customLoad(name,this); 82 } 83 84 public Class load(String name) throws Exception{ 85 return loadClass(name); 86 } 87 88 /** 89 * 自定义加载 90 * @param name 91 * @param cl 92 * @return 93 * @throws ClassNotFoundException 94 */ 95 public Class customLoad(String name,ClassLoader cl) throws ClassNotFoundException { 96 return customLoad(name, false,cl); 97 } 98 99 /** 100 * 自定义加载 101 * @param name 102 * @param resolve 103 * @return 104 * @throws ClassNotFoundException 105 */ 106 public Class customLoad(String name, boolean resolve,ClassLoader cl) 107 throws ClassNotFoundException { 108 //findClass()调用的是URLClassLoader里面重载了ClassLoader的findClass()方法 109 Class clazz = ((HotSwapURLClassLoader)cl).findClass(name); 110 if (resolve) 111 ((HotSwapURLClassLoader)cl).resolveClass(clazz); 112 //缓存加载class文件的**后修改时间 113 long lastModifyTime = getClassLastModifyTime(name); 114 cacheLastModifyTimeMap.put(name,lastModifyTime); 115 return clazz; 116 } 117 118 public Class<?> loadClass(String name) throws ClassNotFoundException { 119 return loadClass(name,false); 120 } 121 122 @Override 123 protected Class<?> findClass(String name) throws ClassNotFoundException { 124 // TODO Auto-generated method stub 125 return super.findClass(name); 126 } 127 128 /** 129 * @param name 130 * @return .class文件**新的修改时间 131 */ 132 private long getClassLastModifyTime(String name){ 133 String path = getClassCompletePath(name); 134 File file = new File(path); 135 if(!file.exists()){ 136 throw new RuntimeException(new FileNotFoundException(name)); 137 } 138 return file.lastModified(); 139 } 140 141 /** 142 * 判断这个文件跟上次比是否修改过 143 * @param name 144 * @return 145 */ 146 private boolean isModify(String name){ 147 long lastmodify = getClassLastModifyTime(name); 148 long previousModifyTime = cacheLastModifyTimeMap.get(name); 149 if(lastmodify>previousModifyTime){ 150 return true; 151 } 152 return false; 153 } 154 155 /** 156 * @param name 157 * @return .class文件的完整路径 (e.g. E:/A.class) 158 */ 159 private String getClassCompletePath(String name){ 160 String simpleName = name.substring(name.lastIndexOf(".") 1); 161 return projectClassPath packagePath simpleName ".class"; 162 } 163 164 } 165 代码:Hot被用来修改的类 1 package testjvm.testclassloader; 2 3 public class Hot { 4 public void hot(){ 5 System.out.println(" version 1 : " this.getClass().getClassLoader()); 6 } 7 } 8 代码:TestHotSwap测试类 1 package testjvm.testclassloader; 2 3 import java.lang.reflect.Method; 4 5 public class TestHotSwap { 6 7 public static void main(String[] args) throws Exception { 8 //开启线程,如果class文件有修改,就热替换 9 Thread t = new Thread(new MonitorHotSwap()); 10 t.start(); 11 } 12 } 13 14 class MonitorHotSwap implements Runnable { 15 // Hot就是用于修改,用来测试热加载 16 private String className = "testjvm.testclassloader.Hot"; 17 private Class hotClazz = null; 18 private HotSwapURLClassLoader hotSwapCL = null; 19 20 @Override 21 public void run() { 22 try { 23 while (true) { 24 initLoad(); 25 Object hot = hotClazz.newInstance(); 26 Method m = hotClazz.getMethod("hot"); 27 m.invoke(hot, null); //打印出相关信息 28 // 每隔10秒重新加载一次 29 Thread.sleep(10000); 30 } 31 } catch (Exception e) { 32 e.printStackTrace(); 33 } 34 } 35 36 /** 37 * 加载class 38 */ 39 void initLoad() throws Exception { 40 hotSwapCL = HotSwapURLClassLoader.getClassLoader(); 41 // 如果Hot类被修改了,那么会重新加载,hotClass也会返回新的 42 hotClazz = hotSwapCL.loadClass(className); 43 } 44 } 在测试类运行的时候,修改Hot.class文件 所以HotSwapURLClassLoader是重加载了Hot类 。注意上面,其实当加载修改后的Hot时,HotSwapURLClassLoader实例跟加载没修改Hot的HotSwapURLClassLoader不是同一个。 图:HotSwapURLClassLoader加载情况 总结:上述类热加载,需要自定义ClassLoader,并且只能重新实例化ClassLoader实例,利用新的ClassLoader实例才能重新加载之前被加载过的class。并且程序需要模块化,才能利用这种热加载方式。 二 class卸载 在Java中class也是可以unload。JVM中class和Meta信息存放在PermGen space区域。如果加载的class文件很多,那么可能导致PermGen space区域空间溢出。引起:java.lang.OutOfMemoryErrorPermGen space. 对于有些Class我们可能只需要使用一次,就不再需要了,也可能我们修改了class文件,我们需要重新加载 newclass,那么oldclass就不再需要了。那么JVM怎么样才能卸载Class呢。 JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):- 该类所有的实例都已经被GC。 - 加载该类的ClassLoader实例已经被GC。 - 该类的java.lang.Class对象没有在任何地方被引用。
GC的时机我们是不可控的,那么同样的我们对于Class的卸载也是不可控的。 例子: 代码:SimpleURLClassLoader,一个简单的自定义classloader 1 package testjvm.testclassloader; 2 3 import java.io.File; 4 import java.net.MalformedURLException; 5 import java.net.URL; 6 import java.net.URLClassLoader; 7 8 public class SimpleURLClassLoader extends URLClassLoader { 9 //工程class类所在的路径 10 public static String projectClassPath = "E:/IDE/work_place/ZJob-Note/bin/"; 11 //所有的测试的类都在同一个包下 12 public static String packagePath = "testjvm/testclassloader/"; 13 14 public SimpleURLClassLoader() { 15 //设置ClassLoader加载的路径 16 super(getMyURLs()); 17 } 18 19 private static URL[] getMyURLs(){ 20 URL url = null; 21 try { 22 url = new File(projectClassPath).toURI().toURL(); 23 } catch (MalformedURLException e) { 24 e.printStackTrace(); 25 } 26 return new URL[] { url }; 27 } 28 29 public Class load(String name) throws Exception{ 30 return loadClass(name); 31 } 32 33 public Class<?> loadClass(String name) throws ClassNotFoundException { 34 return loadClass(name,false); 35 } 36 37 /** 38 * 重写loadClass,不采用双亲委托机制("java."开头的类还是会由系统默认ClassLoader加载) 39 */ 40 @Override 41 public Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException { 42 Class clazz = null; 43 //查看HotSwapURLClassLoader实例缓存下,是否已经加载过class 44 clazz = findLoadedClass(name); 45 if (clazz != null ) { 46 if (resolve){ 47 resolveClass(clazz); 48 } 49 return (clazz); 50 } 51 52 //如果类的包名为"java."开始,则有系统默认加载器AppClassLoader加载 53 if(name.startsWith("java.")){ 54 try { 55 //得到系统默认的加载cl,即AppClassLoader 56 ClassLoader system = ClassLoader.getSystemClassLoader(); 57 clazz = system.loadClass(name); 58 if (clazz != null) { 59 if (resolve) 60 resolveClass(clazz); 61 return (clazz); 62 } 63 } catch (ClassNotFoundException e) { 64 // Ignore 65 } 66 } 67 68 return customLoad(name,this); 69 } 70 71 /** 72 * 自定义加载 73 * @param name 74 * @param cl 75 * @return 76 * @throws ClassNotFoundException 77 */ 78 public Class customLoad(String name,ClassLoader cl) throws ClassNotFoundException { 79 return customLoad(name, false,cl); 80 } 81 82 /** 83 * 自定义加载 84 * @param name 85 * @param resolve 86 * @return 87 * @throws ClassNotFoundException 88 */ 89 public Class customLoad(String name, boolean resolve,ClassLoader cl) 90 throws ClassNotFoundException { 91 //findClass()调用的是URLClassLoader里面重载了ClassLoader的findClass()方法 92 Class clazz = ((SimpleURLClassLoader)cl).findClass(name); 93 if (resolve) 94 ((SimpleURLClassLoader)cl).resolveClass(clazz); 95 return clazz; 96 } 97 98 @Override 99 protected Class<?> findClass(String name) throws ClassNotFoundException { 100 return super.findClass(name); 101 } 102 } 103 代码:A 1 public class A { 2 // public static final Level CUSTOMLEVEL = new Level("test", 550) {}; // 内部类 3 } 代码:TestClassUnload,测试类 1 package testjvm.testclassloader; 2 3 public class TestClassUnLoad { 4 5 public static void main(String[] args) throws Exception { 6 SimpleURLClassLoader loader = new SimpleURLClassLoader(); 7 // 用自定义的加载器加载A 8 Class clazzA = loader.load("testjvm.testclassloader.A"); 9 Object a = clazzA.newInstance(); 10 // 清除相关引用 11 a = null; 12 clazzA = null; 13 loader = null; 14 // 执行一次gc垃圾回收 15 System.gc(); 16 System.out.println("GC over"); 17 } 18 } 19 运行的时候配置VM参数: -verbose:class;用于查看class的加载与卸载情况。如果用的是Eclipse,在Run Configurations中配置此参数即可。 图:Run Configurations配置 上面输出结果中的确A.class被加载了,然后A.class又被卸载了。这个例子中说明了,即便是class加载进了内存,也是可以被释放的。 图:程序运行中,引用没清楚前,内存中情况 图:垃圾回收后,程序没结束前,内存中情况 1、有启动类加载器加载的类型在整个运行期间是不可能被卸载的(jvm和jls规范). 2、被系统类加载器和标准扩展类加载器加载的类型在运行期间不太可能被卸载,因为系统类加载器实例或者标准扩展类的实例基本上在整个运行期间总能直接或者间接的访问的到,其达到unreachable的可能性极小.(当然,在虚拟机快退出的时候可以,因为不管ClassLoader实例或者Class(java.lang.Class)实例也都是在堆中存在,同样遵循垃圾收集的规则). 3、被开发者自定义的类加载器实例加载的类型只有在很简单的上下文环境中才能被卸载,而且一般还要借助于强制调用虚拟机的垃圾收集功能才可以做到.可以预想,稍微复杂点的应用场景中(尤其很多时候,用户在开发自定义类加载器实例的时候采用缓存的策略以提高系统性能),被加载的类型在运行期间也是几乎不太可能被卸载的(至少卸载的时间是不确定的). 综合以上三点, 一个已经加载的类型被卸载的几率很小至少被卸载的时间是不确定的.同时,我们可以看的出来,开发者在开发代码时候,不应该对虚拟机的类型卸载做任何假设的前提下来实现系统中的特定功能. 三 Tomcat中关于类的加载与卸载 Tomcat中与其说有热加载,还不如说是热部署来的准确些。因为对于一个应用,其中class文件被修改过,那么Tomcat会先卸载这个应用(Context),然后重新加载这个应用,其中关键就在于自定义ClassLoader的应用。这里有篇文章很好的介绍了tomcat中对于ClassLoader的应用,请点击here。 Tomcat启动的时候,ClassLoader加载的流程: 1 Tomcat启动的时候,用system classloader即AppClassLoader加载{catalina.home}/bin里面的jar包,也就是tomcat启动相关的jar包。 2 Tomcat启动类Bootstrap中有3个classloader属性,catalinaLoader、commonLoader、sharedLoader在Tomcat7中默认他们初始化都为同一个StandardClassLoader实例。具体的也可以在{catalina.home}/bin/bootstrap.jar包中的catalina.properites中进行配置。 3 StandardClassLoader加载{catalina.home}/lib下面的所有Tomcat用到的jar包。 4 一个Context容器,代表了一个app应用。Context-->WebappLoader-->WebClassLoader。并且Thread.contextClassLoader=WebClassLoader。应用程序中的jsp文件、class类、lib/*.jar包,都是WebClassLoader加载的。 Tomcat加载资源的概况图: 当Jsp文件修改的时候,Tomcat更新步骤: 1 但访问1.jsp的时候,1.jsp的包装类JspServletWrapper会去比较1.jsp文件**新修改时间和上次的修改时间,以此判断1.jsp是否修改过。 2 1.jsp修改过的话,那么jspservletWrapper会清除相关引用,包括1.jsp编译后的servlet实例和加载这个servlet的JasperLoader实例。 3 重新创建一个JasperLoader实例,重新加载修改过后的1.jsp,重新生成一个Servlet实例。 4 返回修改后的1.jsp内容给用户。 图:Jsp清除引用和资源 当app下面的class文件修改的时候,Tomcat更新步骤: 1 Context容器会有专门线程监控app下面的类的修改情况。 2 如果发现有类被修改了。那么调用Context.reload()。清楚一系列相关的引用和资源。 3 然后创新创建一个WebClassLoader实例,重新加载app下面需要的class。 图:Context清除引用和资源 在一个有一定规模的应用中,如果文件修改多次,重启多次的话,java.lang.OutOfMemoryErrorPermGen space这个错误的的出现非常频繁。主要就是因为每次重启重新加载大量的class,超过了PermGen space设置的大小。两种情况可能导致PermGen space溢出。一、GC(Garbage Collection)在主程序运行期对PermGen space没有进行清理(GC的不可控行),二、重启之前WebClassLoader加载的class在别的地方还存在着引用。这里有篇很好的文章介绍了class内存泄露-here 参考: http://blog.csdn.net/runanli/article/details/2972361(关于Class类加载器 内存泄漏问题的探讨) http://www.blogjava.net/zhuxing/archive/2008/07/24/217285.html(Java虚拟机类型卸载和类型更新解析) http://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/(Java 类的热替换 —— 概念、设计与实现) http://www.iteye.com/topic/136427(classloader体系结构)
相关推荐:
上一篇:苏州哪的java培训好_苏州JAVA培训 下一篇:太仓java学习难不难_太仓JAVA培训