一.设置主机名
安装好linux虚拟机后,查看主机名: uname -n 或 hostname命令
点击(此处)折叠或打开
[zhang@localhost etc]$ uname -n
localhost.localdomain
[zhang@localhost etc]$ hostname
localhost.localdomain
1.临时 修改主机名
通过 hostname newhost 命令,这种方式,重启后失效。
2.永久修改主机名
修改配置文件 /etc/sysconfig/network
点击(此处)折叠或打开
[zhang@localhost etc]$ cat /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=localhost.localdomain
修改后,需要重启,生效!
3.配置文件 /etc/hosts 的作用
这个文件的作用是提供 IP 与 主机名对照,即 IP域名 解析的作用。
文件格式:
IP 全局主机名 主机的别名
cat /etc/hosts
点击(此处)折叠或打开
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.10.10.128 namenode master
二.设置静态IP
用root 用户
编辑网卡配置文件
vi /etc/sysconfig/network-script/ifcfg-eth0
进入编辑模式
按i键进行编辑
修改
DEVICE=eth0 #物理设备名
IPADDR=10.10.10.128 #IP地址
NETMASK=255.255.255.0 #掩码值
NETWORK=10.10.10.1 #网络地址(可不要)
BROADCAST=10.10.10.255 #广播地址(可不要)
GATEWAY=10.10.10.1 #网关地址
ONBOOT=yes # [yes|no](引导时是否激活设备)
USERCTL=no #[yes|no](非root用户是否可以控制该设备)
BOOTPROTO=static #[none|static|bootp|dhcp](引导时不使用协议|静态分配|BOOTP协议|DHCP协议)
然后修改DNS配置文件
vi /etc/resolv.conf
进入编辑模式
按i键进行编辑
修改
nameserver 202.109.14.5 #主DNS
nameserver 219.141.136.10 #次DNS
search localdomain
所以网络配置完成后,都需要重启网络服务:service network restart 或/etc/init.d/network restart
在做
java项目(特别是
web项目)的过程中,中文乱码一直是我们开发人员比较头疼的问题,因为涉及到编码,解码,字符集,以及国际化等诸多问题,所以在着手解决的时候也缺乏相关的知识。我花了一些时间自己动手实验了一把,虽然没有洞悉编码,解码这些底层原理,但是解决实际问题应该足够了。这里主要针对java web项目中的文乱码问题。
从浏览器采用form方式提交数据到服务器,可以分为post和get方法。
1,post方法:
在jsp页面中的page指令中,有一个pageEncoding,这个指令表示jsp翻译成servlet时采用的编码,以及form提交数据的编码格式。所以post方法提交数据的编码格式由pageEncoding指定。那解码方式呢?通常,我们在页面设置了pageEncoding=”utf-8”,在后台用request.getParameter()得到的往往是乱码,而进一步通过new String(getBytes(“iso-8859-1”),”utf-8”)处理之后就能得到正确的数据。这是因为服务器默认的解码方式是iso-8859-1,所以用编码,解码流程解释上面那2个动作分别是:utf-8编码—>iso-8859-1解码(当然是乱码); utf-8编码—>iso-8859-1解码—>iso-8859-1编码—>utf-8解码,这是个对称的过程,所以能正确得到数据。那服务器默认的解码方式能改吗?当然可以,调用request.setCharacterEncoding()就能设置,而且只针对post方式有效,设置以后request.getParameter()直接就是正确的数据了。
2,get方法
与post方法一样,编码方式由pageEncoding指定,但是get方式的解码方式与post就不一样了。在tomcat的conf目录下有一个
server.xml的配置文件,在里面找到Connector节点,有一个URIEncoding属性,这个属性就是指定get方式的数据解码格式的,而且只针对get方式有效。其他处理与post一样。
另外,通过Ajax请求向后台发送的数据由于是附在URL地址后面的,所以跟get请求一样。编码由pageEncoding指定,解码由URIEncoding指定。但是有很多开发人员乐于另外一种方式:用两次encodeURI编码,然后在后台用URLDecoder.decode(str,”utf-8”)解码。这是一个什么过程呢?我们知道,encodeURI编码是采用的utf-8编码,所以,这个过程为:utf-8编码—>utf-8编码—>iso-8859-1解码—>utf-8解码。这看起来不像一个对称过程,但最后为什么能得到正确结果呢?这是因为经过第一次utf-8编码之后,产生的已经是非中文字符,所以,对非中文字符采再用utf-8编码,iso-8859-1解码不会有任何问题,这样看来,它还是一个对称的编码,解码过程,当然能正确解析了。
当然,我所说的这个“对称”编码解码过程,也不是所有编码都适用,例如:
gbk编码—>utf-8解码—>utf-8编码—>gbk解码,最后还是乱码!
因为gbk编码—>utf-8解码产生了不可恢复的错误,造成了信息丢失,至于为什么产生永久错误,得从编码的底层说起……
1、双击打开QTP10.0,启动过程中
测试类型选择“WEB”。
2、进入主界面,New——Test,新建一个
测试用例。
3、点击Record按钮,Record and settings对话框中,可以选择WEB测试和
Windows Application两种不同的测试对象类型,这里选择Windows Application。
4、Record and run only on: Applications opened by Quick Test选中之后,下面的列表中选择Flight APP的路径。
5、点击OK,便会自动启动你所选中的APP,开始录制。
6、录制完成之后,点击Stop。
7、Test界面会以Keyword View作为默认页面显示,我们可以点击Expert View来切换到代码视图。
8、现在点击Run,可以回放你刚才录制的用例,生成测试结果。
*QTP使用的是基于VBS的脚本语言,与VBS非常相似,只有在其个别的地方存在细微差别;
QTP较其他开源测试工具而言最大的优势在于方便好用,门槛低,对Windows Application,Web的各种元素、标签、控件、按钮等的支持与控制。
1、Aggregate Report 解析
Aggregate Report 是 JMeter 常用的一个 Listener,中文被翻译为“聚合报告”。今天再次有同行问到这个报告中的各项数据表示什么意思,顺便在这里公布一下,以备大家查阅。
如果大家都是做Web应用的
性能测试,例如只有一个登录的请求,那么在Aggregate Report中,会显示一行数据,共有10个字段,含义分别如下。
Label:每个 JMeter 的 element(例如 HTTP Request)都有一个 Name 属性,这里显示的就是 Name 属性的值
#Samples:表示你这次测试中一共发出了多少个请求,如果模拟10个用户,每个用户迭代10次,那么这里显示100
Average:平均响应时间——默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以Transaction 为单位显示平均响应时间
Median:中位数,也就是 50% 用户的响应时间
90% Line:90% 用户的响应时间
Note:关于 50% 和 90% 并发用户数的含义,请参考下文
http://www.cnblogs.com/jackei/archive/2006/11/11/557972.html
Min:最小响应时间
Max:最大响应时间
Error%:本次测试中出现错误的请求的数量/请求的总数
Throughput:吞吐量——默认情况下表示每秒完成的请求数(Request per Second),当使用了 Transaction Controller 时,也可以表示类似
LoadRunner 的 Transaction per Second 数
KB/Sec:每秒从服务器端接收到的数据量,相当于LoadRunner中的Throughput/Sec
基本知识:
1、吞吐量:是指在没有帧丢失的情况下,设备能够接受的最大速率。
2、存储的最小单位是字节Byte,对于存储单位,有以下几个单位,GB、MB和KB,那么这三者之间的换算关系是:1GB=1024MB,1MB=1024KB,1KB=1024Bytes。
Bit :“位”,称为bit,也就是比特,有的时候也称为位。一个字节为8位二进制表示。
Byte:“字节”,一个字节就是8比特。
3、Mbps (million bits per second 兆位/秒) 代表每秒传输1,000,000比特。该缩写用来描述数据传输速度。例如:4Mbps=每秒钟传输4M比特。
数据传输速率的单位,字母b(bit)是比特和字母 B (Byte)是字节。
4、吞吐量与带宽的区分:吞吐量和带宽是很容易搞混的一个词,两者的单位都是Mbps.先让我们来看两者对应的英语,吞吐量:throughput ; 带宽: Max net bitrate 。当我们讨论通信链路的带宽时,一般是指链路上每秒所能传送的比特数。我们可以说以太网的带宽是10Mbps。但是,我们需要区分链路上的可用带宽(带宽)与实际链路中每秒所能传送的比特数(吞吐量)。我们倾向于用“吞吐量”一次来表示一个系统的测试性能。这样,因为实现受各种低效率因素的影响,所以由一段带宽为10Mbps的链路连接的一对节点可能只达到2Mbps的吞吐量。这样就意味着,一个主机上的应用能够以2Mbps的速度向另外的一个主机发送数据。
5、方差和标准差都是用来描述一组数据的波动性的(集中还是分散),标准差的平方就是方差。方差越大,数据的波动越大。
这里以一个电商购物(B2C)网站为例:
从12月下旬至农历年底(来年2月初)(<=50天)网站预计营业额(400万),这里营业额可以理解为网站完成购买订单总金额;
访问订单转化率:10%,这里理解为百分之多少的访问量会转化为实际的网站订单;
每日访问时间:24小时×80%,这里理解为正常用户会在早6点至凌晨0点之前进行电子购物,下午18点下班至晚上22点为购物高峰期;
每个订单平均选购商品数:3件左右共计300元左右的金额,这里指每个订单平均消费300元,平均购买3件商品;
订单有效率:85%,这里指下了订单的人,有多少是进行付款并完成交易的,15%会取消订单或不付款;
平均浏览率(IP/PV):10次,这里指访问网站的所有客户端IP地址信息统计后,平均每个IP会浏览10个网页;
业务性能需求分析:(假设所有订单全部发生在高峰时段,假设每个用户浏览对比5件商品后会选中一件,每件商品浏览需要点击5次不同链接网页)
高峰期每小时平均下单数:销售额/总销售时间/高峰时间/单笔订单金额/订单有效率=4000000/50/4/300/0.85≈80
高峰期每小时平均访问量(下单访问量/订单转化比率):80*5*5*3/10%=60000
高峰期访问量=1.3×平均访问量:60000*1.3=78000
高峰期访问客户端IP数量:78000/10=7800
压力测试场景设计(粗略估算,仅供参考和理解):
设计甲乙两组测试脚本,甲组产生订单,乙组仅浏览商品相关;
甲组脚本执行人数800,乙组脚本执行用户数7000人;
峰值测试1000人提交订单,10000人在线访问;
如果你经常读一些关于提高
工作效率或时间管理类的博客,一定听说过番茄时间管理法(Pomodoro Technique)。这是一种极好的帮助你集中注意力、获得更高工作效率的方法。
基本上,它的实施方法是这样的:
1. 确定你想要做什么(例如:翻译一篇外文)。
2. 设定一个25分钟的定时器。
3. 工作,直到定时器时间到:这就是一个“番茄钟”。
4. 休息5分钟,继续下一个番茄钟
5. 每4个番茄钟做一次长时间的休息。
(有很多像Tomato Timer这样的应用都是为这种时间管理方法设计的。)
大多数人都会对其做一些细微调整来适应自己:例如,你可以选择每两个番茄钟——而不是四个,做一次长时间的休息。这特别是你刚开始应用这种方法时。
为什么这种方法会有效
你是否曾计划要在办公桌前坐两个小时来写一篇博客,结果却发现自己一会儿整理桌面,一会儿浏览微薄,不断的被一些有趣的链接分心,或就在那儿浪费时间?
按时间段工作能帮助你保持工作状态。当有分心的事情出现——例如“我需要发一个email”或“我想看看微薄上有没有人回复我”——你可以这样告诉自己:这个番茄钟完成之后再做这些事情。
如果你在写博客,将写放在一个番茄钟、修改放在另一个番茄钟,你会发现这个方法十分的有效,如果一个番茄钟写不完,在加一个番茄钟,看看你能完成多少。
番茄时间管理方法的名称来历
如果你是第一次听说“番茄时间管理法(Pomodoro Technique)”,你会奇怪它为什么叫这个名称。Pomodoro就是意大利语里的“番茄”。Francesco Cirillo——番茄时间管理法的发明人——使用的就是一个形状像番茄的定时钟。
关于番茄时间管理法的用法有很多,主要都是用它来防止干扰的:如果你试过这种方法,并发现它真的能提供你的工作效率,那就也做一些研究,丰富它,扩展它。
挑战:今天就尝试一下番茄时间管理法——或下一次你写博客时,看看你能做到何种程度。在下面的评论里告诉大家你的体验。
摘要: 通过java模拟浏览器行为,对bugfree系统进行操作。譬如:通过bug id,查询bug的信息;查询产品族;查询满足特定条件的bug列表;批量更新bug的状态;上报bug到bugfree系统等。package com.yunos.qa;import java.io.BufferedReader;import java.io.IOException;import java.io.Inp...
阅读全文
客户的Oracle 11gR2 Active Data Guard环境,主数据库的standby_file_management=AUTO,备用数据库的standby_file_management=MANUAL,导致在主数据库为表空间添加的数据文件操作没有同步到备用数据库,在$ORACLE_HOME/dbs目录下也没有创建类似UNNAMED00003的文件,备用数据库有如下的告警日志: Tue Sep 02 17:37:36 2014
File #3 added to control file as 'UNNAMED00003' because
the parameter STANDBY_FILE_MANAGEMENT is set to MANUAL
The file should be manually created to continue.
MRP0: Background Media Recovery terminated with error 1274
Errors in file /u01/app/oracle/diag/rdbms/d012dg/d012band/trace/d012band_pr00_5702078.trc:
ORA-01274: cannot add datafile '/oradata1/d012band/tsmisc06.dbf' - file could not be created
Managed Standby Recovery not using Real Time Apply
Recovery interrupted!
Recovered data files to a consistent state at change 866102511
Tue Sep 02 17:37:46 2014
MRP0: Background Media Recovery process shutdown (d012band)
Tue Sep 02 17:52:14 2014
RFS[1]: Selected log 8 for thread 1 sequence 19136 dbid 2134147111 branch 809469738
Tue Sep 02 17:52:25 2014
Archived Log entry 511 added for thread 1 sequence 19135 ID 0x7f340827 dest 1:
Tue Sep 02 17:53:23 2014
alter database recover managed standby database using current logfile disconnect from session
Attempt to start background Managed Standby Recovery process (d012band)
Tue Sep 02 17:53:23 2014
MRP0 started with pid=42, OS id=7471452
MRP0: Background Managed Standby Recovery process started (d012band)
started logmerger process
Tue Sep 02 17:53:29 2014
Managed Standby Recovery starting Real Time Apply
Tue Sep 02 17:53:30 2014
Errors in file /u01/app/oracle/diag/rdbms/d012dg/d012band/trace/d012band_dbw0_4784178.trc:
ORA-01186: file 3 failed verification tests
ORA-01157: cannot identify/lock data file 3 - see DBWR trace file
ORA-01111: name for data file 3 is unknown - rename to correct file
ORA-01110: data file 3: '/u01/app/oracle/product/11.2.0/db_1/dbs/UNNAMED00003'
如果能够找到/u01/app/oracle/product/11.2.0/db_1/dbs/UNNAMED00003文件,可以参考文章:《11gR2 Active Data Guard调整案例[1]》http://blog.itpub.net/23135684/viewspace-759592/ File 3 not verified due to error ORA-01157
MRP0: Background Media Recovery terminated with error 1111
Errors in file /u01/app/oracle/diag/rdbms/d012dg/d012band/trace/d012band_pr00_8716760.trc:
ORA-01111: name for data file 3 is unknown - rename to correct file
ORA-01110: data file 3: '/u01/app/oracle/product/11.2.0/db_1/dbs/UNNAMED00003'
ORA-01157: cannot identify/lock data file 3 - see DBWR trace file
ORA-01111: name for data file 3 is unknown - rename to correct file
ORA-01110: data file 3: '/u01/app/oracle/product/11.2.0/db_1/dbs/UNNAMED00003'
Managed Standby Recovery not using Real Time Apply
Slave exiting with ORA-1111 exception
Errors in file /u01/app/oracle/diag/rdbms/d012dg/d012band/trace/d012band_pr00_8716760.trc:
ORA-01111: name for data file 3 is unknown - rename to correct file
ORA-01110: data file 3: '/u01/app/oracle/product/11.2.0/db_1/dbs/UNNAMED00003'
ORA-01157: cannot identify/lock data file 3 - see DBWR trace file
ORA-01111: name for data file 3 is unknown - rename to correct file
ORA-01110: data file 3: '/u01/app/oracle/product/11.2.0/db_1/dbs/UNNAMED00003'
Recovery Slave PR00 previously exited with exception 1111
MRP0: Background Media Recovery process shutdown (d012band)
Completed: alter database recover managed standby database using current logfile disconnect from session
解决这个问题的关键是手动创建新添加的数据文件,参考如下的内容解决该问题:
How to resolve MRP stuck issues on a physical standby database? (文档 ID 1221163.1)
......
Solution 10 Add the new datafiles to the standby database manually.
1) Please take a hot backup of new datafiles from the primary database.
2) Create a new standby controlfile from the primary database by
SQL>alter database create standby controlfile as '/tmp/controlf.ctl';
If datafiles are on ASM, please follow the note below and you could ignore the rest of steps:
Note 734862.1 Step By Step Guide On How To Recreate Standby Control File
When Datafiles Are On ASM And Using Oracle Managed Files
Or you could modify the wrong datafile name in the standby controlfile by alter database rename command. For example,
SQL> ALTER DATABASE RENAME FILE '<path/UNNAMED00003>' to '<path/real datafile name>';
3) If the new datafile location on the primary is different from the standby, please make sure
db_file_name_convert init parameter is set on the standby database.
Note 47325.1 Init.ora Parameter "DB_FILE_NAME_CONVERT" Reference Note
If db_file_name_convert init parameter has already been set, then you could ignore this step.
4) Cancel the managed recovery
SQL>alter database recover managed standby database cancel;
5) set standby_file_management=manual on the standby database and shutdown the standby database.
SQL>alter system set standby_file_management=manual sid='*';
SQL>shutdown immediate;
6) Copy the hot backup of the new datafiles and the new standby controlfile to the standby.
Please make sure the controlfiles are located in the right location with right names
according to the init parameter control_files. Please make sure the copied datafiles are
located in the right location as well according to name from v$datafile.
7) startup the standby database in mount mode and set standby_file_management=auto.
SQL>startup mount;
SQL>alter system set standby_file_management=auto sid='*';
8) Start the managed recovery.
SQL>alter database recover managed standby database disconnect;
......
--end--
AUM(自动 undo 管理,Automatic Undo Management)几乎不需要配置。您基本上只需要定义将前映像保持可用的时间量。这是通过参数 UNDO_RETENTION 控制的,以秒为单位定义。因此,值 900 表示 15 分钟。
一定要意识到,如果 undo 表空间中存在空间压力时,我们不保证前镜像一定会保留这么长时间。
因此,以下公式可用于计算最佳 undo 表空间大小:
从
Oracle 10g 开始,您可以选择使用 GUARANTEE 选项,以确保在定义的 undo_retention 时间之前,undo 信息不会被覆盖。
UNDO表空间大小由三部分组成:
(UR)UNDO_RETENTION 单位秒
(UPS)每秒产生的undo 数据块的个数
(DBS)
数据库数据文件块的大小DB_BLOCK_SIZE
计算公式
UndoSpace=UR*(UPS*DBS)
其中UNDO_RETENTION 和 DB_BLOCK_SIZE两部分的信息可以在实例配置参数信息中获取。
而第三部分UPS的信息需要从动态性能试图V$UNDOSTAT中获取
下面是获取(UPS)每秒产生的undo 数据块的个数.
SQL> SELECT undoblks/((end_time-begin_time)*86400) "Peak Undo Block Generation"
FROM v$undostat WHERE undoblks=(SELECT MAX(undoblks) FROM v$undostat);
其中列END_TIME and BEGIN_TIME 是日期类型,需要转换成秒(24 hours * 60 minutes * 60 seconds).
SQL> SELECT (UR * (UPS * DBS)) AS "Bytes" FROM (SELECT value AS UR FROM v$parameter WHERE name = 'undo_retention'), (SELECT undoblks/((end_time-begin_time)*86400) AS UPS FROM v$undostat WHERE undoblks = (SELECT MAX(undoblks) FROM v$undostat)), (SELECT block_size AS DBS FROM dba_tablespaces WHERE tablespace_name = (SELECT UPPER(value) FROM v$parameter WHERE name = 'undo_tablespace')); |
10g 和10g 更高的版本,可以使用下面的查询:
SQL>SELECT (UR * (UPS * DBS)) AS "Bytes" FROM (select max(tuned_undoretention) AS UR from v$undostat), (SELECT undoblks/((end_time-begin_time)*86400) AS UPS FROM v$undostat WHERE undoblks = (SELECT MAX(undoblks) FROM v$undostat)), (SELECT block_size AS DBS FROM dba_tablespaces WHERE tablespace_name = (SELECT UPPER(value) FROM v$parameter WHERE name = 'undo_tablespace')); |
默认的三个类加载器
Java默认是有三个ClassLoader,按层次关系从上到下依次是:
Bootstrap ClassLoader
Ext ClassLoader
System ClassLoader
Bootstrap ClassLoader是最顶层的ClassLoader,它比较特殊,是用C++编写集成在JVM中的,是JVM启动的时候用来加载一些核心类的,比如:rt.jar,resources.jar,charsets.jar,jce.jar等,可以运行下面代码看都有哪些:
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm());
}
其余两个ClassLoader都是继承自ClassLoader这个类。Java的类加载采用了一种叫做“双亲委托”的方式(稍后解释),所以除了Bootstrap ClassLoader其余的ClassLoader都有一个“父”类加载器, 不是通过集成,而是一种包含的关系。
//ClassLoader.java
public abstract class ClassLoader {
...
// The parent class loader for delegation
private ClassLoader parent;
...
“双亲委托”
所谓“双亲委托”就是当加载一个类的时候会先委托给父类加载器去加载,当父类加载器无法加载的时候再尝试自己去加载,所以整个类的加载是“自上而下”的,如果都没有加载到则抛出ClassNotFoundException异常。
上面提到Bootstrap ClassLoader是最顶层的类加载器,实际上Ext ClassLoader和System ClassLoader就是一开始被它加载的。
Ext ClassLoader称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有的jar(包括自己手动放进去的jar包)。
System ClassLoader叫做系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件,包括我们平时运行jar包指定cp参数下的jar包。
运行下面的代码可以验证上面内容:
ClassLoader loader = Debug.class.getClassLoader();
while(loader != null) {
System.out.println(loader);
loader = loader.getParent();
}
System.out.println(loader);
“双亲委托”的作用
之所以采用“双亲委托”这种方式主要是为了安全性,避免用户自己编写的类动态替换Java的一些核心类,比如String,同时也避免了重复加载,因为JVM中区分不同类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就是不同的两个类,如果相互转型的话会抛java.lang.ClassCaseException.
自定义类加载器
除了上面说的三种默认的类加载器,用户可以通过继承ClassLoader类来创建自定义的类加载器,之所以需要自定义类加载器是因为有时候我们需要通过一些特殊的途径创建类,比如网络。
至于自定义类加载器是如何发挥作用的,ClassLoader类的loadClass方法已经把算法定义了:
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
>1. Invoke findLoadedClass(String) to check if the class has already been loaded.
>2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
>3. Invoke the findClass(String) method to find the class.
看上面的Javadoc可以知道,自定义的类加载器只要重载findClass就好了。
Context ClassLoader
首先Java中ClassLoader就上面提到的四种,Bootstrap ClassLoader,Ext ClassLoader,System ClassLoader以及用户自定义的,所以Context ClassLoader并不是一种新的类加载器,肯定是这四种的一种。
首先关于类的加载补充一点就是如果类A是被一个加载器加载的,那么类A中引用的B也是由这个加载器加载的(如果B还没有被加载的话),通常情况下就是类B必须在类A的classpath下。
但是考虑多线程环境下不同的对象可能是由不同的ClassLoader加载的,那么当一个由ClassLoaderC加载的对象A从一个线程被传到另一个线程ThreadB中,而ThreadB是由ClassLoaderD加载的,这时候如果A想获取除了自己的classpath以外的资源的话,它就可以通过Thread.currentThread().getContextClassLoader()来获取线程上下文的ClassLoader了,一般就是ClassLoaderD了,可以通过Thread.currentThread().setContextClassLoader(ClassLoader)来显示的设置。
为什么要有Contex ClassLoader
之所以有Context ClassLoader是因为Java的这种“双亲委托”机制是有局限性的:
举网上的一个例子:
> JNDI为例,JNDI的类是由bootstrap ClassLoader从rt.jar中间载入的,但是JNDI具体的核心驱动是由正式的实现提供的,并且通常会处于-cp参数之下(注:也就是默认的System ClassLoader管理),这就要求bootstartp ClassLoader去载入只有SystemClassLoader可见的类,正常的逻辑就没办法处理。怎么办呢?parent可以通过获得当前调用Thread的方法获得调用线程的>Context ClassLoder 来载入类。
我上面提到的加载资源的例子。
Contex ClassLoader提供了一个突破这种机制的后门。
Context ClassLoader一般在一些框架代码中用的比较多,平时写代码的时候用类的ClassLoader就可以了。