??xml version="1.0" encoding="utf-8" standalone="yes"?>天堂av电影在线观看,国产91露脸中文字幕在线,久久夜色精品国产欧美乱极品http://www.aygfsteel.com/conans/category/32378.html你越挣扎我就兴?/description>zh-cnWed, 10 Aug 2011 08:59:02 GMTWed, 10 Aug 2011 08:59:02 GMT60log4j详解与实??http://www.aygfsteel.com/conans/articles/355064.htmlCONANCONANTue, 26 Jul 2011 07:03:00 GMThttp://www.aygfsteel.com/conans/articles/355064.htmllog4j是一个非常强大的log记录软gQ下面我们就来看看在目中如何log4j?/p>

 

首先当然是得到l(f)og4j的jar档,推荐使用1.2.X版,下蝲地址Q?/p>

http://logging.apache.org/log4j/1.2/download.html

 

我们先看一个最单的CZQ?/p>

【示??/strong>

目l构Q?/span>



【注Q?span style="color: #ff0000">׃q里的多个项目公用一个jar档,我们可以创徏一个专门放|jar档的Java工程Q然后将jar档放到l(f)ib目录下。在要用的工程中按图所C行引?/span> ?/p>

 

 1 package com.coderdream.log4j;
 2 
 3 import org.apache.log4j.Logger;
 4 
 5 public class HelloLog4j {
 6 
 7     private static Logger logger = Logger.getLogger(HelloLog4j.class);
 8 
 9     /**
10      * @param args
11      */
12     public static void main(String[] args) {
13         // System.out.println("This is println message.");
14         
15         // 记录debugU别的信?/span>
16         logger.debug("This is debug message.");
17         // 记录infoU别的信?/span>
18         logger.info("This is info message.");
19         // 记录errorU别的信?/span>
20         logger.error("This is error message.");
21     }
22 }

 配置文glog4j.properties:

 1 #可以讄U别Qdebug>info>error
 2 #debugQ显Cdebug、info、error
 3 #infoQ显Cinfo、error
 4 #errorQ只error
 5 log4j.rootLogger=debug,appender1
 6 #log4j.rootLogger=info,appender1
 7 #log4j.rootLogger=error,appender1
 8 
 9 #输出到控制台
10 log4j.appender.appender1=org.apache.log4j.ConsoleAppender
11 #样式为TTCCLayout
12 log4j.appender.appender1.layout=org.apache.log4j.TTCCLayout
输出l果Q?/span>

 

[main] DEBUG com.coderdream.log4j.HelloLog4j - This is debug message.
[main] INFO com.coderdream.log4j.HelloLog4j 
- This is info message.
[main] ERROR com.coderdream.log4j.HelloLog4j 
- This is error message.


 

通过配置文g可知Q我们需要配|?个方面的内容Q?/p>

1、根目录Q别和目的圎ͼQ?/p>

2、目的地Q控制台、文件等{)Q?/p>

3、输出样式?/p>


下面我们来看看Log4J的类图:


 

Logger - 日志写出器,供程序员输出日志信息
Appender - 日志目的圎ͼ把格式化好的日志信息输出到指定的地方?
ConsoleAppender - 目的Cؓ控制台的Appender
FileAppender - 目的Cؓ文g的Appender
RollingFileAppender - 目的Cؓ大小受限的文件的Appender
Layout - 日志格式化器Q用来把E序员的logging request格式化成字符?/strong>
PatternLayout - 用指定的pattern格式化logging request的Layout


Log4j基本使用Ҏ(gu)


  Log4j׃个重要的lg构成Q日志信息的优先U,日志信息的输出目的地Q日志信息的输出格式。日志信息的优先U从高到低有ERROR、WARN?INFO、DEBUGQ分别用来指定这条日志信息的重要E度Q日志信息的输出目的地指定了日志打印到控制台还是文件中Q而输出格式则控制了日志信息的昄内容?br />
  一、定义配|文?/span>

  其实(zhn)也可以完全不用配|文Ӟ而是在代码中配置Log4j环境。但是,使用配置文g(zhn)的应用E序更加灉|。Log4j支持两种配置文g格式Q一U是XML格式的文Ӟ一U是JavaҎ(gu)文Ӟ?|。下面我们介l用JavaҎ(gu)文件做为配|文件的Ҏ(gu)Q?br />
  1.配置根LoggerQ其语法为:

  log4j.rootLogger = [ level ] , appenderName, appenderName, …

  其中Qlevel 是日志记录的优先U,分ؓOFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者?zhn)定义的别。Log4j只用四个别,优先U从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的U别Q?zhn)可以控制到应用程序中相应U别的日志信息的开兟뀂比如在q里定义了INFOU别Q则应用E序中所有DEBUGU别的日志信息将不被打印出来?appenderName是指B日志信息输出到哪个地斏V?zhn)可以同时指定多个输出目的地?br />
  2.配置日志信息输出目的地AppenderQ其语法为:

  log4j.appender.appenderName = fully.qualified.name.of.appender.class
  log4j.appender.appenderName.option1 = value1
  …
  log4j.appender.appenderName.option = valueN

  其中QLog4j提供的appender有以下几U:
  org.apache.log4j.ConsoleAppenderQ控制台Q,
  org.apache.log4j.FileAppenderQ文ӞQ?br />  org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文ӞQ?br />  org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生一个新的文ӞQ?br />  org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)

  3.配置日志信息的格式(布局Q,其语法ؓQ?/span>

  log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
  log4j.appender.appenderName.layout.option1 = value1
  …
  log4j.appender.appenderName.layout.option = valueN

  其中QLog4j提供的layout有以e几种Q?br />  org.apache.log4j.HTMLLayoutQ以HTML表格形式布局Q,
  org.apache.log4j.PatternLayoutQ可以灵zd指定布局模式Q,
  org.apache.log4j.SimpleLayoutQ包含日志信息的U别和信息字W串Q,
  org.apache.log4j.TTCCLayoutQ包含日志生的旉、线E、类别等{信息)

  Log4J采用cMC语言中的printf函数的打印格式格式化日志信息Q打印参数如下: %m 输出代码中指定的消息

  %p 输出优先U,即DEBUGQINFOQWARNQERRORQFATAL
  %r 输出自应用启动到输出该log信息耗费的毫U数
  %c 输出所属的cȝQ通常是所在类的全?br />  %t 输出产生该日志事件的U程?br />  %n 输出一个回车换行符QWindowsq_?#8220;rn”QUnixq_?#8220;n”
  %d 输出日志旉点的日期或时_默认格式为ISO8601Q也可以在其后指定格式,比如Q?d{yyy MMM dd HH:mm:ss,SSS}Q输出类|2002q?0?8?22Q?0Q?8Q?21
  %l 输出日志事g的发生位|,包括cȝ名、发生的U程Q以及在代码中的行数。D例:Testlog4.main(TestLog4.java:10)

  二、在代码中用Log4j

  1.得到记录?/span>

  使用Log4jQ第一步就是获取日志记录器Q这个记录器负责控制日志信息。其语法为:

  public static Logger getLogger( String name)

  通过指定的名字获得记录器Q如果必要的话,则ؓq个名字创徏一个新的记录器。Name一般取本类的名字,比如Q?br />
  static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )

  2.d配置文g

  当获得了日志记录器之后,W二步将配置Log4j环境Q其语法为:

  BasicConfigurator.configure ()Q?自动快速地使用~省Log4j环境?br />  PropertyConfigurator.configure ( String configFilename) Q读取用Java的特性文件编写的配置文g?br />  DOMConfigurator.configure ( String filename ) Q读取XML形式的配|文件?br />
  3.插入记录信息Q格式化日志信息Q?/span>

  当上两个必要步骤执行完毕Q?zhn)可以轻村֜使用不同优先U别的日志记录语句插入到(zhn)想记录日志的Q何地方,其语法如下:

  Logger.debug ( Object message ) ;
  Logger.info ( Object message ) ;
  Logger.warn ( Object message ) ;
  Logger.error ( Object message ) ;


 

CZ2~示?

 

【示??/strong> 输出为文本文件或HTML文g

 

#讄U别Q?br />log4j.rootLogger=debug,appender1

#输出到文?q里默认加方?
log4j.appender.appender1
=org.apache.log4j.FileAppender
#讄文g输出路径
#?/span>1】文本文?br />#log4j.appender.appender1.File=c:/Log4JDemo02.log
#?/span>2】HTML文g
log4j.appender.appender1.File
=c:/Log4JDemo02.html
#讄文g输出样式
#log4j.appender.appender1.layout
=org.apache.log4j.TTCCLayout
log4j.appender.appender1.layout
=org.apache.log4j.HTMLLayout


?/strong> CZ3?/strong> 输出为文本文件或HTML文g

#讄U别和多个目的地
log4j.rootLogger
=debug,appender1,appender2

#输出到控制台
log4j.appender.appender1
=org.apache.log4j.ConsoleAppender
#讄输出样式
log4j.appender.appender1.layout
=org.apache.log4j.TTCCLayout

#输出到文?q里默认加方?
log4j.appender.appender2
=org.apache.log4j.FileAppender
#讄文g输出路径
#?/span>1】文本文?br />#log4j.appender.appender2.File=c:/Log4JDemo02.log
#?/span>2】HTML文g
log4j.appender.appender2.File
=c:/Log4JDemo02.html
#讄文g输出样式
#log4j.appender.appender2.layout
=org.apache.log4j.TTCCLayout
log4j.appender.appender2.layout
=org.apache.log4j.HTMLLayout
【示??/strong> SimpleLayout样式

 

#讄U别和目的地
log4j.rootLogger
=debug,appender1

#输出到控制台
log4j.appender.appender1
=org.apache.log4j.ConsoleAppender
#讄输出样式
log4j.appender.appender1.layout
=org.apache.log4j.SimpleLayout


 输出l果Q?/p>

DEBUG - This is debug message.
INFO 
- This is info message.
ERROR 
- This is error message.

【示??/strong> 自定义样?/p>

#讄U别和目的地
log4j.rootLogger
=debug,appender1

#输出到控制台
log4j.appender.appender1
=org.apache.log4j.ConsoleAppender
#讄输出样式
log4j.appender.appender1.layout
=org.apache.log4j.PatternLayout
#自定义样?br /># 
%r 旉 0
%t Ҏ(gu)?nbsp;main
%p 优先U?nbsp;DEBUG/INFO/ERROR
%c 所属类的全?包括包名)
%l 发生的位|,在某个类的某?br /># %m 输出代码中指定的讯息Q如log(message)中的message
%n 输出一个换?br />
log4j.appender.appender1.layout.ConversionPattern
=%r [%t] [%p] - %-%-%m%n

输出l果Q?/p>

1 0 [main] [DEBUG] - com.coderdream.log4j.HelloLog4j 
2 -com.coderdream.log4j.HelloLog4j.main(HelloLog4j.java:16-This is debug message.
3 31 [main] [INFO] - com.coderdream.log4j.HelloLog4j 
4 -com.coderdream.log4j.HelloLog4j.main(HelloLog4j.java:18-This is info message.
5 31 [main] [ERROR] - com.coderdream.log4j.HelloLog4j 
6 -com.coderdream.log4j.HelloLog4j.main(HelloLog4j.java:20-This is error message.

【示??/strong> 多目的地、自定义样式

#讄U别和目的地
log4j.rootLogger
=debug,appender1,appender2

#输出到控制台
log4j.appender.appender1
=org.apache.log4j.ConsoleAppender
#讄输出样式
log4j.appender.appender1.layout
=org.apache.log4j.PatternLayout
#自定义样?br /># %r 旉 
0
# %t Ҏ(gu)?nbsp;main
# %p 优先U?nbsp;DEBUG/INFO/ERROR
# %c 所属类的全?包括包名)
# %l 发生的位|,在某个类的某?br /># %m 输出代码中指定的讯息Q如log(message)中的message
# %n 输出一个换行符?br />log4j.appender.appender1.layout.ConversionPattern
=[%d{yy/MM/dd HH:mm:ss:SSS}][%C-%M] %m%n

#输出到文?q里默认加方?
log4j.appender.appender2
=org.apache.log4j.FileAppender
#讄文g输出路径
#?/span>1】文本文?br />log4j.appender.appender2.File=c:/Log4JDemo06.log
#讄文g输出样式
log4j.appender.appender2.layout
=org.apache.log4j.PatternLayout
log4j.appender.appender2.layout.ConversionPattern
=[%d{HH:mm:ss:SSS}][%C-%M] -%m%n

【示??/strong> 【企业应用】设|?/span> 特定包的U别和目的地

先增加一个包Q新Z个类Q?/p>

package com.coderdream.log4jDao;

import org.apache.log4j.Logger;

public class HelloDao {
    
private static Logger logger = Logger.getLogger(HelloDao.class);

    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        
// 记录debugU别的信?/span>
        logger.debug("This is debug message from Dao.");
        
// 记录infoU别的信?/span>
        logger.info("This is info message from Dao.");
        
// 记录errorU别的信?/span>
        logger.error("This is error message from Dao.");
    }
}


如果q个cM为基c,如J2EE中的BaseDao、BaseAction、BaseService{等Q则我们可以各层的日志信息分类输出到各个文件?/p>

#省略根,只设|特定包的别和目的?br />log4j.logger.com.coderdream.log4j=debug,appender1
log4j.logger.com.coderdream.log4jDao
=info,appender1,appender2

#输出到控制台
log4j.appender.appender1
=org.apache.log4j.ConsoleAppender
#讄输出样式
log4j.appender.appender1.layout
=org.apache.log4j.PatternLayout
#自定义样?br /># %r 旉 
0
# %t Ҏ(gu)?nbsp;main
# %p 优先U?nbsp;DEBUG/INFO/ERROR
# %c 所属类的全?包括包名)
# %l 发生的位|,在某个类的某?br /># %m 输出代码中指定的讯息Q如log(message)中的message
# %n 输出一个换行符?br />log4j.appender.appender1.layout.ConversionPattern
=[%d{yy/MM/dd HH:mm:ss:SSS}][%C-%M] %m%n

#输出到文?q里默认加方?
log4j.appender.appender2
=org.apache.log4j.FileAppender
#讄文g输出路径
#?/span>1】文本文?br />log4j.appender.appender2.File=c:/Log4JDemo07_Dao.log
#讄文g输出样式
log4j.appender.appender2.layout
=org.apache.log4j.PatternLayout
log4j.appender.appender2.layout.ConversionPattern
=[%d{HH:mm:ss:SSS}][%C-%M] -%m%n
【示??/strong> log4j.xml的配|方?br />

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 3 
 4 <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 5 
 6     <appender name="appender1"
 7         class="org.apache.log4j.RollingFileAppender">
 8         <param name="File" value="logfile08.html" />
 9         <param name="MaxFileSize" value="1MB" />
10         <param name="MaxBackupIndex" value="5" />
11         <layout class="org.apache.log4j.HTMLLayout">
12         </layout>
13     </appender>
14 
15     <root>
16         <level value="debug" />
17         <appender-ref ref="appender1" />
18     </root>
19 </log4j:configuration>

Z提高效率Q我们可以在写日志前增加判断Q?/p>

// 记录debugU别的信?/span>
if (logger.isDebugEnabled()) {
    logger.debug(
"This is debug message from Dao.");
}

// 记录infoU别的信?/span>
if (logger.isInfoEnabled()) {
    logger.info(
"This is info message from Dao.");
}

// 记录errorU别的信?/span>
logger.error("This is error message from Dao.");




















CONAN 2011-07-26 15:03 发表评论
]]>
log4j详解http://www.aygfsteel.com/conans/articles/345084.htmlCONANCONANThu, 24 Feb 2011 09:14:00 GMThttp://www.aygfsteel.com/conans/articles/345084.html阅读全文

CONAN 2011-02-24 17:14 发表评论
]]>
Log4j性能调优http://www.aygfsteel.com/conans/articles/345083.htmlCONANCONANThu, 24 Feb 2011 09:10:00 GMThttp://www.aygfsteel.com/conans/articles/345083.html
log4j.rootLogger=ERROR,fileout,stdout
log4j.logger.monitorLogger=INFO,monitorAppender
log4j.additivity.monitorLogger
=false


log4j.appender.stdout
=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout
=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern
=%d (%F:%L) %-5p %c - %m%n

log4j.appender.fileout
=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fileout.File
=logs/server_log.txt
log4j.appender.fileout.layout
=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern
=%d [%t] (%F:%L) %-5p %c - %m%n

log4j.appender.monitorAppender
=org.apache.log4j.DailyRollingFileAppender
log4j.appender.monitorAppender.File
=mtlogs/mt_log.txt
log4j.appender.monitorAppender.layout
=org.apache.log4j.PatternLayout
log4j.appender.monitorAppender.layout.ConversionPattern
=%m%n
log4j.appender.monitorAppender.DatePattern
='.'yyyy-MM-dd-HH
log4j.appender.monitorAppender.BufferedIO
=true
#Buffer单位为字节,默认?K
log4j.appender.monitorAppender.BufferSize=8192
1Q?span style="color: #ff0000;">log4j.additivity.monitorLogger=false
q个选项用于控制监控logger的日志不会输出到rootloggerQ否则无Z产生许多重复的数据,同时也会影响性能Q?br />
2Q?/span>
log4j.appender.monitorAppender.DatePattern='.'yyyy-MM-dd-HH
q个选项用于告诉
DailyRollingFileAppender每小时输出日志,而不是默认的一天输Zơ,因ؓ监控日志的数据量很巨大,如果以天为单位输出,日志文g会很大(GU)Q而且再处理会很耗时?br /> 其他一些输出选项q有Q?br /> 1)'.'yyyy-MM: 每月
2)'.'yyyy-ww: 每周
3)'.'yyyy-MM-dd: 每天
4)'.'yyyy-MM-dd-a: 每天两次
5)'.'yyyy-MM-dd-HH: 每小?
6)'.'yyyy-MM-dd-HH-mm: 每分?

3Q?/span>log4j.appender.monitorAppender.BufferedIO=true
log4j.appender.monitorAppender.BufferSize=8192
q? 个选项用于告诉log4j输出日志的时候采用缓冲的方式Q而不是即时flush方式Qƈ且设定了~冲?KQ?K是默认|可以Ҏ(gu)日志输出的情冉|? 攏V这个选项很重要,在测试中发现Q当q发讉K很高Q例如每一U?00个ƈ发以上,使用~存跟不使用~冲差距很大。具体数字我q里׃列出来了?br /> 另外我想说的是,log4j输出~冲日志是以8K为单位的Q因为磁盘的一个block?KQ这样可以减碎片,也就是说假设你设|缓存ؓ18KQlog4j?6KQ?K*2)的时候就会输出)Q而不?8K?br />
4Q组装输出内容之前可对logger的输出别先q行判断而不要完全依赖log4j控制Q因为组装输出日志内容也是要损耗效率的?br />         //若log4jq未开启infoU日志记录,直接q回
        if(!monitorLogger.isInfoEnabled()){
            return;
        }
        StringBuilder log = new StringBuilder();
        logSql.append(logPk+" ");
        ...

5Q用异步输?org.apache.log4j.AsyncAppenderQ异步输出必M用xml方式配置才能支持Q我把上面properties形式的配|文件用xml表达一下:
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration debug="true">

    
<appender name="stdout"
        class
="org.apache.log4j.ConsoleAppender">
        
<layout class="org.apache.log4j.PatternLayout">
            
<param name="ConversionPattern" value="%d (%F:%L) %-5p %c - %m%n" />
        
</layout>
    
</appender>

    
<appender name="fileout"
        class
="org.apache.log4j.DailyRollingFileAppender">
        
<layout class="org.apache.log4j.PatternLayout">
            
<param name="ConversionPattern" value="%d [%t] (%F:%L) %-5p %c - %m%n" />
        
</layout>
        
<param name="File"
            value
="logs/server_log.txt" />
    
</appender>

    
<appender name="monitorAppender"
        class
="org.apache.log4j.DailyRollingFileAppender">
        
<layout class="org.apache.log4j.PatternLayout">
            
<param name="ConversionPattern" value="%m%n" />
        
</layout>
        
<param name="DatePattern" value="'.'yyyy-MM-dd-HH" />        
        
<param name="File" value="mtlogs/mt_log.txt" />
        
<param name="BufferedIO" value="true" />
        
<!-- 8KZ个写单元 -->
        
<param name="BufferSize" value="8192" />
    
</appender>

    
<appender name="async" class="org.apache.log4j.AsyncAppender">
        
<appender-ref ref="monitorAppender"/>
    
</appender>
    
    
<root>
        
<priority value="error" />
        
<appender-ref ref="stdout" />
        
<appender-ref ref="fileout" />
    
</root>
    
    
<category name="com.danga.MemCached">
        
<priority value="error" />
        
<appender-ref ref="fileout" />
    
</category >
    
    
<category name="com.opensymphony">
        
<priority value="error" />
        
<appender-ref ref="fileout" />
    
</category >
    
    
<category name="monitorLogger" additivity="false">
        
<priority value="info" />
        
<appender-ref ref="async" />
    
</category >
</log4j:configuration>
配置中红色的部分是用于支持异步输出的,在用jmeter试的过E中发觉使用异步方式Q工作的不是很稳定。性能的提升也不显著。所以最后ƈ没有采用?br />
InputStream in=null;
        
try {
             in 
= Log4jConfigLocator.class.getResourceAsStream(fileName);
             
if(fileName.endsWith(".xml")){
                 
//载入XML格式的配|文?/span>
                 Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
                 DOMConfigurator.configure(doc.getDocumentElement());
             }
else{
                 
//载入properties格式的配|文?/span>
                 Properties props = new Properties();
                 props.load(in);
                 PropertyConfigurator.configure(props);
             }
        




CONAN 2011-02-24 17:10 发表评论
]]>
动态非侵入拦截http://www.aygfsteel.com/conans/articles/282635.htmlCONANCONANTue, 16 Jun 2009 08:18:00 GMThttp://www.aygfsteel.com/conans/articles/282635.html阅读全文

CONAN 2009-06-16 16:18 发表评论
]]>
Word/Excel/PDF文g转换成HTML整理http://www.aygfsteel.com/conans/articles/255092.htmlCONANCONANTue, 17 Feb 2009 06:57:00 GMThttp://www.aygfsteel.com/conans/articles/255092.html目开发过E中Q需求涉及到了各U文档{换ؓHTML或者网|昄格式Q现在将实现方式整理如下Q?
一、用Jacob转换Word,Excel为HTML

“JACOB一个Java-COM中间?通过q个lg你可以在Java应用E序中调用COMlg和Win32 libraries?#8221;

首先下蝲Jacob包,JDK1.5以上需要用Jacob1.9版本QJDK1.6未试Q,与先前的Jacob1.7差别不大

1、将压羃包解压后QJacob.jard到Libraries中;

2、将Jacob.dll放至“WINDOWS\SYSTEM32”下面?br />
需要注意的是:
【用IDE启动Web服务器时Q系l读取不到Jacob.dllQ例如用MyEclipse启动TomcatQ就需要将dll文gcopy到MyEclipse安装目录?#8220;jre\bin”下面?
一般系l没有加载到Jacob.dll文gӞ报错信息为:“java.lang.UnsatisfiedLinkError: no jacob in java.library.path”?

新徏c:

Java代码 复制代码
  1. public class JacobUtil   
  2. {   
  3.     public static final int WORD_HTML = 8;   
  4.   
  5.     public static final int WORD_TXT = 7;   
  6.   
  7.     public static final int EXCEL_HTML = 44;   
  8.   
  9.     /**  
  10.      * WORD转HTML  
  11.      * @param docfile WORD文g全\? 
  12.      * @param htmlfile 转换后HTML存放路径  
  13.      */  
  14.     public static void wordToHtml(String docfile, String htmlfile)   
  15.     {   
  16.         ActiveXComponent app = new ActiveXComponent("Word.Application"); // 启动word   
  17.         try  
  18.         {   
  19.             app.setProperty("Visible"new Variant(false));   
  20.             Dispatch docs = app.getProperty("Documents").toDispatch();   
  21.             Dispatch doc = Dispatch.invoke(   
  22.                     docs,   
  23.                     "Open",   
  24.                     Dispatch.Method,   
  25.                     new Object[] { docfile, new Variant(false),   
  26.                             new Variant(true) }, new int[1]).toDispatch();   
  27.             Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object[] {   
  28.                     htmlfile, new Variant(WORD_HTML) }, new int[1]);   
  29.             Variant f = new Variant(false);   
  30.             Dispatch.call(doc, "Close", f);   
  31.         }   
  32.         catch (Exception e)   
  33.         {   
  34.             e.printStackTrace();   
  35.         }   
  36.         finally  
  37.         {   
  38.             app.invoke("Quit"new Variant[] {});   
  39.         }   
  40.     }   
  41.   
  42.     /**  
  43.      * EXCEL转HTML  
  44.      * @param xlsfile EXCEL文g全\? 
  45.      * @param htmlfile 转换后HTML存放路径  
  46.      */  
  47.     public static void excelToHtml(String xlsfile, String htmlfile)   
  48.     {   
  49.         ActiveXComponent app = new ActiveXComponent("Excel.Application"); // 启动word   
  50.         try  
  51.         {   
  52.             app.setProperty("Visible"new Variant(false));   
  53.             Dispatch excels = app.getProperty("Workbooks").toDispatch();   
  54.             Dispatch excel = Dispatch.invoke(   
  55.                     excels,   
  56.                     "Open",   
  57.                     Dispatch.Method,   
  58.                     new Object[] { xlsfile, new Variant(false),   
  59.                             new Variant(true) }, new int[1]).toDispatch();   
  60.             Dispatch.invoke(excel, "SaveAs", Dispatch.Method, new Object[] {   
  61.                     htmlfile, new Variant(EXCEL_HTML) }, new int[1]);   
  62.             Variant f = new Variant(false);   
  63.             Dispatch.call(excel, "Close", f);   
  64.         }   
  65.         catch (Exception e)   
  66.         {   
  67.             e.printStackTrace();   
  68.         }   
  69.         finally  
  70.         {   
  71.             app.invoke("Quit"new Variant[] {});   
  72.         }   
  73.     }   
  74.   
  75. }  

当时我在找{换控件时Q发现网易也转蝲了一偏关于Jacob使用帮助Q但其中出现了比较严重的错误QString htmlfile = "C:\\AA";

只指定到了文件夹一U,正确写法是String htmlfile = "C:\\AA\\xxx.html";

 

到此WORD/EXCEL转换HTML已l差不多了,怿大家应该很清楚了:)

 

二、用XPDFPDF转换为HTML

 

1、下载xpdf最新版本,地址Q?a >http://www.foolabs.com/xpdf/download.html

我下载的?span class="Apple-style-span" style="word-spacing: 0px; text-transform: none; color: #000000; text-indent: 0px; font-family: Simsun; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px">xpdf-3.02pl2-win32.zip

 

2、下载中文支持包

我下载的?span class="Apple-style-span" style="word-spacing: 0px; text-transform: none; color: #000000; text-indent: 0px; font-family: Simsun; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px">xpdf-chinese-simplified.tar.gz

 

3、下载pdftohtml支持?/p>

地址Q?a >http://sourceforge.net/projects/pdftohtml/

我下载的是:pdftohtml-0.39-win32.tar.gz

 

4、解压调?/p>

1) 先将xpdf-3.02pl2-win32.zip解压Q解压后的内容可Ҏ(gu)需要进行删减,如果只需要{换ؓtxt格式Q其他的exe文g可以删除Q只保留pdftotext.exeQ以此类推;

2) 然后xpdf-chinese-simplified.tar.gz解压到刚才xpdf-3.02pl2-win32.zip的解压目录;

3) pdftohtml-0.39-win32.tar.gz解压Qpdftohtml.exe解压到xpdf-3.02pl2-win32.zip的解压目录;

4) 目录l构Q?/p>

 +---[X:\xpdf]

           |-------各种转换用到的exe文g

           |

           |-------xpdfrc

           |

           +------[X:\xpdf\xpdf-chinese-simplified]

                                      |

                                      |

                                      +-------很多转换旉要用到的字符文g

 

xpdfrcQ此文g是用来声明{换字W集对应路径的文?/p>

 

5) 修改xpdfrc文g(文g原名为sample-xpdfrc)

修改文g内容为:

 

Txt代码 复制代码
  1. #----- begin Chinese Simplified support package   
  2. cidToUnicode    Adobe-GB1       xpdf-chinese-simplified\Adobe-GB1.cidToUnicode   
  3. unicodeMap      ISO-2022-CN     xpdf-chinese-simplified\ISO-2022-CN.unicodeMap   
  4. unicodeMap      EUC-CN          xpdf-chinese-simplified\EUC-CN.unicodeMap   
  5. unicodeMap  GBK    xpdf-chinese-simplified\GBK.unicodeMap   
  6. cMapDir         Adobe-GB1       xpdf-chinese-simplified\CMap   
  7. toUnicodeDir                    xpdf-chinese-simplified\CMap   
  8. fontDir  C:\WINDOWS\Fonts   
  9. displayCIDFontTT Adobe-GB1 C:\WINDOWS\Fonts\simhei.ttf   
  10. #----- end Chinese Simplified support package  

 

6) 创徏bat文gpdftohtml.batQ放|的路径不能包含I格Q?/p>

内容为:

 

Txt代码 复制代码
  1. @echo off   
  2. set folderPath=%1  
  3. set filePath=%2  
  4. cd /d %folderPath%   
  5. pdftohtml -enc GBK %filePath%   
  6. exit  

 

7) 创徏c?/p>

 

Java代码 复制代码
  1. public class ConvertPdf   
  2. {   
  3.     private static String INPUT_PATH;   
  4.     private static String PROJECT_PATH;   
  5.        
  6.     public static void convertToHtml(String file, String project)   
  7.     {   
  8.         INPUT_PATH = file;   
  9.         PROJECT_PATH = project;   
  10.         if(checkContentType()==0)   
  11.         {   
  12.             toHtml();   
  13.         }   
  14.     }   
  15.        
  16.     private static int checkContentType()   
  17.     {   
  18.         String type = INPUT_PATH.substring(INPUT_PATH.lastIndexOf(".") + 1, INPUT_PATH.length())   
  19.                 .toLowerCase();   
  20.         if (type.equals("pdf"))   
  21.             return 0;   
  22.         else  
  23.             return 9;   
  24.     }   
  25.        
  26.     private static void toHtml()   
  27.     {   
  28.         if(new File(INPUT_PATH).isFile())   
  29.         {   
  30.             try  
  31.             {   
  32.                 String cmd = "cmd /c start X:\\pdftohtml.bat \"" + PROJECT_PATH + "\" \"" + INPUT_PATH + "\"";   
  33.                 Runtime.getRuntime().exec(cmd);   
  34.             }   
  35.             catch (IOException e)   
  36.             {   
  37.                 e.printStackTrace();   
  38.             }   
  39.         }   
  40.     }   
  41.        
  42. }  

String cmd = "....";此处代码是调用创建的bat文gq行转换 

 

8) 试转换

 

 

Java代码 复制代码
  1. public static void main(String[] args)   
  2. {   
  3.     ConvertPdf.convertToHtml("C:\\test.pdf""X:\\xpdf");   
  4. }  

 

 

以上是整理的内容,后箋q会d视频转换为FLV格式Q如果需要的?)

说的不是很详l,到问题的朋友可以自己努力解决一?)



CONAN 2009-02-17 14:57 发表评论
]]>
JavaE序cd载完全揭?/title><link>http://www.aygfsteel.com/conans/articles/251110.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 13 Jan 2009 05:00:00 GMT</pubDate><guid>http://www.aygfsteel.com/conans/articles/251110.html</guid><description><![CDATA[<p>cd载是java语言提供的最强大的机制之一。尽类加蝲q不是讨论的热点话题Q但所有的~程人员都应该了解其工作机制Q明白如何做才能让其满我们的需要。这能有效节省我们的~码旉Q从不断调试ClassNotFoundException, ClassCastException的工作中解脱出来? <br /> <br /> q篇文章从基讲vQ比如代码与数据的不同之处是什么,他们是如何构成一个实例或对象的。然后深入探讨java虚拟机(JVMQ是如何利用cd载器d代码Q以及java中类加蝲器的主要cd。接着用一个类加蝲的基本算法看一下类加蝲器如何加载一个内部类。本文的下一节演CZD代码来说明扩展和开发属于自qcd载器的必要性。紧接着解释如何使用定制的类加蝲器来完成一个一般意义上的Q务,使其可以加蝲Lq端客户的代码,在JVM中定义,实例化ƈ执行它。本文包括了J2EE关于cd载的规范——事实上q已l成ZJ2EE的标准之一?br />                                                                                                   <br /> <strong>cM数据</strong><br /> <br /> 一个类代表要执行的代码Q而数据则表示其相关状态。状态时常改变,而代码则不会。当我们一个特定的状态与一个类相对应v来,也就意味着一个类事例化。尽相同的cd应的实例其状态千差万别,但其本质都对应着同一D代码。在JAVA中,一个类通常有着一?class文gQ但也有例外。在JAVA的运行时环境中(Java runtimeQ,每一个类都有一个以W一c?first-class)的Java对象所表现出现的代码,其是java.lang.Class的实例。我们编译一个JAVA文gQ编译器都会嵌入一个public, static, final修饰的类型ؓjava.lang.ClassQ名UCؓclass的域变量在其字节码文件中。因Z用了public修饰Q我们可以采用如下的形式对其讉KQ?br /> <br /> </p> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>java.lang.Class klass = Myclass.class;</td> </tr> </tbody> </table> <br /> 一旦一个类被蝲入JVM中,同一个类׃会被再次载入了(切记Q同一个类Q。这里存在一个问题就是什么是“同一个类”Q正如一个对象有一个具体的状态,x识,一个对象始l和其代?c?相关联。同理,载入JVM的类也有一个具体的标识Q我们接下来看?br /> <br /> 在Java中,一个类用其完全匚wcd(fully qualified class name)作ؓ标识Q这里指的完全匹配类名包括包名和cd。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如果一个名为Pg的包中,有一个名为Cl的类Q被cd载器KlassLoader的一个实例kl1加蝲QCl的实例,即C1.class在JVM中表CZؓ(Cl, Pg, kl1)。这意味着两个cd载器的实?Cl, Pg, kl1) ?(Cl, Pg, kl2)是不同的Q被它们所加蝲的类也因此完全不同,互不兼容的。那么在JVM中到底有多少U类加蝲器的实例Q下一节我们揭C答案?br /> <br /> <strong>cd载器</strong><br /> <br /> 在JVM中,每一个类都被java.lang.ClassLoader的一些实例来加蝲.cClassLoader是在包中java.lang里,开发者可以自由地l承它ƈd自己的功能来加蝲cR?br /> <br /> 无论何时我们键入java MyMainClass来开始运行一个新的JVMQ?#8220;引导cd载器(bootstrap class loader)”负责一些关键的Javac,如java.lang.Object和其他一些运行时代码先加载进内存中。运行时的类在JRE\lib\rt.jar包文件中。因属于pȝ底层执行动作Q我们无法在JAVA文档中找到引导类加蝲器的工作l节。基于同L原因Q引导类加蝲器的行ؓ在各JVM之间也是大相径庭?br /> 同理Q如果我们按照如下方式:<br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>log(java.lang.String.class.getClassLoader());</td> </tr> </tbody> </table> <p><br /> 来获取java的核心运行时cȝ加蝲器,׃得到null?br /> <br /> 接下来介ljava的扩展类加蝲器。扩展库提供比javaq行代码更多的特性,我们可以把扩展库保存在由java.ext.dirs属性提供的路径中?br /> <br /> (~辑注:java.ext.dirs属性指的是pȝ属性下的一个keyQ所有的pȝ属性可以通过System.getProperties()Ҏ(gu)获得。在~者的pȝ中,java.ext.dirs的value?#8221; C:\Program Files\Java\jdk1.5.0_04\jre\lib\ext”。下面将要谈到的如java.class.path也同属系l属性的一个key?<br /> <br /> cExtClassLoader专门用来加蝲所有java.ext.dirs下的.jar文g。开发者可以通过把自q.jar文g或库文g加入到扩展目录的classpathQ其可以被扩展cd载器d?br /> <br /> 从开发者的角度Q第三种同样也是最重要的一U类加蝲器是AppClassLoader。这U类加蝲器用来读取所有的对应在java.class.pathpȝ属性的路径下的cR?br /> <br /> Sun的java指南中,文章“理解扩展cd?#8221;QUnderstanding Extension Class LoadingQ对以上三个cd载器路径有更详尽的解释,q是其他几个JDK中的cd载器<br /> <br /> ●java.net.URLClassLoader <br /> <br /> ●java.security.SecureClassLoader <br /> <br /> ●java.rmi.server.RMIClassLoader <br /> <br /> ●sun.applet.AppletClassLoader <br /> <br /> java.lang.ThreadQ包含了public ClassLoader getContextClassLoader()Ҏ(gu)Q这一Ҏ(gu)q回针对一具体U程的上下文环境cd载器。此cd载器qE的创徏者提供,以供此线E中q行的代码在需要加载类或资源时使用。如果此加蝲器未被徏立,~省是其父线E的上下文类加蝲器。原始的cd载器一般由d应用E序的类加蝲器徏立?/p> <p> </p> <p align="center">    <?gt;</p> <p align="center"><strong>cd载器如何工作Q?br /> <br /> </strong>  除了引导cd载器Q所有的cd载器都有一个父cd载器Q不仅如此,所有的cd载器也都是java.lang.ClassLoadercd。以上两U类加蝲器是不同的,而且对于开发者自订制的类加蝲器的正常q行也至关重要。最重要的方面是正确讄父类加蝲器。Q何类加蝲器,其父cd载器是加载该cd载器的类加蝲器实例。(CQ类加蝲器本w也是一个类Q)<br /> <br /> 使用loadClass()Ҏ(gu)可以从类加蝲器中获得该类。我们可以通过java.lang.ClassLoader的源代码来了解该Ҏ(gu)工作的细节,如下Q?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>protected synchronized Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException<br /> {<br /> // First check if the class is already loaded <br /> Class c = findLoadedClass(name); <br /> if (c == null) <br /> {<br /> try <br /> {<br /> if (parent != null)<br /> {<br /> c = parent.loadClass(name, false);<br /> } else {<br /> c = findBootstrapClass0(name);<br /> }<br /> } catch (ClassNotFoundException e) { <br /> // If still not found, then invoke // findClass to find the class. <br /> c = findClass(name);<br /> }<br /> }<br /> if (resolve) <br /> {<br /> resolveClass(c);<br /> }<br /> return c;<br /> }</td> </tr> </tbody> </table> <br /> 我们可以使用ClassLoader的两U构造方法来讄父类加蝲器:<br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>public class MyClassLoader extends ClassLoader<br /> {<br /> public MyClassLoader()<br /> {<br /> super(MyClassLoader.class.getClassLoader());<br /> }<br /> }</td> </tr> </tbody> </table> <br /> ?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>public class MyClassLoader extends ClassLoader<br /> {<br /> public MyClassLoader()<br /> {<br /> super(getClass().getClassLoader());<br /> }<br /> }</td> </tr> </tbody> </table> <br /> W一U方式较为常用,因ؓ通常不徏议在构造方法里调用getClass()Ҏ(gu)Q因为对象的初始化只是在构造方法的出口处才完全完成。因此,如果父类加蝲器被正确建立Q当要示从一个类加蝲器的实例获得一个类Ӟ如果它不能找到这个类Q它应该首先去访问其父类。如果父cM能找到它(卛_父类也不能找不这个类Q等{?Q而且如果findBootstrapClass0()Ҏ(gu)也失败了Q则调用findClass()Ҏ(gu)。findClass()Ҏ(gu)的缺省实C抛出ClassNotFoundExceptionQ当它们l承java.lang.ClassLoader来订制类加蝲器时开发者需要实现这个方法。findClass()的缺省实现方式如下:<br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); }</td> </tr> </tbody> </table> <br /> 在findClass()Ҏ(gu)内部Q类加蝲器需要获取Q意来源的字节码。来源可以是文gpȝQURLQ数据库Q可以生字节码的另一个应用程序,及其他类似的可以产生java规范的字节码的来源。你甚至可以使用BCEL (Byte Code Engineering LibraryQ字节码工程?Q它提供了运行时创徏cȝ捷径。BCEL已经被成功地使用在以下方面:~译器,优化器,h器,代码产生器及其他分析工具。一旦字节码被检索,此方法就会调用defineClass()Ҏ(gu)Q此行ؓ对不同的cd载实例是有差异的。因此,如果两个cd载实例从同一个来源定义一个类Q所定义的结果是不同的?br /> <br /> JAVA语言规范QJava language specificationQ详l解释了JAVA执行引擎中的cL接口的加载(loadingQ,链接QlinkingQ或初始化(initializationQ过E?br /> <br /> 图一昄了一个主cȝ为MyMainClass的应用程序。依照之前的阐述QMyMainClass.class会被AppClassLoader加蝲? MyMainClass创徏了两个类加蝲器的实例QCustomClassLoader1 ? CustomClassLoader2,他们可以从某数据源(比如|络Q获取名为Target的字节码。这表示cTarget的类定义不在应用E序c\径或扩展c\径。在q种情况下,如果MyMainClass惌用自定义的类加蝲器加载Targetc,CustomClassLoader1和CustomClassLoader2会分别独立地加蝲q定义Target.classcR这在java中有重要的意义。如果TargetcL一些静态的初始化代码,q且假设我们只希望这些代码在JVM中只执行一ơ,而这些代码在我们目前的步骤中会执行两ơ——分别被不同的CustomClassLoaders加蝲q执行。如果类Target被两个CustomClassLoaders加蝲q创Z个实例Target1和Target2Q如图一昄Q它们不是类型兼容的。换句话_在JVM中无法执行以下代码:<br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>Target target3 = (Target) target2;</td> </tr> </tbody> </table> <br /> 以上代码会抛Z个ClassCastException。这是因为JVM把他们视为分别不同的c,因ؓ他们被不同的cd载器所定义。这U情况当我们不是使用两个不同的类加蝲器CustomClassLoader1 ? CustomClassLoader2Q而是使用同一个类加蝲器CustomClassLoader的不同实例时Q也会出现同L错误。这些会在本文后边用具体代码说明?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/364n0268z3zb.JPG" width="449" height="566" /><br /> <br /> ?. 在同一个JVM中多个类加蝲器加载同一个目标类</div> </td> </tr> </tbody> </table> </p> <p align="center"> </p> <p align="center"><?gt;<br /> <strong>Z么我们需要我们自qcd载器<br /> <br /> </strong>  原因之一为开发者写自己的类加蝲器来控制JVM中的cd载行为,java中的c靠其包名和cd来标识,对于实现了java.io.Serializable接口的类QserialVersionUID扮演了一个标识类版本的重要角艌Ӏ这个唯一标识是一个类名、接口名、成员方法及属性等l成的一?4位的哈希字段Q而且也没有其他快L方式来标识一个类的版本。严D来,如果以上的都匚wQ那么则属于同一个类?br /> <br /> 但是让我们思考如下情况:我们需要开发一个通用的执行引擎。可以执行实现某一特定接口的Q何Q务。当d被提交到q个引擎Q首先需要加载这个Q务的代码。假设不同的客户Ҏ(gu)引擎提交了不同的dQ凑巧,q些所有的d都有一个相同的cd和包名。现在面临的问题是q个引擎是否可以针对不同的用h提交的信息而做Z同的反应。这一情况在下文的参考一节有可供下蝲的代码样例,samepath ?differentversionsQ这两个目录分别演示了这一概念?? 昄了文件目录结构,有三个子目录samepath, differentversions, ?differentversionspushQ里Ҏ(gu)例子Q?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/9l33653u08js.JPG" width="446" height="461" /><br /> ?. 文g夹结构组l示?/div> </td> </tr> </tbody> </table> <br /> 在samepath 中,cversion.Version保存在v1和v2两个子目录里Q两个类h同样的类名和包名Q唯一不同的是下边q行Q?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>public void fx(){ log("this = " + this + "; Version.fx(1)."); }</td> </tr> </tbody> </table> <br /> V1中,日志记录中有Version.fx(1)Q而在v2中则是Version.fx(2)。把q个两个存在l微不同的类攑֜一个classpath下,然后q行Testc:<br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>set CLASSPATH=.;%CURRENT_ROOT%\v1;%CURRENT_ROOT%\v2<br /> %JAVA_HOME%\bin\java Test</td> </tr> </tbody> </table> <br /> ?昄了控制台输出。我们可以看到对应着Version.fx(1)的代码被执行了,因ؓcd载器在classpath首先看到此版本的代码?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/spb0js0651u8.JPG" width="428" height="193" /><br /> ?. 在类路径中samepath试排在最前面的version 1</div> </td> </tr> </tbody> </table> <br /> 再次q行Q类路径做如下微改动?<br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>set CLASSPATH=.;%CURRENT_ROOT%\v2;%CURRENT_ROOT%\v1<br /> %JAVA_HOME%\bin\java Test</td> </tr> </tbody> </table> <br /> 控制台的输出变ؓ?。对应着Version.fx(2)的代码被加蝲Q因为类加蝲器在classpath中首先找到它的\径?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/wb8py2r57509.JPG" width="428" height="192" /><br /> ?. 在类路径中samepath试排在最前面的version 2</div> </td> </tr> </tbody> </table> <br /> Ҏ(gu)以上例子可以很明昑֜看出Q类加蝲器加载在c\径中被首先找到的元素。如果我们在v1和v2中删除了version.VersionQ做一个非version.Version形式?jar文gQ如myextension.jarQ把它放到对应java.ext.dirs的\径下Q再ơ执行后看到version.Version不再被AppClassLoader加蝲Q而是被扩展类加蝲器加载。如?所C?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/rm118409yo66.JPG" width="429" height="158" /><br /> ?. AppClassLoader及ExtClassLoader</div> </td> </tr> </tbody> </table> <br /> l箋q个例子Q文件夹differentversions包含了一个RMI执行引擎Q客L可以提供l执行引擎Q何实Ccommon.TaskIntf接口的Q务。子文g夹client1 ?client2包含了类client.TaskImpl有个l微不同的两个版本。两个类的区别在以下几行Q?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>static<br /> {<br /> log("client.TaskImpl.class.getClassLoader (v1) : " + TaskImpl.class.getClassLoader());<br /> }<br /> <br /> public void execute(){ log("this = " + this + "; execute(1)"); }</td> </tr> </tbody> </table> <br /> 在client1和client2里分别有getClassLoader(v1) ? execute(1)和getClassLoader(v2) ? execute(2)的的log语句。ƈ且,在开始执行引擎RMI服务器的代码中,我们随意地将client2的Q务实现放在类路径的前面?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>CLASSPATH=%CURRENT_ROOT%\common;%CURRENT_ROOT%\server;<br /> %CURRENT_ROOT%\client2;%CURRENT_ROOT%\client1<br /> %JAVA_HOME%\bin\java server.Server</td> </tr> </tbody> </table> <br /> 如图6Q?Q?的屏q截图,在客LVMQ各自的client.TaskImplc被加蝲、实例化Qƈ发送到服务端的VM来执行。从服务端的控制収ͼ可以明显看到client.TaskImpl代码只被服务端的VM执行一ơ,q个单一的代码版本在服务端多ơ生成了许多实例Qƈ执行d?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/511b346uj8rr.JPG" width="429" height="252" /><br /> ?. 执行引擎服务器控制台</div> </td> </tr> </tbody> </table> <br /> ?昄了服务端的控制台Q加载ƈ执行两个不同的客L的请求,如图7?所C。需要注意的是,代码只被加蝲了一ơ(从静态初始化块的日志中也可以明显看出Q,但对于客L的调用这个方法被执行了两ơ?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/806698qpznjf.JPG" width="429" height="169" /><br /> ?. 执行引擎客户? 1控制台 </div> </td> </tr> </tbody> </table> <br /> ?中,客户端VM加蝲了含有client.TaskImpl.class.getClassLoader(v1)的日志内容的cTaskImpl的代码,q提供给服务端的执行引擎。图8的客LVM加蝲了另一个TaskImpl的代码,q发送给服务端?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/75d4v3u7sq8y.JPG" width="428" height="169" /><br /> ?. 执行引擎客户? 2控制台 </div> </td> </tr> </tbody> </table> <br /> 在客L的VM中,cclient.TaskImpl被分别加载,初始化,q发送到服务端执行。图6q揭CZclient.TaskImpl的代码只在服务端的VM中加载了一ơ,但这“唯一的一?#8221;却在服务端创造了许多实例q执行。或许客L1该不高兴了因为ƈ不是它的client.TaskImpl(v1)的方法调用被服务端执行了Q而是其他的一些代码。如何解册一问题Q答案就是实现定制的cd载器?br /> </p> <p align="center"><?gt;</p> <p align="center"><strong>定制cd载器<br /> <br /> </strong>  要较好地控制cȝ加蝲Q就要实现定制的cd载器。所有自定义的类加蝲器都应承自java.lang.ClassLoader。而且在构造方法中Q我们也应该讄父类加蝲器。然后重写findClass()Ҏ(gu)。differentversionspush文g夹包含了一个叫做FileSystemClassLoader的自订制的类加蝲器。其l构如图9所C?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/r5ji48er1w43.JPG" width="400" height="630" /><br /> ?. 定制cd载器关系</div> </td> </tr> </tbody> </table> <br /> 以下是在common.FileSystemClassLoader实现的主Ҏ(gu)Q?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>public byte[] findClassBytes(String className)<br /> {<br /> try<br /> {<br /> String pathName = currentRoot + File.separatorChar + className. replace(’.’, File.separatorChar) + ".class";<br /> FileInputStream inFile = new FileInputStream(pathName); <br /> byte[] classBytes = new byte[inFile.available()];<br /> inFile.read(classBytes); <br /> return classBytes; <br /> }<br /> catch (java.io.IOException ioEx)<br /> {<br /> return null; <br /> }<br /> }<br /> <br /> public Class findClass(String name)throws ClassNotFoundException<br /> {<br /> byte[] classBytes = findClassBytes(name); <br /> if (classBytes==null)<br /> {<br /> throw new ClassNotFoundException();<br /> } else{<br /> return defineClass(name, classBytes, 0, classBytes.length);<br /> }<br /> }<br /> <br /> public Class findClass(String name, byte[] classBytes)throws ClassNotFoundException<br /> {<br /> if (classBytes==null)<br /> {<br /> throw new ClassNotFoundException( "(classBytes==null)"); <br /> } else{<br /> return defineClass(name, classBytes, 0, classBytes.length);<br /> }<br /> }<br /> <br /> public void execute(String codeName, byte[] code)<br /> {<br /> Class klass = null;<br /> try<br /> {<br /> klass = findClass(codeName, code);<br /> TaskIntf task = (TaskIntf) klass.newInstance();<br /> task.execute();<br /> } catch(Exception exception){<br /> exception.printStackTrace();<br /> }<br /> }</td> </tr> </tbody> </table> <br /> q个cM客户端把client.TaskImpl(v1)转换成字节数l,之后此字节数l被发送到RMI服务端。在服务端,一个同Lcȝ来把字节数组的内容{换回代码。客L代码如下Q?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>public class Client<br /> {<br /> public static void main (String[] args)<br /> {<br /> try{ byte[] code = getClassDefinition ("client.TaskImpl"); <br /> serverIntf.execute("client.TaskImpl", code);<br /> }<br /> catch(RemoteException remoteException)<br /> {<br /> remoteException.printStackTrace();<br /> }<br /> }<br /> <br /> private static byte[] getClassDefinition (String codeName)<br /> {<br /> String userDir = System.getProperties(). getProperty("BytePath");<br /> FileSystemClassLoader fscl1 = null; <br /> try<br /> {<br /> fscl1 = new FileSystemClassLoader (userDir);<br /> }<br /> catch(FileNotFoundException fileNotFoundException)<br /> {<br /> fileNotFoundException.printStackTrace(); <br /> }<br /> return fscl1.findClassBytes(codeName);<br /> }<br /> }</td> </tr> </tbody> </table> <br /> 在执行引擎中Q从客户端收到的代码被送到定制的类加蝲器中。定制的cd载器把其从字节数l定义成c,实例化ƈ执行。需要指出的是,Ҏ(gu)一个客戯求,我们用类FileSystemClassLoader的不同实例来定义客户端提交的client.TaskImpl。而且Qclient.TaskImplq不在服务端的类路径中。这也就意味着当我们在FileSystemClassLoader调用findClass()Ҏ(gu)ӞfindClass()调用内在的defineClass()Ҏ(gu)。类client.TaskImpl被特定的cd载器实例所定义。因此,当FileSystemClassLoader的一个新的实例被使用Q类又被重新定义为字节数l。因此,Ҏ(gu)个客Lhcclient.TaskImpl被多ơ定义,我们可以在相同执行引擎JVM中执行不同的client.TaskImpl的代码?br /> <br /> <table width="90%" align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc"> <tbody> <tr> <td>public void execute(String codeName, byte[] code)throws RemoteException<br /> {<br /> FileSystemClassLoader fileSystemClassLoader = null;<br /> try<br /> {<br /> fileSystemClassLoader = new FileSystemClassLoader();<br /> fileSystemClassLoader.execute(codeName, code);<br /> }<br /> catch(Exception exception)<br /> {<br /> throw new RemoteException(exception.getMessage()); <br /> }<br /> }</td> </tr> </tbody> </table> <br /> CZ在differentversionspush文g夹下。服务端和客L的控制台界面分别如图10Q?1Q?2所C:<br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/xt7zup25eyzk.JPG" width="428" height="251" /><br /> ?0. 定制cd载器执行引擎</div> </td> </tr> </tbody> </table> <br /> ?0昄的是定制的类加蝲器控制台。我们可以看到client.TaskImpl的代码被多次加蝲。实际上针对每一个客LQ类都被加蝲q初始化?br /> <br /> <table width="90%" align="center" border="0"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/qjuwm77a3l70.JPG" width="429" height="183" /><br /> ?1. 定制cd载器Q客L1</div> </td> </tr> </tbody> </table> <br /> ?1中,含有client.TaskImpl.class.getClassLoader(v1)的日志记录的cTaskImpl的代码被客户端的VM加蝲Q然后送到服务端。图12 另一个客L把包含有client.TaskImpl.class.getClassLoader(v1)的类代码加蝲q往服务端?br /> <br /> <table width="90%" align="center"> <tbody> <tr> <td> <div align="center"><img alt="" src="http://dev.yesky.com/imagelist/05/10/1dpn2sj8pu1l.JPG" width="427" height="181" /><br /> ?2. 定制cd载器Q客L1</div> </td> </tr> </tbody> </table> <br /> q段代码演示了我们如何利用不同的cd载器实例来在同一个VM上执行不同版本的代码?br /> <br /> <strong>J2EE的类加蝲?/strong><br /> <br /> J2EE的服务器們֐于以一定间隔频率,丢弃原有的类q新蝲入新的类。在某些情况下会q样执行Q而有些情况则不。同P对于一个web服务器如果要丢弃一个servlet实例Q可能是服务器管理员的手动操作,也可能是此实例长旉未相应。当一个JSP面被首ơ请求,容器会把此JSP面译成一个具有特定Ş式的servlet代码。一旦servlet代码被创建,容器׃把这个servlet译成class文g{待被用。对于提交给容器的每ơ请求,容器都会首先查这个JSP文g是否刚被修改q。是的话重新翻译此文gQ这可以保每次的请求都是及时更新的。企业的部|方案以.ear, .war, .rar{Ş式的文gQ同样需要重复加载,可能是随意的也可能是依照某种配置Ҏ(gu)定期执行。对所有的q些情况——类的加载、卸载、重新加?#8230;…全部都是建立在我们控制应用服务器的类加蝲机制的基上的。实现这些需要扩展的cd载器Q它可以执行由其自n所定义的类。Brett Peterson已经在他的文?Understanding J2EE Application Server Class Loading Architecturesl出了J2EE应用服务器的cd载方案的详细说明Q详见网站TheServerSide.com?br /> <br /> <strong>l束?/strong><br /> <br /> 本文探讨了类载入到虚拟机是如何进行唯一标识的,以及cd果存在同Lcd和包名时所产生的问题。因为没有一个直接可用的cȝ本管理机Ӟ所以如果我们要按自q意愿来加载类Ӟ需要自p制类加蝲器来扩展其行为。我们可以利用许多J2EE服务器所提供?#8220;热部|?#8221;功能来重新加载一个新版本的类Q而不改动服务器的VM。即使不涉及应用服务器,我们也可以利用定制类加蝲器来控制java应用E序载入cL的具体行为。Ted Neward的书Server-Based Java Programming中详l阐qjava的类加蝲QJ2EE的API以及使用他们的最佳途径?br /> </p> <img src ="http://www.aygfsteel.com/conans/aggbug/251110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/conans/" target="_blank">CONAN</a> 2009-01-13 13:00 <a href="http://www.aygfsteel.com/conans/articles/251110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ThreadLocal 的?/title><link>http://www.aygfsteel.com/conans/articles/251108.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Tue, 13 Jan 2009 04:58:00 GMT</pubDate><guid>http://www.aygfsteel.com/conans/articles/251108.html</guid><description><![CDATA[<p>EasyDBO的数据库q接部分Qؓ了给每个q接提供上下文,E序用到了一个关键的cZ—ThreadLocal?/p> <p><strong>什么是ThreadLocalQ?/strong></p> <p>֐思义它是local variableQ线E局部变量)。它的功用非常简单,是为每一个用该变量的线E都提供一个变量值的副本Q是每一个线E都可以独立地改变自q副本Q而不会和其它U程的副本冲H。从U程的角度看Q就好像每一个线E都完全拥有该变量?/p> <p>使用场景</p> <ol> <li><strong>To keep state with a thread (user-id, transaction-id, logging-id)</strong> </li> <li><strong>To cache objects which you need frequently</strong></li> </ol> <p><strong>ThreadLocalc?/strong></p> <p>它主要由四个Ҏ(gu)l成initialValue()Qget()Qset(T)Qremove()Q其中值得注意的是initialValue()Q该Ҏ(gu)是一个protected的方法,昄是ؓ了子c重写而特意实现的。该Ҏ(gu)q回当前U程在该U程局部变量的初始|q个Ҏ(gu)是一个gq调用方法,在一个线E第1ơ调用get()或者set(Object)时才执行Qƈ且仅执行1ơ。ThreadLocal中的实实现直接q回一个nullQ?/p> <p>ThreadLocal的原?/p> <p>ThreadLocal是如何做Cؓ每一个线E维护变量的副本的呢Q其实实现的思\很简单,在ThreadLocalcM有一个MapQ用于存储每一个线E的变量的副本。比如下面的CZ实现Q?/p> <p>public class ThreadLocal<br /> {<br /> private Map values = Collections.synchronizedMap(new HashMap());<br /> public Object get()<br /> {<br /> Thread curThread = Thread.currentThread(); <br /> Object o = values.get(curThread); <br /> if (o == null && !values.containsKey(curThread))<br /> {<br /> o = initialValue();<br /> values.put(curThread, o); <br /> }<br /> return o; <br /> }</p> <p> public void set(Object newValue)<br /> {<br /> values.put(Thread.currentThread(), newValue);<br /> }</p> <p> public Object initialValue()<br /> {<br /> return null; <br /> }<br /> } </p> <p><strong>ThreadLocal 的?/strong></p> <p>使用Ҏ(gu)一Q?/p> <p>Hibernate的文档时看到了关于ThreadLocal理多线E访问的部分。具体代码如?<br /> <br /> 1.  public static final ThreadLocal session = new ThreadLocal(); <br /> 2.  public static Session currentSession() { <br /> 3.      Session s = (Session)session.get(); <br /> 4.      //open a new session,if this session has none <br /> 5.   if(s == null){ <br /> 6.      s = sessionFactory.openSession(); <br /> 7.      session.set(s); <br /> 8.   } <br />       return s; <br /> 9. } <br /> <br /> 我们逐行分析 <br /> 1? 初始化一个ThreadLocal对象QThreadLocal有三个成员方?get()、set()、initialvalue()? <br />     如果不初始化initialvalueQ则initialvalueq回null? <br /> 3。session的getҎ(gu)当前U程q回其对应的U程内部变量Q也是我们需要的net.sf.hibernate.SessionQ相当于对应每个数据库连接).多线E情况下׃n数据库链接是不安全的。ThreadLocal保证了每个线E都有自qsQ数据库q接Q? <br /> 5。如果是该线E初ơ访问,自然QsQ数据库q接Q会是nullQ接着创徏一个SessionQ具体就是行6?<br /> 6。创Z个数据库q接实例 s <br /> 7。保存该数据库连接s到ThreadLocal中? <br /> 8。如果当前线E已l访问过数据库了Q则从session中get()可以获取该U程上次获取q的q接实例?</p> <p>使用Ҏ(gu)?/p> <p>当要l线E初始化一个特D值时Q需要自己实现ThreadLocal的子cdƈ重写该方法,通常使用一个内部匿名类对ThreadLocalq行子类化,EasyDBO中创建jdbcq接上下文就是这样做的:</p> <p>public class JDBCContext{<br />  private static Logger logger = Logger.getLogger(JDBCContext.class);<br />  private DataSource ds;<br />  protected Connection connection;<br />  private boolean isValid = true;<br />  private static ThreadLocal jdbcContext;<br />  <br />  private JDBCContext(DataSource ds){<br />   this.ds = ds;<br />   createConnection();  <br />  }<br />  public static JDBCContext getJdbcContext(javax.sql.DataSource ds)<br />  {  <br />   if(jdbcContext==null)jdbcContext=new JDBCContextThreadLocal(ds);<br />   JDBCContext context = (JDBCContext) jdbcContext.get();<br />   if (context == null) {<br />    context = new JDBCContext(ds);<br />   }<br />   return context;<br />  }</p> <p> private static class JDBCContextThreadLocal extends ThreadLocal {<br />   public javax.sql.DataSource ds;<br />   public JDBCContextThreadLocal(javax.sql.DataSource ds)<br />   {<br />    this.ds=ds;<br />   }<br />   protected synchronized Object initialValue() {<br />    return new JDBCContext(ds);<br />   }<br />  }<br /> }</p> <p>使用单例模式Q不同的U程调用getJdbcContext()获得自己的jdbcContextQ都是通过JDBCContextThreadLocal 内置子类来获得JDBCContext对象的线E局部变量,q个变量是该U程所独有的?/p> <img src ="http://www.aygfsteel.com/conans/aggbug/251108.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/conans/" target="_blank">CONAN</a> 2009-01-13 12:58 <a href="http://www.aygfsteel.com/conans/articles/251108.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Classloader 基础http://www.aygfsteel.com/conans/articles/251107.htmlCONANCONANTue, 13 Jan 2009 04:56:00 GMThttp://www.aygfsteel.com/conans/articles/251107.html什么是ClassLoader

ClassLoader是一个抽象类Q我们用它的实例对象来装载类Q?font face="宋体">它负责将 Java 字节码装载到 JVM 中, q其成?/span> JVM 一部分?/span> JVM 的类动态装载技术能够在q行时刻动态地加蝲或者替换系l的某些功能模块Q?/span>而不影响pȝ其他功能模块的正常运行?/span>一般是通过cdd一个class文g来装载这个类Q(其它加蝲形式暂时没有研究q)?/p>

ClassLoader装蝲q程

c装载就是寻找一个类或是一个接口的字节码文件ƈ通过解析该字节码来构造代表这个类或是q个接口?/span> class 对象的过E。在 Java 中,c装载器把一个类装入 Java 虚拟ZQ要l过三个步骤来完成:装蝲、链接和初始化,其中链接又可以分成校验、准备和解析三步Q除了解析外Q其它步骤是严格按照序完成的,各个步骤的主要工作如下:

1.        装蝲Q查扑֒导入cL接口的字节码Q?/span>

2.        链接Q执行下面的校验、准备和解析步骤Q其中解析步骤是可以选择的;

l        校验Q检查导入类或接口的二进制数据的正确性;

l        准备Q给cȝ静态变量分配ƈ初始化存储空_

l        解析Q将W号引用转成直接引用Q?/span>

3.        初始化:Ȁzȝ的静态变量的初始?/span> Java 代码和静?/span> Java 代码块?/span>

装蝲的实?/font>

JVM 中类的装载是?/span> ClassLoader 和它的子cL实现的?/span> Java ClassLoader 是一个重要的 Java q行时系l组Ӟ它负责在q行时查扑֒装入 Java 字节码?/span>

?/span> Java 中, ClassLoader 是一个抽象类Q它在包 java.lang 中。可以这栯Q只要了解了 ClassLoader 中的一些重要的Ҏ(gu)Q再l合上面所介绍?/span> JVM 中类装蝲的具体的q程Q对动态装载类q项技术就有了一个比较大概的掌握Q这些重要的Ҏ(gu)包括以下几个Q?/span>

1.        loadCass Ҏ(gu)Q?/span> loadClass(String name ,boolean resolve) 其中 name 参数指定?/span> JVM 需要的cȝ名称 , 该名UCcȝ全限定名表示Q如 Java.lang.Object Q?/span> resolve 参数告诉Ҏ(gu)是否需要解析类Q在初始化类之前Q应考虑c解析,q不是所有的c都需要解析,如果 JVM 只需要知道该cL否存在或扑և该类的超c,那么׃需要解析。这个方法是 ClassLoader 的入口点?/span>

2.        defineClass Ҏ(gu)   q个Ҏ(gu)接受cL件的字节数组q把它{换成 Class 对象。字节数l可以是从本地文件系l或|络装入的数据。它把字节码分析成运行时数据l构、校验有效性等{?/span>

3.        findSystemClass Ҏ(gu)   findSystemClass Ҏ(gu)从本地文件系l装?/span> Java 字节码。它在本地文件系l中LcLӞ如果存在Q就使用 defineClass 字节数l{换成 Class 对象。当q行 Java 应用E序?/span> , q是 JVM 正常装入cȝ~省机制?/span>

4.        resolveClass Ҏ(gu) resolveClass(Class c) Ҏ(gu)解析装入的类Q如果该cdl被解析q那么将不做处理。当调用 loadClass Ҏ(gu)?/span> , 通过它的 resolve 参数军_是否要进行解析?/span>

5.        findLoadedClass Ҏ(gu)   当调?/span> loadClass Ҏ(gu)装入cL , 调用 findLoadedClass Ҏ(gu)来查?/span> ClassLoader 是否已装入这个类 , 如果已装?/span> , 那么q回 Class 对象 , 否则q回 NULL 。如果强行装载已存在的类 , 会抛出链接错误?/span>

java.lang.Classc?/font>

某个cȝ所有实例内部都有一个引用,指向该类对应的Class的实例的位置Q每个javacd应的Class实例可以当作是类在内存中的代理h。所以当要获得类的信?如有哪些cd?有哪些方?Ӟ都可以让cd应的Class的实例代?java的Reflection机制大量的使用q种Ҏ(gu)来实现。但是ClasscL法手工实例化Q当载入Lcȝ时候自动创Z个该cd应的Class的实例。每个javac都是由某个classLoader(ClassLoader的实?来蝲入的Q因此Classcd的实例中都会他的ClassLoader的实例的引用。可以通过getClass.getClassLoader()得到CLassLoader的实例?/p>

java动态蝲入class的两U方?
1)implicit隐式,卛_用实例化才蝲入的Ҏ(gu)来动态蝲入class
2)explicit昑ּ方式,又分两种方式:
a)java.lang.Class的forName()Ҏ(gu)
b)java.lang.ClassLoader的loadClass()Ҏ(gu)

各种javacȝ哪些classLoader加蝲?

1)javacd以通过实例.getClass.getClassLoader()得到
2)接口由AppClassLoader(SystemClassLoader)载入 QSystemClassLoaderQ可以由ClassLoader.getSystemClassLoader()获得实例
3)ClassLoadercȝbootstrap loader载入

ClassLoader hierachy:

1)jvm初始化生bootstrap loader。ƈ讑֮它的父ClassLoader为null

2)bootstrap loader建立AppClassLoader,载入 q行java.exe? ?cp?classpath中的c(每个q行中的U程都有一个成员contextClassLoaderQ用来在q行时动态地载入其它cȝl默认的contextClassLoader是systemClassLoaderQ?/p>

Java c装载的代理l构

?/span> (Bootstrap) 装蝲器:该装载器没有父装载器Q它?/span> JVM 实现的一部分Q从 sun.boot.class.path 装蝲q行时库的核心代码?/span>

扩展 (Extension) 装蝲器:l承的父装蝲器ؓ根装载器Q不像根装蝲器可能与q行时的操作pȝ有关Q这个类装蝲器是用纯 Java 代码实现的,它从 java.ext.dirs ( 扩展目录 ) 中装载代码?/span>

(System or Application) 装蝲器:装蝲器ؓ扩展装蝲器,我们都知道在安装 JDK 的时候要讄环境变量 (CLASSPATH ) Q这个类装蝲器就是从 java.class.path(CLASSPATH 环境变量 ) 中装载代码的Q它也是用纯 Java 代码实现的,同时q是用户自定义类装蝲器的~省父装载器?/span>

应用程?/span> (Applet) 装蝲器:父装载器为系l装载器Q它从用h定的|络上的特定目录装蝲应用程序代码?/span>

java中的代理l构是自上而下查找cȝQ这与很多web装蝲器不同?/p>

tomcat中的实现的子ClassLoader的结?/font>

Tomcat Server在启动的时候将构造一个ClassLoader树,以保证模块的cd是私有的
Tomcat Server的ClassLoaderl构如下Q?


       ---------------------------+
       |         Bootstrap           |
       |             |               |
       |          System             |
       |             |               |
       |          Common             |
       |         /      \            |
       |     Catalina  Shared        |
       |               /    \        |
       |          WebApp1  WebApp2   |
       ---------------------------+

其中Q?
- Bootstrap - 载入JVM自带的类?JAVA_HOME/jre/lib/ext/*.jar
- System - 载入$CLASSPATH/*.class
- Common - 载入$CATALINA_HOME/common/...Q它们对TOMCAT和所有的WEB APP都可?
- Catalina - 载入$CATALINA_HOME/server/...Q它们仅对TOMCAT可见Q对所有的WEB APP都不可见
- Shared - 载入$CATALINA_HOME/shared/...Q它们仅Ҏ(gu)有WEB APP可见Q对TOMCAT不可见(也不必见Q?
- WebApp? - 载入ContextBase?/WEB-INF/...Q它们仅对该WEB APP可见

ClassLoader被组l成树ŞQ一般的工作原理是:
1) U程需要用到某个类Q于是contextClassLoader被请求来载入该类
2) contextClassLoaderh它的父ClassLoader来完成该载入h
3) 如果父ClassLoader无法载入c,则contextClassLoader试图自己来蝲?


注意QWebApp?ClassLoader的工作原理和上述有少怸同:
它先试图自己载入c(在ContextBase?/WEB-INF/...中蝲入类Q,如果无法载入Q再h父ClassLoader完成



CONAN 2009-01-13 12:56 发表评论
]]>
JAVA操作大型文本文ghttp://www.aygfsteel.com/conans/articles/213757.htmlCONANCONANWed, 09 Jul 2008 11:14:00 GMThttp://www.aygfsteel.com/conans/articles/213757.html阅读全文

CONAN 2008-07-09 19:14 发表评论
]]>
一ơJava垃圾攉调优实战http://www.aygfsteel.com/conans/articles/213752.htmlCONANCONANWed, 09 Jul 2008 11:07:00 GMThttp://www.aygfsteel.com/conans/articles/213752.html1 资料

2 GC日志打印

  GC调优是个很实验很伽利略的zdQGC日志是先决的数据参考和最l验证:

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps(GC发生的时? -XX:+PrintGCApplicationStoppedTime(GC消耗了多少旉) -XX:+PrintGCApplicationConcurrentTime(GC之间q行了多时?

3 攉器选择

CMS攉器:暂停旉优先

   配置参数Q?XX:+UseConcMarkSweepGC
   已默认无需配置的参敎ͼ-XX:+UseParNewGC(Parallel攉新生? -XX:+CMSPermGenSweepingEnabled(CMS攉持久? -XX:UseCMSCompactAtFullCollection(FullGC时压~年老代)

   初始效果Q?G堆内存的新生代约60mQminor gcU?-20毫秒Qfull gcU?30毫秒?/p>

4 调优实战

      Parallel攉高达1U的暂停旉基本不可忍受Q所以选择CMS攉器?/p>

      不知Z在被压的Mule 2.0应用里,每秒都有大约400M的v量短命对象生:

  1. 因ؓ默认60M的新生代太小了,频繁发生minor gcQ大U?.2U就q行一ơ?
  2. 因ؓCMS攉器中MaxTenuringThreshold(生代对象撑过q多次minor gc才进入年老代的设|?默认0Q存zȝ临时对象不经qSurvivor区直接进入年老代Q不久就占满q老代发生full gc?

     对这两个参数q行调优Q既要改善上面两U情况,又要避免新生代过大,复制ơ数q多造成minor gc的暂停时间过ѝ?/p>

  1. 使用-Xmn调到1/3 d存。比较后讄-Xmn500mQ新生代实际U?60m?-XX:NewRatio参数无效)?
  2. d-XX:+PrintTenuringDistribution 参数观察各个Age的对象d,观察后设|?XX:MaxTenuringThreshold=5?

      优化后,大约1.1U才发生一ơminor GCQ同时年老代的增镉K度大大减缓Q预计几个小时才会发生一ơGCQ而minor gc速度依然保持?5-20ms之间?/p>

      参数定稿Q?/p>

 -Xms1024m -Xmx1024m -Xmn500m -XX:+UseConcMarkSweepGC   -XX:MaxTenuringThreshold=5  -XX:+ExplicitGCInvokesConcurrent

      最后服务处理速度?180 tps 上升?380 tpsQ调整两个参数提?7%的性能q是W很划算的买卖?/p>

CONAN 2008-07-09 19:07 发表评论
]]>
Effective JavaMW记 http://www.aygfsteel.com/conans/articles/212422.htmlCONANCONANThu, 03 Jul 2008 12:36:00 GMThttp://www.aygfsteel.com/conans/articles/212422.html阅读全文

CONAN 2008-07-03 20:36 发表评论
]]>
Java中类型与cȝ区别 http://www.aygfsteel.com/conans/articles/212197.htmlCONANCONANWed, 02 Jul 2008 12:35:00 GMThttp://www.aygfsteel.com/conans/articles/212197.html
(1)基本数据cdQ包括byte,short,int,long,float,double,char,boolean{八U类型,在Java中,基本数据cd的数据都是有W号敎ͼ没有无符L型数据,q是不同于C++的一个地斏V?br />
(2)复合数据cdQ包括数l和cMU。其中类包括Integer,BigInteger{,参见Javacdjava.lang.Number的所有子c;数组是数字与保存的数据对象联pv来的容器Q可以是多维的,可以保存基本数据cd的数据,也可以保存类cd的数据?br />
L下例Q?br /> (1) int i=10;
(2) Integer i = new Integer(10);

在上例中Q变量i的值都是整型?0Q但是在W一个方法中Q变量i是一个intcd变量Q属于一个基本数据类型;在第二个Ҏ(gu)中,变量i是一个类的实例对象,属于一个复合类型Integercȝ一个实例变量,更确切地_i是一个指向Integercd例对象的引用Q在“=”双是构造一个新分配的Integercd的变量,该对象表C整型?0Q?#8220;=”左边是定义一个指向Integercd对象的引?对象句柄)Q得该对象引用指向新分配的对象?br />
结Q类是一U特D的数据cdQ这是cd与类的区?)

CONAN 2008-07-02 20:35 发表评论
]]>
Java标准cd提供的容器ȝ http://www.aygfsteel.com/conans/articles/212196.htmlCONANCONANWed, 02 Jul 2008 12:35:00 GMThttp://www.aygfsteel.com/conans/articles/212196.html在Java中,容器主要包括Q数l?Array)、集?Collection)和映?Map)三种?br />
(1)数组ArrayQ将数字与元素联pv来,其中的元素都h相同的数据类型,只能通过下标来访问其元素Q数l可以是一l的Q也可以是多l的Q数l一旦生成,其容量就不能改变。数l是一U复合数据类型,在Java中,除了可以?#8220;int[] array;”来声明和表示一个数l,q可以用ArraycL表示一个数l,同样圎ͼJDKcdq提供了Arrayscȝ操作数组Q该cd义了Ҏ(gu)l进行操作的各种Ҏ(gu)(赋倹{排序、搜索、比较、查扑օ素等)?br />
(2)集合CollectionQ是一个接口类Q包括List、Set、Queue{子接口Q其具体的实现类可以用来保存多个元素。这里只讨论常用的子接口List和Set的常用实现类。常用的List实现cLArrayList、Vector和LinkedList{,常用的Set实现cLHashSet、LinkedHashSet和TreeSet{。需要注意的是,List和Set有着很大的不同,主要包括是否允许元素重复和是否维护元素的ơ序?br />
(3)映射MapQ保存相兌的键值对。其具体的实现类可以键映射到|Ҏ(gu)键得到|因此Q一个映不能包含重复的键,但是允许有重复的|每个键最多只能映到一个倹{?常见的Map实现cLHashMap、Hashtable、LinkedHashMap和TreeMap{?br />
Z讨论的方便,下面以ArrayQList、Set、Map为分cL讨论q几U容器的使用特点?br />
(1)ArrayQ?br />
    数组的用很直接Q主要是Ҏ(gu)下表来获取其元素。其特点是一旦生成,其容量不能改变,q且每个元素之间不允许有“I隙”。其使用实例可以参考电(sh)子工业出版社“宝典”pd之《Java JDK 实例宝典?夏先?~著)Q个人感觉这本书写得不错Q给Z许多JDKcd的具体用实例,代码的注释也比较详细Q很适合初学者入门学习用,如果看Java Doc q是有不明白的地方,也可以参考此?)

(2)ListQ可用来存放多个元素Q能够自动扩充容量,能够l护元素的次序,q且允许元素重复?br />
    (2.1)ArrayListc:最常用的List实现c,内部是通过数组实现的,它允许对元素q行快速的随机讉KQ但是要从ArrayList的中间位|插入或者删?nbsp;   元素Ӟ需要对数组q行复制、移动,代h(hun)比较高,因此QArrayList适合随机查找和遍历,不适合插入和删除?br />
    (2.2)Vectorc:同ArrayList一P其内部也是通过数组实现的,不同的是QVector支持U程的同步,能够避免多线E同时写而引L不一_但是实现U程的同步需要很高的代h(hun)Q因此访问Vector比ArrayList慢?br />
    (2.3)LinkedListc:见其名,该类与链表肯定有关系:)该类的内部是通过链表来实现的Q很适合数据的动态插入和删除Q但是随卌问和遍历的速度比较慢。此外,该类q提供了List接口中没有定义的Ҏ(gu)Q专门用于操作表头和表尾元素Q可以当作堆栈、队列和双向队列使用?/span>

(3)SetQ可用来存放多个元素Q但是不允许元素重复(即不保存重复元素)Q也不能够维护元素的ơ序。很直观Q联想一下数学中的集合的概念很好理解了。此外,需要注意的是,加入Set的元素必d义equals()Ҏ(gu)以确保对象的唯一性,如String对象?br />
    (3.1) HashSetc:采用散列函数对元素进行排序,是专门ؓ快速查询而设计的存入HashSet的对象必d义hashCode()Ҏ(gu)?br />
    (3.2)TreeSetc:采用U黑树的数据l构q行排序元素Q用它可以从Set中提取有序的序列?br />
    (3.3) LinkedHashSetc:内部使用散列以加快查询速度Q同时用链表维护元素的插入ơ序Q在使用q代器遍历时Q会按插入次序显C结果?br />

(4)MapQ可以用来存攄兌的键值对Q根据键得到倹{常见的Map实现cLHashMap、Hashtable、LinkedHashMap和TreeMap?/p>

    (4.1)HashMapc:一个最常用的MapQ它Ҏ(gu)键的hashCode值存储数据,Ҏ(gu)键可以直接获取它的|h很快的访问速度Q但不支持线E同步。HashMap最多允怸条记录的键ؓnullQ但是允许多条记录的gؓnull?br />     
    (4.2)Hashtablec:与HashMapcMQ但是它不允许记录的键或者gؓnullQ支持线E同步,因而Hashtable在写入数据时会很慢?br />
    (4.3)LinkedHashMapc:保存了记录的插入序Q在用Iterator遍历它时Q先得到的记录肯定时先插入的Q在遍历的时候比HashMap慢?br />
    (4.4)TreeMapc:能够把它保存的记录根据键排序Q默认ؓ升序排列。当用Iterator遍历它时Q得到的记录是排q序的记录?/p>

CONAN 2008-07-02 20:35 发表评论
]]>
常用java date Ҏ(gu)集合http://www.aygfsteel.com/conans/articles/211309.htmlCONANCONANSat, 28 Jun 2008 06:48:00 GMThttp://www.aygfsteel.com/conans/articles/211309.html
Calendar time=Calendar.getInstance();
time.clear();
time.set(Calendar.YEAR,year); //year ?int
time.set(Calendar.MONTH,i-1);//注意,Calendar对象默认一月ؓ0          
int day=time.getActualMaximum(Calendar.DAY_OF_MONTH);//本月份的天数
注:在用setҎ(gu)之前Q必dclear一下,否则很多信息会承自pȝ当前旉

2.Calendar和Date的{?br />
(1) Calendar转化为Date
Calendar cal=Calendar.getInstance();
Date date=cal.getTime();

(2) Date转化为Calendar
Date date=new Date();
Calendar cal=Calendar.getInstance();
cal.setTime(date);

3.格式化输出日期时?Q这个用的比较多Q?br />
Date date=new Date();
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String time=df.format(date);
System.out.println(time);

4.计算一q中的第几星?br />
(1)计算某一天是一q中的第几星?br /> Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
int weekno=cal.get(Calendar.WEEK_OF_YEAR);

(2)计算一q中的第几星期是几号
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(df.format(cal.getTime()));
输出:
2006-01-02

5.add()和roll()的用?不太常用)

(1)add()Ҏ(gu)
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
cal.add(Calendar.DATE, -4);
Date date=cal.getTime();
System.out.println(df.format(date));
cal.add(Calendar.DATE, 4);
date=cal.getTime();
System.out.println(df.format(date));
输出Q?br />     2006-08-30
    2006-09-03
(2)rollҎ(gu)
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8);
cal.set(Calendar.DAY_OF_MONTH, 3);
cal.roll(Calendar.DATE, -4);
date=cal.getTime();
System.out.println(df.format(date));
cal.roll(Calendar.DATE, 4);
date=cal.getTime();
System.out.println(df.format(date));
输出Q?br />     2006-09-29
    2006-09-03
可见Qroll()Ҏ(gu)在本月内循环Q一般用add()Ҏ(gu)Q?br />
6.计算两个L旉中间的间隔天敎ͼq个比较常用Q?br /> (1)传进Calendar对象
    public int getIntervalDays(Calendar startday,Calendar endday)...{      
        if(startday.after(endday))...{
            Calendar cal=startday;
            startday=endday;
            endday=cal;
        }   
        long sl=startday.getTimeInMillis();
        long el=endday.getTimeInMillis();
      
        long ei=el-sl;          
        return (int)(ei/(1000*60*60*24));
    }
(2)传进Date对象

    public int getIntervalDays(Date startday,Date endday)...{       
        if(startday.after(endday))...{
            Date cal=startday;
            startday=endday;
            endday=cal;
        }       
        long sl=startday.getTime();
        long el=endday.getTime();      
        long ei=el-sl;          
        return (int)(ei/(1000*60*60*24));
    }
(3)改进_计算盔R天数的方?br />     public int getDaysBetween (Calendar d1, Calendar d2) ...{
        if (d1.after(d2)) ...{
            java.util.Calendar swap = d1;
            d1 = d2;
            d2 = swap;
        }
        int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
        int y2 = d2.get(Calendar.YEAR);
        if (d1.get(Calendar.YEAR) != y2) ...{
            d1 = (Calendar) d1.clone();
            do ...{
                days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);//得到当年的实际天?br />                 d1.add(Calendar.YEAR, 1);
            } while (d1.get(Calendar.YEAR) != y2);
        }
        return days;
    }
注意Q通过上面的方法可以衍生出求Q何时_如要查出邮箱三周之内收到的邮Ӟ得到当前pȝ旉Q再得到三周前时_用收件的旉d?最好装化成 longL?br /> 如:1q前日期Q注意毫U的转换Q?br />    java.util.Date myDate=new java.util.Date();
   long myTime=(myDate.getTime()/1000)-60*60*24*365;
   myDate.setTime(myTime*1000);
   String mDate=formatter.format(myDate);

7. String ?Date QLong 之间怺转换 Q最常用Q?br />
字符串{化成旉cdQ字W串可以是Q意类型,只要和SimpleDateFormat中的格式一致即可)
通常我们取时间跨度的时候,会substring出具体时_QlongQ比?br />
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("M/dd/yyyy hh:mm:ss a",java.util.Locale.US);
java.util.Date d = sdf.parse("5/13/2003 10:31:37 AM");
long dvalue=d.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String mDateTime1=formatter.format(d);

8. 通过旉求时?br />
q月周求日期
SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM F E");
java.util.Date date2= formatter2.parse("2003-05 5 星期?);
SimpleDateFormat formatter3 = new SimpleDateFormat("yyyy-MM-dd");
String mydate2=formatter3.format(date2);

求是星期?br /> mydate= myFormatter.parse("2001-1-1");
SimpleDateFormat formatter4 = new SimpleDateFormat("E");
String mydate3=formatter4.format(mydate);

9. java ?具体的数据库l合

在开发web应用中,针对不同的数据库日期cdQ我们需要在我们的程序中Ҏ(gu)期类型做各种不同的{换。若对应数据库数据是oracle的DatecdQ即只需要年月日的,可以选择使用java.sql.DatecdQ若对应的是MSsqlserver 数据库的DateTimecdQ即需要年月日时分U的Q选择java.sql.Timestampcd
你可以用dateFormat定义旉日期的格式,转一个字W串卛_

class Datetest{
*method 字W串cd的日期{换ؓ一个timestampQ时间戳记java.sql.TimestampQ?br /> *@param dateString 需要{换ؓtimestamp的字W串
*@return dataTime timestamp

public final static java.sql.Timestamp string2Time(String dateString)
throws java.text.ParseException {
DateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);//讑֮格式
//dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.ENGLISH);
dateFormat.setLenient(false);
java.util.Date timeDate = dateFormat.parse(dateString);//utilcd
java.sql.Timestamp dateTime = new java.sql.Timestamp(timeDate.getTime());//Timestampcd,timeDate.getTime()q回一个long?br /> return dateTime;
}

*method 字W串cd的日期{换ؓ一个DateQjava.sql.DateQ?br /> *@param dateString 需要{换ؓDate的字W串
*@return dataTime Date

public final static java.sql.Date string2Date(String dateString)
throws java.lang.Exception {
DateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
dateFormat.setLenient(false);
java.util.Date timeDate = dateFormat.parse(dateString);//utilcd
java.sql.Date dateTime = new java.sql.Date(timeDate.getTime());//sqlcd
return dateTime;
}

public static void main(String[] args){
Date da = new Date();
注意Q这个地方da.getTime()得到的是一个long型的?br /> System.out.println(da.getTime());

由日期date转换为timestamp

W一U方法:使用new Timestamp(long)
Timestamp t = new Timestamp(new Date().getTime());
System.out.println(t);

W二U方法:使用Timestamp(int year,int month,int date,int hour,int minute,int second,int nano)
Timestamp tt = new Timestamp(Calendar.getInstance().get(
      Calendar.YEAR) - 1900, Calendar.getInstance().get(
      Calendar.MONTH), Calendar.getInstance().get(
      Calendar.DATE), Calendar.getInstance().get(
      Calendar.HOUR), Calendar.getInstance().get(
      Calendar.MINUTE), Calendar.getInstance().get(
      Calendar.SECOND), 0);
System.out.println(tt);

try {
String sToDate = "2005-8-18";//用于转换成java.sql.Date的字W串
      String sToTimestamp = "2005-8-18 14:21:12.123";//用于转换成java.sql.Timestamp的字W串
      Date date1 = string2Date(sToDate);
      Timestamp date2 = string2Time(sToTimestamp);
System.out.println("Date:"+date1.toString());//l果昄
System.out.println("Timestamp:"+date2.toString());//l果昄
}catch(Exception e) {
e.printStackTrace();
}
}



CONAN 2008-06-28 14:48 发表评论
]]>
Java正则表达式详?/title><link>http://www.aygfsteel.com/conans/articles/209562.html</link><dc:creator>CONAN</dc:creator><author>CONAN</author><pubDate>Fri, 20 Jun 2008 14:44:00 GMT</pubDate><guid>http://www.aygfsteel.com/conans/articles/209562.html</guid><description><![CDATA[<table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">如果你曾l用qPerl或Q何其他内建正则表辑ּ支持的语aQ你一定知道用正则表达式处理文本和匚w模式是多么简单。如果你不熟(zhn)这个术语,那么“正则表达?#8221;QRegular ExpressionQ就是一个字W构成的Ԍ它定义了一个用来搜索匹配字W串的模式?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">许多语言Q包括Perl、PHP、Python、JavaScript和JScriptQ都支持用正则表辑ּ处理文本Q一些文本编辑器用正则表辑ּ实现高“搜烦-替换”功能。那么Java又怎样呢?本文写作Ӟ一个包含了用正则表辑ּq行文本处理的Java规范需求(Specification RequestQ已l得到认可,你可以期待在JDK的下一版本中看到它?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">然而,如果现在需要用正则表辑ּQ又该怎么办呢Q你可以从Apache.org下蝲源代码开攄Jakarta-ORO库。本文接下来的内容先要地介绍正则表达式的入门知识Q然后以Jakarta-ORO APIZ介绍如何使用正则表达式?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true"><font size="4" _extended="true">一、正则表辑ּ基础知识</font></strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">我们先从单的开始。假设你要搜索一个包含字W?#8220;cat”的字W串Q搜索用的正则表辑ּ是“cat”。如果搜索对大小写不敏感Q单?#8220;catalog”?#8220;Catherine”?#8220;sophisticated”都可以匹配。也是_</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_a.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">1.1 句点W号</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">假设你在玩英文拼字游戏,惌扑և三个字母的单词,而且q些单词必须?#8220;t”字母开_?#8220;n”字母l束。另外,假设有一本英文字典,你可以用正则表达式搜索它的全部内宏V要构造出q个正则表达式,你可以用一个通配W——句点符?#8220;.”。这P完整的表辑ּ是“t.n”Q它匚w“tan”?#8220;ten”?#8220;tin”?#8220;ton”Q还匚w“t#n”?#8220;tpn”甚至“t n”Q还有其他许多无意义的组合。这是因为句点符号匹配所有字W,包括I格、Tab字符甚至换行W:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_b.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">1.2 Ҏ(gu)L?/strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">Z解决句点W号匚w范围q于q泛q一问题Q你可以在方括号Q?#8220;[]”Q里面指定看来有意义的字W。此Ӟ只有Ҏ(gu)号里面指定的字符才参与匹配。也是_正则表达?#8220;t[aeio]n”只匹?#8220;tan”?#8220;Ten”?#8220;tin”?#8220;ton”。但“Toon”不匹配,因ؓ在方括号之内你只能匹配单个字W:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_c.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">1.3 “?#8221;W号</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">如果除了上面匚w的所有单词之外,你还惌匚w“toon”Q那么,你可以?#8220;|”操作W?#8220;|”操作W的基本意义是“?#8221;q算。要匚w“toon”Q?#8220;t(a|e|i|o|oo)n”正则表达式。这里不能用方扩号Q因为方括号只允许匹配单个字W;q里必须使用圆括?#8220;()”。圆括号q可以用来分l,具体请参见后面介l?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_d.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">1.4 表示匚wơ数的符?/strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">表一昄了表C匹配次数的W号Q这些符L来确定紧靠该W号左边的符号出现的ơ数Q?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4n.jpg" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">假设我们要在文本文g中搜索美国的C会安全L。这个号码的格式?99-99-9999。用来匹配它的正则表辑ּ如图一所C。在正则表达式中Q连字符Q?#8220;-”Q有着Ҏ(gu)的意义,它表CZ个范_比如??。因此,匚wC会安全L中的q字W号Ӟ它的前面要加上一个{义字W?#8220;\”?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4a.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">图一Q匹配所?23-12-1234形式的社会安全号?/p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">假设q行搜烦的时候,你希望连字符号可以出玎ͼ也可以不出现——即Q?99-99-9999?99999999都属于正的格式。这Ӟ你可以在q字W号后面加上“Q?#8221;数量限定W号Q如图二所C:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 90px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4b.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">图二Q匹配所?23-12-1234?23121234形式的社会安全号?/p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">下面我们再来看另外一个例子。美国汽车牌照的一U格式是四个数字加上二个字母。它的正则表辑ּ前面是数字部?#8220;[0-9]{4}”Q再加上字母部分“[A-Z]{2}”。图三显CZ完整的正则表辑ּ?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4c.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">图三Q匹配典型的国汽R牌照LQ如8836KV</p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">1.5 “?#8221;W号</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">“^”W号UCؓ“?#8221;W号。如果用在方括号内,“^”表示不想要匹配的字符。例如,囑֛的正则表辑ּ匚w所有单词,但以“X”字母开头的单词除外?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4d.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">囑֛Q匹配所有单词,?#8220;X”开头的除外</p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">1.6 圆括号和I白W号</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">假设要从格式?#8220;June 26, 1951”的生日日期中提取出月份部分,用来匚w该日期的正则表达式可以如图五所C:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 107px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4e.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">图五Q匹配所有Moth DD,YYYY格式的日?/p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">新出现的“\s”W号是空白符P匚w所有的I白字符Q包括Tab字符。如果字W串正确匚wQ接下来如何提取出月份部分呢Q只需在月份周围加上一个圆括号创徏一个组Q然后用ORO APIQ本文后面详l讨论)提取出它的倹{修改后的正则表辑ּ如图六所C:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 118px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4f.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">囑օQ匹配所有Month DD,YYYY格式的日期,定义月䆾gؓW一个组</p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">1.7 其它W号</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">为简便v见,你可以用一些ؓ常见正则表达式创建的快捷W号。如表二所C:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">表二Q常用符?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4o.jpg" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">例如Q在前面C会安全L的例子中Q所有出?#8220;[0-9]”的地Ҏ(gu)们都可以使用“\d”。修改后的正则表辑ּ如图七所C:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4g.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">图七Q匹配所?23-12-1234格式的社会安全号?/p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true"><font size="4" _extended="true">二、Jakarta-ORO?/font></strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">有许多源代码开攄正则表达式库可供JavaE序员用,而且它们中的许多支持Perl 5兼容的正则表辑ּ语法。我在这里选用的是Jakarta-ORO正则表达式库Q它是最全面的正则表辑ּAPI之一Q而且它与Perl 5正则表达式完全兼宏V另外,它也是优化得最好的API之一?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">Jakarta-ORO库以前叫做OROMatcherQDaniel Savarese大方地把它赠送给了Jakarta Project。你可以按照本文最后参考资源的说明下蝲它?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">我首先将要介l用Jakarta-ORO库时你必d建和讉K的对象,然后介绍如何使用Jakarta-ORO API?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">?PatternCompiler对象</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">首先Q创Z个Perl5Compilercȝ实例Qƈ把它赋值给PatternCompiler接口对象。Perl5Compiler是PatternCompiler接口的一个实玎ͼ允许你把正则表达式编译成用来匚w的Pattern对象?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_e.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">?Pattern对象</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">要把正则表达式编译成Pattern对象Q调用compiler对象的compile()Ҏ(gu)Qƈ在调用参C指定正则表达式。例如,你可以按照下面这U方式编译正则表辑ּ“t[aeio]n”Q?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_f.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">默认情况下,~译器创Z个大写敏感的模式(patternQ。因此,上面代码~译得到的模式只匚w“tin”?#8220;tan”?“ten”?#8220;ton”Q但不匹?#8220;Tin”?#8220;taN”。要创徏一个大写不敏感的模式Q你应该在调用编译器的时候指定一个额外的参数Q?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_g.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">创徏好Pattern对象之后Q你可以通过PatternMatchercȝ该Pattern对象q行模式匚w?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">?PatternMatcher对象</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">PatternMatcher对象Ҏ(gu)Pattern对象和字W串q行匚w查。你要实例化一个Perl5Matchercdƈ把结果赋值给PatternMatcher接口。Perl5MatchercLPatternMatcher接口的一个实玎ͼ它根据Perl 5正则表达式语法进行模式匹配:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_h.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">使用PatternMatcher对象Q你可以用多个方法进行匹配操作,q些Ҏ(gu)的第一个参数都是需要根据正则表辑ּq行匚w的字W串Q?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">· boolean matches(String input, Pattern pattern)Q当输入字符串和正则表达式要_匚w时用。换句话_正则表达式必d整地描述输入字符丌Ӏ?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">· boolean matchesPrefix(String input, Pattern pattern)Q当正则表达式匹配输入字W串起始部分时用?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">· boolean contains(String input, Pattern pattern)Q当正则表达式要匚w输入字符串的一部分时用(卻I它必L一个子Ԍ?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">另外Q在上面三个Ҏ(gu)调用中,你还可以用PatternMatcherInput对象作ؓ参数替代String对象Q这Ӟ你可以从字符串中最后一ơ匹配的位置开始l进行匹配。当字符串可能有多个子串匚wl定的正则表辑ּӞ用PatternMatcherInput对象作ؓ参数很有用了。用PatternMatcherInput对象作ؓ参数替代StringӞ上述三个Ҏ(gu)的语法如下:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">· boolean matches(PatternMatcherInput input, Pattern pattern)</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">· boolean matchesPrefix(PatternMatcherInput input, Pattern pattern)</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">· boolean contains(PatternMatcherInput input, Pattern pattern)</td> </tr> </tbody> </table> <p>  <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true"><font size="4" _extended="true">三、应用实?/font></strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">下面我们来看看Jakarta-ORO库的一些应用实例?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">3.1 日志文g处理</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">dQ分析一个Web服务器日志文Ӟ定每一个用戯在网站上的时间。在典型的BEA WebLogic日志文g中,日志记录的格式如下:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_i.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">分析q个日志记录Q可以发玎ͼ要从q个日志文g提取的内Ҏ(gu)两项QIP地址和页面访问时间。你可以用分l符P圆括P从日志记录提取出IP地址和时间标记?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">首先我们来看看IP地址。IP地址?个字节构成,每一个字节的值在0?55之间Q各个字节通过一个句点分隔。因此,IP地址中的每一个字节有臛_一个、最多三个数字。图八显CZ为IP地址~写的正则表辑ּQ?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 118px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4h.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">囑օQ匹配IP地址</p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">IP地址中的句点字符必须q行转义处理Q前面加?#8220;\”Q,因ؓIP地址中的句点h它本来的含义Q而不是采用正则表辑ּ语法中的Ҏ(gu)含义。句点在正则表达式中的特D含义本文前面已l介l?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">日志记录的时间部分由一Ҏ(gu)括号包围。你可以按照如下思\提取出方括号里面的所有内容:首先搜烦起始Ҏ(gu)号字W(“[”Q,提取出所有不过l束Ҏ(gu)号字W(“]”Q的内容Q向前寻扄x到结束方括号字符。图?ji)显CZq部分的正则表达式?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4i.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">图九(ji)Q匹配至一个字W,直至扑ֈ“]”</p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">现在Q把上述两个正则表达式加上分l符P圆括P后合q成单个表达式,q样可以从日志记录提取出IP地址和时间。注意,Z匚w“- -”Q但不提取它Q,正则表达式中间加入了“\s-\s-\s”。完整的正则表达式如囑֍所C?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 73px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4j.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">囑֍Q匹配IP地址和时间标?/p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">现在正则表达式已l编写完毕,接下来可以编写用正则表辑ּ库的Java代码了?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">Z用Jakarta-ORO库,首先创徏正则表达式字W串和待分析的日志记录字W串Q?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_j.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">q里使用的正则表辑ּ与图十的正则表达式差不多完全相同Q但有一点例外:在Java中,你必d每一个向前的斜杠Q?#8220;\”Q进行{义处理。图十不是Java的表CŞ式,所以我们要在每?#8220;\”前面加上一?#8220;\”以免出现~译错误。遗憄是,转义处理q程很容易出现错误,所以应该小心}慎。你可以首先输入未经转义处理的正则表辑ּQ然后从左到右依ơ把每一?#8220;\”替换?#8220;\\”。如果要复检Q你可以试着把它输出到屏q上?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">初始化字W串之后Q实例化PatternCompiler对象Q用PatternCompiler~译正则表达式创Z个Pattern对象Q?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_k.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">现在Q创建PatternMatcher对象Q调用PatternMatcher接口的contain()Ҏ(gu)查匹配情况:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_l.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">接下来,利用PatternMatcher接口q回的MatchResult对象Q输出匹配的l。由于logEntry字符串包含匹配的内容Q你可以看到cd下面的输出:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_m.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">3.2 HTML处理实例一</strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">下面一个Q务是分析HTML面内FONT标记的所有属性。HTML面内典型的FONT标记如下所C:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_n.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">E序按照如下Ş式,输出每一个FONT标记的属性:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_o.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">在这U情况下Q我你用两个正则表辑ּ。第一个如囑֍一所C,它从字体标记提取?#8220;"face="Arial, Serif" size="+2" color="red"”?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 91px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4k.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">囑֍一Q匹配FONT标记的所有属?/p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">W二个正则表辑ּ如图十二所C,它把各个属性分割成名字-值对?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 140px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4l.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">囑֍二:匚w单个属性,q把它分割成名字-值对</p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">分割l果为:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_p.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">现在我们来看看完成这个Q务的Java代码。首先创Z个正则表辑ּ字符Ԍ用Perl5Compiler把它们编译成Pattern对象。编译正则表辑ּ的时候,指定Perl5Compiler.CASE_INSENSITIVE_MASK选项Q得匹配操作不区分大小写?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">接下来,创徏一个执行匹配操作的Perl5Matcher对象?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_q.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">假设有一个Stringcd的变量htmlQ它代表了HTML文g中的一行内宏V如果html字符串包含FONT标记Q匹配器返回true。此Ӟ你可以用匚w器对象返回的MatchResult对象获得W一个组Q它包含了FONT的所有属性:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_r.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">接下来创Z个PatternMatcherInput对象。这个对象允怽从最后一ơ匹配的位置开始l进行匹配操作,因此Q它很适合于提取FONT标记内属性的名字-值对。创建PatternMatcherInput对象Q以参数形式传入待匹配的字符丌Ӏ然后,用匹配器实例提取出每一个FONT的属性。这通过指定PatternMatcherInput对象Q而不是字W串对象Qؓ参数Q反复地调用PatternMatcher对象的contains()Ҏ(gu)完成。PatternMatcherInput对象之中的每一ơP代将把它内部的指针向前移动,下一ơ检将从前一ơ匹配位|的后面开始?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">本例的输出结果如下:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_s.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">3.3 HTML处理实例?/strong></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">下面我们来看看另一个处理HTML的例子。这一ơ,我们假定Web服务器从widgets.acme.comUd了newserver.acme.com。现在你要修改一些页面中的链接:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_t.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">执行q个搜烦的正则表辑ּ如图十三所C:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true"><img style="width: 500px; height: 108px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4m.gif" border="0" _extended="true" /></p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"> <p align="center" _extended="true">囑֍三:匚w修改前的链接</p> </td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">如果能够匚wq个正则表达式,你可以用下面的内Ҏ(gu)换图十三的链接:</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><a _extended="true"></a><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_u.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">注意#字符的后面加上了$1。Perl正则表达式语法用$1?2{表C已l匹配且提取出来的组。图十三的表辑ּ把所有作Z个组匚w和提取出来的内容附加到链接的后面?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">现在Q返回Java。就象前面我们所做的那样Q你必须创徏试字符Ԍ创徏把正则表辑ּ~译到Pattern对象所必需的对象,以及创徏一个PatternMatcher对象Q?img style="width: 500px; height: 181px" alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_v.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">接下来,用com.oroinc.text.regex包Utilcȝsubstitute()静态方法进行替换,输出l果字符Ԍ</td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_w.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">Util.substitute()Ҏ(gu)的语法如下:</td> </tr> </tbody> </table> <table height="17" width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" height="13" _extended="true"><img alt="" src="http://www.ccw.com.cn/htm/app/aprog/01_7_31_4_x.jpg" border="0" _extended="true" /></td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true">q个调用的前两个参数是以前创建的PatternMatcher和Pattern对象。第三个参数是一个Substiution对象Q它军_了替换操作如何进行。本例用的是Perl5Substitution对象Q它能够q行Perl5风格的替换。第四个参数是想要进行替换操作的字符Ԍ最后一个参数允许指定是否替换模式的所有匹配子ԌUtil.SUBSTITUTE_ALLQ,或只替换指定的次数?/td> </tr> </tbody> </table> <table width="620" align="center" _extended="true"> <tbody _extended="true"> <tr _extended="true"> <td class="a14" _extended="true"><strong _extended="true">【结束语?/strong>在这文章中Q我Z介绍了正则表辑ּ的强大功能。只要正运用,正则表达式能够在字符串提取和文本修改中v到很大的作用。另外,我还介绍了如何在JavaE序中通过Jakarta-ORO库利用正则表辑ּ。至于最l采用老式的字W串处理方式Q用StringTokenizerQcharAtQ和substringQ,q是采用正则表达式,q就有待你自己决定了?/td> </tr> </tbody> </table> </p> <img src ="http://www.aygfsteel.com/conans/aggbug/209562.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/conans/" target="_blank">CONAN</a> 2008-06-20 22:44 <a href="http://www.aygfsteel.com/conans/articles/209562.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¡</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ͳ</a>| <a href="http://" target="_blank">ͩ®</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̩</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">差</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ͻȪ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ѳ</a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ٹ</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank">բ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">㰲</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ӽ</a>| <a href="http://" target="_blank">˼</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>