ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>蜜芽tv福利在线视频,国产精品久久久久国产a级,久久免费国产视频http://www.aygfsteel.com/leopallas/archive/2006/05/09/45170.htmlLeoLeoTue, 09 May 2006 03:17:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/05/09/45170.htmlhttp://www.aygfsteel.com/leopallas/comments/45170.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/05/09/45170.html#Feedback2http://www.aygfsteel.com/leopallas/comments/commentRss/45170.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/45170.html     昨天è¯ÖMº†ä¸€½‹‡å…³äºŽJDBC4.0设计与性能提高的文章,ç”׃ºŽž®å¼Ÿè‹Þp¯­¾˜»è¯‘水准实在有限åQŒå°±ä¸åœ¨˜q™é‡ŒçŒ®ä¸‘了,ž®±æŠŠåŽŸæ–‡¾l™å¤§å®¶è{载出来供大家阅读:

转蝲自:http://www.javaworld.com/javaworld/jw-05-2006/jw- 0501-jdbc .html

Design and performance improvements with JDBC 4.0

Effectively utilize JDBC'S features to get desired results with less code

Summary
Java Database Connectivity (JDBC) 4.0 is ready for release by mid 2006 as a part of Java Standard Edition 6.0. How can you leverage the new specification to improve the design and performance of database access and interactions in Java applications? This article discusses the new features of JDBC 4.0, illustrates its solutions to some existing problems, and presents its improvements in design and performance through examples. (2,100 words; May 1, 2006)
By Shashank Tiwari


Java Database Connectivity (JDBC), which has existed from the first public version of the core Java language, has evolved significantly over the last 10 years. In its current version, 4.0, which will be packaged with Java Standard Edition 6.0 (Java SE is Sun's new name for J2SE), it shows significant improvements in design and provides a richer API, with focus on ease of development and improvement in productivity.

This article discusses some of the important changes in the JDBC specification that either improve the design or facilitate better performance. The article does not enlist or survey every single change incorporated as a part of Java Specification Request 221, the JDBC 4.0 initiative.

After reading this article, you should be ready to leverage the new features in your next set of applications.

Annotations and the generic DataSet
I assume you are already aware of annotations and generics, which were introduced in Java with J2SE 5.0. JDBC 4.0 introduces annotations and the generic DataSet. This change aims to simplify execution of SQL queries (in scenarios that return a single result set) and SQL DML (data manipulation language) statements (that return either a row count or nothing).

The new API defines a set of Query and DataSet interfaces. The Query interface defines a set of methods decorated with the JDBC annotations. These decorated methods describe the SQL select and update statements, and specify how the result set should be bound to a DataSet. The DataSet interface is a parameterized type, as defined by generics. The DataSet interface provides a type-safe definition for the result set data.

All Query interfaces inherit from the BaseQuery interface. A concrete implementation of the interface can be instantiated using either the Connection.createQueryObject() or DataSource.createQueryObject() methods and passing a Query interface type as its parameter.

A DataSet interface inherits from java.util.List. A data class describing the columns of the result set data, returned by an annotated method of the Query interface, is its parameter type. A DataSet can be manipulated and operated upon both in a connected and disconnected mode. Thus, the DataSet is implemented either as a ResultSet or a CachedRowSet, depending on its operating mode: connected or disconnected. DataSet, being a sub-interface of the java.util.List, allows access of its data rows with the Iterator pattern, using the java.util.Iterator interface.

The data class or the user-defined class, which is a parameter type of the DataSet interface, can be specified in two ways: as a structure or as a JavaBeans object. Either method achieves the goal of binding result set data columns to user-defined class definitions, but the JavaBeans component model is more elegant and facilitates object definition reuse within other frameworks that support the JavaBeans model.

Listing 1 illustrates code snippets for a simple example to show how the new API is used to create and run SQL queries, define result set data using a user-defined class, and bind the returned result set to the user-defined specifications.

Listing 1. Employee user-defined type and employeeQueries

pubic class Employee {
   private int employeeId;
   private String firstName;
   private String lastName;

   public int getEmployeeId() {
      return employeeId;
   }
  
   public setEmployeeId(int employeeId) {
      this.employeeId = employeeId;
   }

   public String getFirstName() {
      return firstName;
   }

   public setFirstName(String firstName) {
      this.firstName = firstName;
   }

   pubic String lastName() {
      return lastName;
   }

   public setLastName(String lastName) {
      this.lastName = lastName;
   }
}


interface EmployeeQueries extends BaseQuery {
   @Select (sql="SELECT employeeId, firstName, lastName FROM employee")
   DataSet<Employee> getAllEmployees ();

   @Update (sql="delete from employee")
   int deleteAllEmployees ();
}


Connection con = ...

EmployeeQueries empQueries = con.createQueryObject (EmployeeQueries.class);

DataSet<Employee> empData = empQueries.getAllEmployees ();

Exception-handling enhancements
The exception-handling functionality in the JDBC API prior to version 4.0 is limited and often insufficient. SQLException is thrown for all types of errors. There is no classification of exceptions, and no hierarchy defines them. The only way to get some meaningful information is to retrieve and analyze the SQLState value. SQLState values and their corresponding meanings change from datasource to datasource; hence, getting to the root of the problem and efficiently handling exceptions proves to be a tedious task.

JDBC 4.0 has enhanced exception-handling capability and alleviates some of the mentioned problems. The key changes are as follows:

  • Classification of SQLException into transient and non-transient types
  • Support for chained exceptions
  • Implementation of the Iterable interface

The SQLTransientException is thrown where a previously failed operation may succeed on retrial. The SQLNonTransientException is thrown where retrial will not lead to a successful operation unless the cause of the SQLException is corrected.

Figure 1 illustrates the subclasses of SQLTransientException and SQLNonTransientException.


Figure 1. SQL exception classes: Transient and non-transient

Support for chained exceptions are now included. New constructors add extra parameters to capture possible causes for the exception. Multiple SQLExceptions could be iterated over in a loop, and getCause() could be called to determine the exception's possible cause. The getCause() method can return non-SQLExceptions if they are the underlying cause of the exceptions.

The SQLException class now implements the Iterable interface and supports the J2SE 5.0 for each loop for easier and more elegant looping.

Listing 2 depicts the usage of the new for-each-loop construct:

Listing 2. For each loop

catch(SQLException ex) {
   for(Throwable t : ex) {
      System.out.println("exception:" + t);
   }
}


SQL/XML
A large amount of data now exists in the XML format. Databases have extended support for the XML data type by defining a standard XML type in the SQL 2003 specification. Most database vendors have an implementation of the XML data type in their new releases. With the inclusion of such a type, an XML dataset or document could be one of the fields or column values in a row of a database table. Prior to JDBC 4.0, perhaps the best way to manipulate such data within the JDBC framework is to use proprietary extensions from the driver vendors or access it as a CLOB type.

JDBC 4.0 now defines SQLXML as the Java data type that maps the database SQL XML type. The API supports processing of an XML type as a string or as a StAX stream. Streaming API for XML, which for Java has been adopted via JSR 173, is based on the Iterator pattern, as opposed to the Simple API for XML Processing (SAX), which is based on the Observer pattern.

Invoking the Connection object's createSQLXML() method can create a SQLXML object. This is an empty object, so the data can be attached to it by either using the setString() method or by associating an XML stream using the createXMLStreamWriter() method with the object. Similarly, XML data can be retrieved from a SQLXML object using getString() or associating an XML stream using createXMLStreamReader() with the object.

The ResultSet, the PreparedStatement, and the CallableStatement interfaces have getSQLXML() methods for retrieving a SQLXML data type. PreparedStatement and CallableStatement also have setSQLXML() methods to add SQLXML objects as parameters.

The SQLXML resources can be released by calling their free() methods, which might prove pertinent where the objects are valid in long-running transactions. DatabaseMetaData's getTypeInfo() method can be called on a datasource to check if the database supports the SQLXML data type, since this method returns all the data types it supports.

Connections and Statements
The Connection interface definitions have been enhanced to analyze connection state and usage to facilitate efficiency.

Sometimes database connections are unusable though they may not necessarily be closed and garbage collected. In such situations, the database appears slow and unresponsive. In most of these circumstances, reinitializing the connections is perhaps the only way to resolve the problem. When using the JDBC API prior to version 4.0, there is no way to distinguish between a stale connection and a closed connection. The new API adds an isValid() method to the Connection interface to query if the connection is still valid.

Also, database connections are often shared among clients, and sometimes some clients tend to use more resources than others, which can lead to starvation-like situations. The Connection interface defines a setClientInfo() method to define client-specific properties, which could be utilized to analyze and monitor resource utilization by the clients.

RowId
The RowId in many databases is a unique way to identify a row in a table. Queries using RowId in the search criteria are often the fastest way to retrieve data, especially true in the case of the Oracle and DB2 databases. Since java.sql.RowId is now a built-in type in Java, you could utilize the performance benefits associated with its usage. RowIds are most useful in identifying unique and specific rows when duplicate data exists and some rows are identical. However, it is important to understand that RowIds often are unique only for a table and not for the entire database; they may change and are not supported by all databases. RowIds are typically not portable across datasources and thus should be used with caution when working with multiple datasources.

A RowId is valid for the lifetime defined by the datasource and as long as the row is not deleted. The DatabaseMetadata.getRowIdLifetime() method is called to determine the RowId's lifetime. The return type is an enumeration type as summarized in the table below.

RowIdLifetime enum type Definition
ROWID_UNSUPPORTED Datasource does not support RowId type
ROWID_VALID_OTHER Implementation-dependent lifetime
ROWID_VALID_TRANSACTION Lifetime is at least the containing transaction
ROWID_VALID_SESSION Lifetime is at least the containing session
ROWID_VALID_FOREVER Unlimited lifetime

The ROWID_VALID_TRANSACTION, ROWID_VALID_SESSION, and ROWID_VALID_FOREVER definitions are true as long as the row is not deleted. It is important to understand that a new RowId is assigned if a row is deleted and reinserted, which sometimes could happen transparently at the datasource. As an example, in Oracle, if the "enable row movement" clause is set on a partitioned table and an update of the partition key causes the row to move from one partition to another, the RowId will change. Even without the "enable row movement" flag with the "alter table table_name" move, the RowId could change.

Both the ResultSet and CallableStatement interfaces have been updated to include a method called getRowID(), which returns a javax.sql.RowId type.

Listing 3 shows how RowId could be retrieved from a ResultSet and from a CallableStatement.

Listing 3. Get RowId

//The method signatures to retrieve RowId from a ResultSet is as follows:
   RowId getRowId (int columnIndex)
   RowId getRowId (String columnName)
...

Statement stmt = con.createStatement ();

ResultSet rs = stmt. ExecuteQuery (�;

while (rs.next ()) {

...

java.sql.RowId rid = rs.getRowId (1);

...

}

//The method signatures to retrieve RowId from a CallableStatement is as follows:
   RowId getRowId (int parameterIndex)
   RowId getRowId (String parameterName)

Connection con;
...

CallableStatement cstmt = con.prepareCall (�;
...

cstmt.registerOutParameter (2, Types.ROWID);

...

cstmt.executeUpdate ();

...

java.sql.RowId rid = cstmt.getRowId (2);

The RowId can be used to refer uniquely to a row and thus can be used to retrieve the rows or update the row data. When fetching or updating using RowId references, it is important to know the validity of the RowId's lifetime to assure consistent results. It is also advisable to simultaneously use another reference, such as the primary key, to avoid inconsistent results in circumstances where the RowId could change transparently.

The RowId values can also be set or updated. In the case of an updateable ResultSet, the updateRowId() method could be used to update the RowId for a particular row in a table.

Both the PreparedStatement and the CallableStatement interfaces support a setRowId() method, with different signatures, to set the RowId as a parameter value. This value could be used to refer to data rows or to update the RowId value for a particular row in a table.

The facility to set or update the RowId provides the flexibility to control the unique row identifiers and could be used to make such identifiers unique across the tables used. Perhaps, portability of RowId across supporting datasources could also be achieved by explicitly setting consistent values across them. However, because system-generated RowIds are often efficient, and transparent tasks could alter RowIds, they are best used by an application as a read-only attribute.

Leverage nonstandard vendor implemented resources
The new JDBC API defines a java.sql.Wrapper interface. This interface provides the ability to access datasource-vendor-specific resources by retrieving the delegate instance using the corresponding wrapped proxy instance.

This Wrapper interface has 17 sub-interfaces as per the current specification and includes Connection, ResultSet, Statement, CallableStatement, PreparedStatement, DataSource, DatabaseMetaData, and ResultSetMetaData, among others in the list. This is an excellent design as it facilitates datasource-vedor-specific resource implementation at almost all stages of the query-creation and result-set-retrieval lifecycles.

The unwrap() method returns the object that implements the given interface to allow access to vendor-specific methods. The isWrapperFor() method returns a Boolean value. It returns true if it implements the interface, or if it directly or indirectly is a wrapper for the object.

As an example, when using Oracle, Oracle JDBC drivers provide update batching extensions that are better performing and more efficient as compared to the standard JDBC batch-updating mechanisms. For earlier JDBC versions, this implies using the Oracle-specific definitions, such as OraclePreparedStatement, in the code. This compromises code portability. With the new API, many such efficient implementations can be wrapped and exposed within the standard JDBC definitions.

Service provider mechanism for driver loading
In a nonmanaged or standalone program scenario, prior to JDBC 4.0, you would have to load the JDBC driver class explicitly by invoking the Class.forName method, as shown in Listing 4:

Listing 4. Class.forName

Class.forName ("com.driverprovider.jdbc.jdbcDriverImpl");

With JDBC 4.0, if the JDBC driver vendors package their drivers as services, defined under the server provider mechanism definitions as per the JAR specification, the DriverManager code would implicitly load the driver by searching for it in the classpath. The benefit of this mechanism is that the developer does not need to know about the specific driver class and can write a little less code when using JDBC. Also, since the driver class name is no longer in the code, a name change would not require recompilations. If multiple drivers are specified in the classpath, then DriverManger will try and establish a connection using the first driver it encounters in the classpath and iterate further if required.

Conclusion
In this article, I have discussed some of the new and improved features of JDBC 4.0. Many of these new features enhance a developer's productivity and facilitate development. Also, the specification does not eradicate the possible use of extra JDBC frameworks to provide templating facilities and advanced exception-handling capabilities. However, there is some criticism as well. Some believe that annotations effectively lead to hard-coding in code, which causes problems in code maintainability.



Leo 2006-05-09 11:17 发表评论
]]>
ANT安装、配¾|?(è½?http://www.aygfsteel.com/leopallas/archive/2006/05/08/44963.htmlLeoLeoMon, 08 May 2006 02:54:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/05/08/44963.htmlhttp://www.aygfsteel.com/leopallas/comments/44963.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/05/08/44963.html#Feedback3http://www.aygfsteel.com/leopallas/comments/commentRss/44963.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/44963.html

ANT安装、配¾|?/span>

内容摘要åQ?br />ant是一个基于JAVA的自动化脚本引擎åQŒè„šæœ¬æ ¼å¼äØ“XML。除了做JAVA¾~–译相关ä»ÕdŠ¡å¤–ï¼ŒANT˜q˜å¯ä»¥é€šè¿‡æ’äšg实现很多应用的调用ã€?/p>


ANT的基本概念:
ANT的安装:解包åQŒè®¾¾|®èµ\å¾?
ANTçš„ä‹É用:最好的学习只不˜q‡æ˜¯ä¸€ä¸ªç®€å•实用的例子èµäh­¥â€¦â€?
ANT的基本概念:Java的Makefile
当一个代码项目大了以后,每次重新¾~–译åQŒæ‰“包,‹¹‹è¯•½{‰éƒ½ä¼šå˜å¾—非常复杂而且重复åQŒå› æ­¤c语言中有make脚本来帮助这些工作的扚w‡å®Œæˆã€‚在Java 中应用是òq›_°æ— å…³æ€§çš„åQŒå½“然不会用òq›_°ç›¸å…³çš„make脚本来完成这些批处理ä»ÕdŠ¡äº†ï¼ŒANT本èínž®±æ˜¯˜q™æ ·ä¸€ä¸ªæµ½E‹è„šæœ¬å¼•æ“Žï¼Œç”¨äºŽè‡ªåŠ¨åŒ–è°ƒç”¨ç¨‹åºå®Œæˆé¡¹ç›®çš„¾~–译åQŒæ‰“包,‹¹‹è¯•½{‰ã€‚除了基于JAVA是åã^台无关的外,脚本的格式是åŸÞZºŽXML的,比make脚本来说˜q˜è¦å¥½ç»´æŠ¤ä¸€äº›ã€?/p>


每个ant脚本åQˆç¼ºçœå«build.xmlåQ‰ä¸­è®„¡½®äº†ä¸€¾pÕdˆ—ä»ÕdŠ¡(target)åQšæ¯”å¦‚å¯¹äºŽä¸€ä¸ªä¸€èˆ¬çš„™å¹ç›®å¯èƒ½éœ€è¦æœ‰ä»¥ä¸‹ä»ÕdŠ¡ã€?/p>

ä»ÕdŠ¡1åQšusage 打印本脚本的帮助信息åQˆç¼ºçœï¼‰
ä»ÕdŠ¡2åQšclean <-- init 清空初始化环å¢?
ä»ÕdŠ¡3åQšjavadoc <-- build <-- init 生成JAVADOC
ä»ÕdŠ¡4åQšjar <-- build <-- init 生成JAR
ä»ÕdŠ¡5åQšall <-- jar + javadoc <-- build <-- init 完成以上所有ä“Q务:jar javadoc
而多个ä“Q务之间往往又包含了一定了依赖关系åQšæ¯”å¦‚æŠŠæ•´ä¸ªåº”ç”¨æ‰“åŒ…ä»ÕdŠ¡(jar)的这个依赖于¾~–译ä»ÕdŠ¡(build)åQŒè€Œç¼–译ä“Q务又依赖于整个环境初始化ä»ÕdŠ¡(init)½{‰ã€?/p>

注:我看到很多项目的ant脚本中的命名基本上都是一致的åQŒæ¯”如:¾~–译一般叫build或者compileåQ›æ‰“包一般叫jar或waråQ›ç”Ÿæˆæ–‡æ¡£ä¸€èˆ¬å‘½åäØ“javadoc或javadocsåQ›æ‰§è¡Œå…¨éƒ¨ä“Q务all。在每个ä»ÕdŠ¡çš„ä¸­åQŒANT会根据配¾|®è°ƒç”¨ä¸€äº›å¤–éƒ¨åº”ç”¨åÆˆé…ä»¥ç›¸åº”å‚æ•°æ‰§è¡Œã€‚è™½ç„¶ANT可调用的外部应用¿Uç±»éžå¸¸ä¸°å¯ŒåQŒä½†å…¶å®žæœ€å¸¸ç”¨çš„å°±2åQ?个:比如javac javadoc jar½{‰ã€?
ANT的安è£?br />解包后在¾pȝ»Ÿå¯æ‰§è¡Œèµ\径中加入指向antçš„binçš„èµ\径就可以了,比如可以在GNU/Linux上把以下配置加入/etc/profile中:
export ANT_HOME=/home/ant
export JAVA_HOME=/usr/java/j2sdk1.4.1
export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin

˜q™æ ·æ‰§è¡Œant 后,如果不指定配¾|®æ–‡ä»¶ant会缺省找build.xml˜q™ä¸ªé…ç½®æ–‡äšgåQŒåƈæ ÒŽ®é…ç½®æ–‡äšg执行ä»ÕdŠ¡åQŒç¼ºçœçš„ä»ÕdŠ¡è®„¡½®å¯ä»¥æŒ‡å‘最常用的ä“Q务,比如åQ? buildåQŒæˆ–指向打印帮助信息åQšusageåQŒå‘Šè¯‰ç”¨æˆähœ‰é‚£äº›è„šæœ¬é€‰é¡¹å¯ä»¥ä½¿ç”¨ã€?/p>


ANTçš„ä‹Éç”?/p>

最好的学习˜q‡ç¨‹ž®±æ˜¯çœ‹æ‡‚那些open source™å¹ç›®ä¸­çš„build.xml脚本åQŒç„¶åŽæ ¹æ®è‡ªå·Þqš„需要简化成一个更½Ž€å•çš„åQŒANTå’ŒAPACHE上很多非常工½E‹æ´¾çš„项目:½Ž€å•易用,而且适应性非常强åQŒå› ä¸ø™¿™äº›é¡¹ç›®çš„建立往往来源于开发äh员日常最直接的需求ã€?br />以下是的一个WebLucene应用的例子:修改自JDOMçš„build.xmlåQ?/p>

<project default="usage" basedir=".">

<!-- =================================================================== -->
<!-- Initialization target -->
<!-- =================================================================== -->
<target name="init">
<tstamp/>
<property file="${basedir}/build.properties" />
<property name="Name" value="ProjectFullName"/>
<property name="name" value="project_name"/>
<property name="version" value="0.2"/>
<property name="year" value="2003"/>

<echo message="----------- ${Name} ${version} [${year}] ------------"/>

<property name="debug" value="off"/>
<property name="optimize" value="on"/>
<property name="deprecation" value="on"/>

<property name="src.dir" value="./src/WEB-INF/src"/>
<property name="lib.dir" value="./src/WEB-INF/lib"/>
<property name="packages" value="com.chedong.*,org.apache.lucene.*"/>

<property name="build.src" value="./src/WEB-INF/build"/>
<property name="build.dest" value="./src/WEB-INF/classes"/>
<property name="build.javadocs" value="./src/doc"/>

<path id="classpath">
<pathelement path="${jsdk_jar}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>

<filter token="year" value="${year}"/>
<filter token="version" value="${version}"/>
<filter token="date" value="${TODAY}"/>
<filter token="log" value="true"/>
<filter token="verbose" value="true"/>
</target>

<!-- =================================================================== -->
<!-- Help on usage -->
<!-- =================================================================== -->
<target name="usage" depends="init">
<echo message="${Name} Build file"/>
<echo message="-------------------------------------------------------------"/>
<echo message=""/>
<echo message=" available targets are:"/>
<echo message=""/>
<echo message=" jar --> generates the ${name}.jar file"/>
<echo message=" build --> compiles the source code"/>
<echo message=" javadoc --> generates the API documentation"/>
<echo message=" clean --> cleans up the directory"/>
<echo message=""/>
<echo message=" Please rename build.properties.default to build.properties"/>
<echo message=" and edit build.properties to specify JSDK 2.3 classpath."/>
<echo message=""/>
<echo message=" See the comments inside the build.xml file for more details."/>
<echo message="-------------------------------------------------------------"/>
<echo message=""/>
<echo message=""/>
</target>

<!-- =================================================================== -->
<!-- Prepares the source code -->
<!-- =================================================================== -->
<target name="prepare-src" depends="init">
<!-- create directories -->
<mkdir dir="${build.src}"/>
<mkdir dir="${build.dest}"/>

<!-- copy src files -->
<copy todir="${build.src}">
<fileset dir="${src.dir}"/>
</copy>
</target>

<!-- =================================================================== -->
<!-- Compiles the source directory -->
<!-- =================================================================== -->
<target name="build" depends="prepare-src">
<javac srcdir="${build.src}"
destdir="${build.dest}"
debug="${debug}"
optimize="${optimize}">
<classpath refid="classpath"/>
</javac>
</target>

<!-- =================================================================== -->
<!-- Creates the class package -->
<!-- =================================================================== -->
<target name="jar" depends="build">
<jar jarfile="${lib.dir}/${name}.jar"
basedir="${build.dest}"
includes="**"/>
</target>

<!-- =================================================================== -->
<!-- Creates the API documentation -->
<!-- =================================================================== -->
<target name="javadoc" depends="build">
<mkdir dir="${build.javadocs}"/>
<javadoc packagenames="${packages}"
sourcepath="${build.src}"
destdir="${build.javadocs}"
author="true"
version="true"
use="true"
splitindex="true"
windowtitle="${Name} API"
doctitle="${Name}">
<classpath refid="classpath"/>
</javadoc>
</target>

<!-- =================================================================== -->
<!-- Clean targets -->
<!-- =================================================================== -->
<target name="clean" depends="init">
<delete dir="${build.src}"/>
<delete dir="${build.dest}/org"/>
<delete dir="${build.dest}/com"/>
<delete>
<fileset dir="${build.dest}" includes="**/*.class"/>
</delete>
</target>
</project>
<!-- End of file -->

¾~ºçœä»ÕdŠ¡åQšusage 打印帮助文档åQŒå‘Šè¯‰æœ‰é‚£äº›ä»ÕdС选项åQšå¯ç”¨çš„æœ‰build, jar, javadocå’Œclean.

初始化环境变量:init
所有ä“Q务都åŸÞZºŽä¸€äº›åŸºæœ¬çŽ¯å¢ƒå˜é‡çš„è®„¡½®åˆå§‹åŒ–完成,是后¾l­å…¶ä»–ä“Q务的基础åQŒåœ¨çŽ¯å¢ƒåˆå§‹åŒ–è¿‡½E‹ä¸­åQŒæœ‰2ç‚ÒŽ¯”较可以方便设¾|®ï¼š

1 除了使用却缺省的property讄¡½®äº†JAVA源èµ\径和输出路径外,引用了一个外部的build.propertiesæ–‡äšg中的讄¡½®åQ?br /><property file="${basedir}/build.properties" />
˜q™æ ·å¤§éƒ¨åˆ†ç®€å•配¾|®ç”¨æˆ·åªè¦ä¼šçœ‹æ‡‚build.propertiesž®±å¯ä»¥äº†åQŒæ¯•竟XML比è“vkey value的属性文件还是要可读性差一些。用build.properties也可以方便其他用户从¾~–译的细节中解放出来ã€?/p>

2 CLASSPATH讄¡½®åQšä‹É用了其中的:
<path id="classpath">
<pathelement path="${jsdk_jar}"/>
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
则相当于讄¡½®äº†ï¼šCLASSPATH=/path/to/resin/lib/jsdk23.jar; /path/to/project/lib/*.jar;

æ–‡äšg复制åQšprepare-src
创徏临时SRC存放目录和输出目录�br /><!-- =================================================================== -->
<!-- Prepares the source code -->
<!-- =================================================================== -->
<target name="prepare-src" depends="init">
<!-- create directories -->
<mkdir dir="${build.src}"/>
<mkdir dir="${build.dest}"/>

<!-- copy src files -->
<copy todir="${build.src}">
<fileset dir="${src.dir}"/>
</copy>
</target>

¾~–译ä»ÕdŠ¡åQšbuild
¾~–译时的CLASSPATH环境通过一下方式找到引用一个path对象
<classpath refid="classpath"/>

打包ä»ÕdŠ¡åQšjar
对应用打包生成项目所写名çš?jaræ–‡äšg
<!-- =================================================================== -->
<!-- Creates the class package -->
<!-- =================================================================== -->
<target name="jar" depends="build">
<jar jarfile="${lib.dir}/${name}.jar"
basedir="${build.dest}"
includes="**"/>
</target>

生成JAVADOC文档ä»ÕdŠ¡: javadoc
<!-- =================================================================== -->
<!-- Creates the API documentation -->
<!-- =================================================================== -->
<target name="javadoc" depends="build">
<mkdir dir="${build.javadocs}"/>
<javadoc packagenames="${packages}"
sourcepath="${build.src}"
destdir="${build.javadocs}"
author="true"
version="true"
use="true"
splitindex="true"
windowtitle="${Name} API"
doctitle="${Name}">
<classpath refid="classpath"/>
</javadoc>
</target>

清空临时¾~–译文äšgåQšclean
<!-- =================================================================== -->
<!-- Clean targets -->
<!-- =================================================================== -->
<target name="clean" depends="init">
<delete dir="${build.src}"/>
<delete dir="${build.dest}/org"/>
<delete dir="${build.dest}/com"/>
<delete>
<fileset dir="${build.dest}" includes="**/*.class"/>
</delete>
</target>

TODOåQ?br />更多ä»ÕdŠ¡/扩展åQšï¼ˆæ ·ä¾‹åQ?/p>

‹¹‹è¯•ä»ÕdŠ¡åQšJUnit‹¹‹è¯•
代码风格‹‚€æŸ¥ä“Q务:CheckStyleåQŒJalopy½{?
é‚®äšg警报ä»ÕdŠ¡åQšå¯ä»¥æŠŠä»¥ä¸Š˜q™äº›ä»ÕdŠ¡çš„è¾“å‡ø™­¦å‘Šå‘送到制定的用户列表中åQŒè¿™ä¸ªä“Q务可以设¾|®æ¯å¤©è‡ªåŠ¨è¿è¡Œã€?

参考资料:

Jakarta ANT:
http://ant.apache.org



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=707995



Leo 2006-05-08 10:54 发表评论
]]>
JDBC2/3.0的特征点æ»?http://www.aygfsteel.com/leopallas/archive/2006/05/08/44961.htmlLeoLeoMon, 08 May 2006 02:49:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/05/08/44961.htmlhttp://www.aygfsteel.com/leopallas/comments/44961.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/05/08/44961.html#Feedback2http://www.aygfsteel.com/leopallas/comments/commentRss/44961.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/44961.html 最˜q‘写½E‹åºå·²ç»å¾ˆå°‘直接用JDBC了,一直都是用ibaits, Hibernate½{‰æ¥æ‹›å‘¼åQŒå› ä¸ºçŽ°åœ¨çš„é›†æˆæ¡†æž¶å·²ç»å¾ˆç¨³å®šäº†ã€‚ä¸˜q‡å¯¹JDBC的直接ä‹É用还是不可以忽略的,JDBC3.0提供的n多的新特征还是要熟悉了解的,以前学jdbc的时候就是上¾|‘找些demo和介¾læ¥å­¦ï¼Œä½¿ç”¨å¾ˆå•一åQŒå¯¹JDBC3.0的好多新的特征都忽略了,比如下面一个例子:

Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM user WHERE username='aa'");
stmt.executeUpdate("UPDATE user SET lastdatetime=now() where username='aa'");

˜q™æ˜¯ä¸€ä¸ªç”¨æˆïL™»å½•æ—¶åQŒç»å¸¸ç”¨åˆ°çš„代码åQŒå…ˆæ˜¯æ ¹æ®ç”¨æˆ·åaa查找该用æˆïLš„详细信息åQŒç„¶åŽå†æ›´æ–°è¯¥ç”¨æˆïLš„æœ€åŽç™»å½•æ—¶é—ß_¼ˆlastdatetimeåQ‰ã€‚è¿™˜q™ä¸ªé‡Œé¢åQŒæˆ‘们用了两个sql语句åQŒè¿™ä¸ªæ˜¯æˆ‘一直用的方法,但是如果用JDBC2.0¾l™æˆ‘们提供的便利åQŒæˆ‘们只要写一条sqlž®±å¤Ÿäº†ï¼Œå…¶ä»–的都交给jdbcåQŒçœ‹ä¸‹é¢çš„代码:

Statement stmt2 = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet rs2 = stmt.executeQuery("SELECT * FROM user WHERE username='aa'");
rs2.next();
rs2.updateDate("lastdatetime", new Date(Calendar.getInstance().getTimeInMillis()));
rs2.updateRow();

˜q™é‡Œé¢æœ€ä¸»è¦çš„特征就是ResultSet.TYPE_FORWARD_ONLYå’ŒResultSet.CONCUR_UPDATABLEåQŒé€šè¿‡åˆå§‹åŒ–Statement时传不同的参敎ͼŒå¯ä»¥å¯¹ResultSet˜q›è¡Œä¸ç”¨çš„错作限制。con.createStatement的时候,有三¿Uå¯ä»¥æŽ‰ç”¨çš„函数åQ?/font>

1、createStatement();
2、createStatement(int resultSetType, int resultSetConcurrency)
3、createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)

其中resultSetType可选值是åQ?br />   1、ResultSet.TYPE_FORWARD_ONLY  在ResultSet中只能先前移动游标,
   2、ResultSet.TYPE_SCROLL_INSENSITIVE 在ResultSet中可以随心所‹Æ²çš„先前向后¿UÕdŠ¨æ¸¸æ ‡åQ?br />   3、ResultSet.TYPE_SCROLL_SENSITIVE 在ResultSet中可以随心所‹Æ²çš„先前向后¿UÕdŠ¨æ¸¸æ ‡åQŒåŒæ—¶ResultSet的值有所改变的时候,他可以得到改变后的最新的å€?br />其中resultSetConcurrency可选值是åQ?br />   1、ResultSet.CONCUR_READ_ONLY  在ResultSet中的数据记录是只è¯Èš„åQŒå¯ä»¥ä¿®æ”?br />   2、ResultSet.CONCUR_UPDATABLE  在ResultSet中的数据记录可以ä»ÀL„ä¿®æ”¹åQŒç„¶åŽæ›´æ–îC¼šæ•°æ®åº?br />其中resultSetHoldability可选值是åQ?br />   1、ResultSet.HOLD_CURSORS_OVER_COMMIT 表示修改提交æ—?不关闭ResultSet的游æ ?br />   2、ResultSet.CLOSE_CURSORS_AT_COMMIT  表示修改提交æ—?关闭ResultSet的游æ ?/font>

对于查询操作½W¬ä¸€¿Uåˆå§‹åŒ–æ–ÒŽ³•createStatement()åQŒç›¸å½“于½W¬äºŒ¿Uæ–¹æ³•çš„createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)åQŒç¬¬ä¸‰ç§æ–ÒŽ³•çš„createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT)

下面写一ŒDµdemo的代码,我把一些特征函数都用出来,但是只是用来查考和说明名灵‹zÀL€§çš„ã€?/font>

 Statement stmt2 = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
 ResultSet rs2 = stmt.executeQuery("SELECT * FROM user");
 rs2.next();
 rs2.updateDate("lastdatetime", new Date(Calendar.getInstance().getTimeInMillis()));
 rs2.updateRow();
 rs2.afterLast();
 while(rs2.previous()){ /**....*/ }
 rs.beforeFirst();
 while(rs2.next()){  /**....*/ }
 rs.last();
 rs.first();
 rs.absolute(5); //游标¿UÕdŠ¨åˆ°ç¬¬5æ?br /> rs.absolute(-1);  //游标¿UÕdŠ¨åˆ°æœ€åŽä¸€æ?br /> rs.relative(-5);  //游标向上¿UÕdЍ5æ?br /> rs.relative(2);   //游标向下¿UÕdЍ2æ?br /> rs.deleteRow(); //删除当前è¡?br /> rs.last();  //游标¿UÕdŠ¨åˆ°æœ€å?br /> rs.updateString("summary", "This is ..."); //讄¡½®æ›´æ–°çš„å­—ŒDµå€?br /> rs.cancelRowUpdates();  //取消刚才输入的更æ–?br /> rs.getRow(); //得到当前行号
 rs.moveToInsertRow();  //游标¿UÕdŠ¨åˆ°è¦æ–°å¢žçš„é‚£æ¡è®°å½•ä¸Š
 rs.updateInt("id", 1);
 rs.updateString(2, "my name");
 rs.insertRow(); //插入新记�/font>


JDBC2.0提供的还有一个功能就是数据库的批量操ä½?/font>åQ?/font>

  con.setAutoCommit(false);
  Statement stmt3 = con.createStatement();
  stmt3.addBatch("insert .....");
  stmt3.addBatch("insert .....");
  int[] rows = stmt3.executeBatch();
  con.commit();

但是有一点要注意åQŒstmt3.executeBatch()他不会自动给你回滚数据操作,当你æœ?条update语句的时候,如果½W¬ä¸‰æ¡å‘生错误,那么ž®†æ— æ³•自动回滚前两条update语句的媄响,所以一定要自己手工˜q›è¡Œäº‹åŠ¡½Ž¡ç†ã€?/font>

在您的事务中使用 Savepoint
JDBC3.0中最令äh兴奋的附加特点就æ˜?Savepoint 了。有时候需要的是对事务多一点的控制åQŒè€Œä¸æ˜¯åœ¨å½“前的事务中½Ž€å•地å¯Òޝä¸€ä¸ªæ”¹å˜è¿›è¡Œå›žæ»šã€‚在JDBC3.0下,您就可以通过 Savepoint 获得˜q™ç§æŽ§åˆ¶ã€‚Savepoint 接口允许您将事务分割为各个逻辑断点åQŒä»¥æŽ§åˆ¶æœ‰å¤šž®‘事务需要回滚。看下面的代码:

conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate( "INSERT INTO authors (first_name, last_name) valueS(′Lewis� ′Carroll�");
Savepoint svpt = conn.setSavepoint("NewAuthor");
try{
 rows = stmt.executeUpdate( "UPDATE authors set type = ′fiction�WHERE last_name = ′Carroll�);
}catch(Exception e){
 conn.rollback(svpt);
 rows = stmt.executeUpdate( " update .......... other sql ");
}
conn.commit();

上面代码昄¡¤ºåQŒå½“UPDATE authorså¤ÞpÓ|的时候,¾pȝ»Ÿäº‹åŠ¡å›žæ»šUPDATE authorsçš„sql的媄响,而INSERT INTO authorsçš„sql仍然有效


‹‚€ç´¢è‡ªåЍäñ”生的关键å­?/font>
ä¸ÞZº†è§£å†³å¯¹èŽ·å–è‡ªåŠ¨äñ”生的或自动增加的关键字的值的需求,JDBC 3.0现在ž®†èŽ·å–è¿™¿Uå€¼å˜å¾—很è½ÀL¾ã€‚要¼‹®å®šä»ÖM½•所产生的关键字的å€û|¼Œåªè¦½Ž€å•地在语句的 execute() æ–ÒŽ³•中指定一个可选的标记åQŒStatement.RETURN_GENERATED_KEYSå’ŒStatement.NO_GENERATED_KEYS。在执行˜q™æ¡è¯­å¥åŽï¼Œæ‰€äº§ç”Ÿçš„关键字的值就会通过ä»? Statement 的实例方æ³?getGeneratedKeys() 来检ç´?ResultSet 而获得。ResultSet 包含了每个所产生的关键字的列。看下面代码åQ?/font>

Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO authors (first_name, last_name) valueS (′George� ′Orwell�", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
if ( rs.next() ) {
 int key = rs.getInt();
}

 参考资料: http://java.sun.com/j2se/1.5.0/docs/api/java/sql/package-summary.html



]]>
js写的Hashtable¾c?/title><link>http://www.aygfsteel.com/leopallas/archive/2006/04/29/44087.html</link><dc:creator>Leo</dc:creator><author>Leo</author><pubDate>Sat, 29 Apr 2006 12:59:00 GMT</pubDate><guid>http://www.aygfsteel.com/leopallas/archive/2006/04/29/44087.html</guid><wfw:comment>http://www.aygfsteel.com/leopallas/comments/44087.html</wfw:comment><comments>http://www.aygfsteel.com/leopallas/archive/2006/04/29/44087.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.aygfsteel.com/leopallas/comments/commentRss/44087.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/leopallas/services/trackbacks/44087.html</trackback:ping><description><![CDATA[ <div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"> <!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> <span style="color: rgb(0, 0, 0);"><</span> <span style="color: rgb(0, 0, 0);">script language</span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">javascript</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);"> type</span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">text/javascript</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">></span> <span style="color: rgb(0, 0, 0);"> <br /> <br />function Hashtable()<br />{<br />    </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash        </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> </span> <span style="color: rgb(0, 0, 255);">new</span> <span style="color: rgb(0, 0, 0);"> Object();<br />    </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">.add        </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> function(key,value){<br />                        </span> <span style="color: rgb(0, 0, 255);">if</span> <span style="color: rgb(0, 0, 0);">(typeof(key)</span> <span style="color: rgb(0, 0, 0);">!=</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">undefined</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">){<br />                            </span> <span style="color: rgb(0, 0, 255);">if</span> <span style="color: rgb(0, 0, 0);">(</span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">.contains(key)</span> <span style="color: rgb(0, 0, 0);">==</span> <span style="color: rgb(0, 0, 255);">false</span> <span style="color: rgb(0, 0, 0);">){<br />                                </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash[key]</span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);">typeof(value)</span> <span style="color: rgb(0, 0, 0);">==</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">undefined</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">?</span> <span style="color: rgb(0, 0, 255);">null</span> <span style="color: rgb(0, 0, 0);">:value;<br />                                </span> <span style="color: rgb(0, 0, 255);">return</span> <span style="color: rgb(0, 0, 0);"> </span> <span style="color: rgb(0, 0, 255);">true</span> <span style="color: rgb(0, 0, 0);">;<br />                            } </span> <span style="color: rgb(0, 0, 255);">else</span> <span style="color: rgb(0, 0, 0);"> {<br />                                </span> <span style="color: rgb(0, 0, 255);">return</span> <span style="color: rgb(0, 0, 0);"> </span> <span style="color: rgb(0, 0, 255);">false</span> <span style="color: rgb(0, 0, 0);">;<br />                            }<br />                        } </span> <span style="color: rgb(0, 0, 255);">else</span> <span style="color: rgb(0, 0, 0);"> {<br />                            </span> <span style="color: rgb(0, 0, 255);">return</span> <span style="color: rgb(0, 0, 0);"> </span> <span style="color: rgb(0, 0, 255);">false</span> <span style="color: rgb(0, 0, 0);">;<br />                        }<br />                    }<br />    </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">.remove        </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> function(key){delete </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash[key];}<br />    </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">.count        </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> function(){var i</span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);">0</span> <span style="color: rgb(0, 0, 0);">;</span> <span style="color: rgb(0, 0, 255);">for</span> <span style="color: rgb(0, 0, 0);">(var k in </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash){i</span> <span style="color: rgb(0, 0, 0);">++</span> <span style="color: rgb(0, 0, 0);">;} </span> <span style="color: rgb(0, 0, 255);">return</span> <span style="color: rgb(0, 0, 0);"> i;}<br />    </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">.items        </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> function(key){</span> <span style="color: rgb(0, 0, 255);">return</span> <span style="color: rgb(0, 0, 0);"> </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash[key];}<br />    </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">.contains    </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> function(key){ </span> <span style="color: rgb(0, 0, 255);">return</span> <span style="color: rgb(0, 0, 0);"> typeof(</span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash[key])</span> <span style="color: rgb(0, 0, 0);">!=</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">undefined</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">;}<br />    </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">.clear        </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> function(){</span> <span style="color: rgb(0, 0, 255);">for</span> <span style="color: rgb(0, 0, 0);">(var k in </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash){delete </span> <span style="color: rgb(0, 0, 255);">this</span> <span style="color: rgb(0, 0, 0);">._hash[k];}}<br /><br />}<br /><br />var a </span> <span style="color: rgb(0, 0, 0);">=</span> <span style="color: rgb(0, 0, 0);"> </span> <span style="color: rgb(0, 0, 255);">new</span> <span style="color: rgb(0, 0, 0);"> Hashtable();<br /><br />a.add(</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">aa</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">);<br />a.add(</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">bb</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">,</span> <span style="color: rgb(0, 0, 0);">2342</span> <span style="color: rgb(0, 0, 0);">);<br />a.add(</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">bb</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">,</span> <span style="color: rgb(0, 0, 0);">2342</span> <span style="color: rgb(0, 0, 0);">);<br /><br />a.remove(</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">aa</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">);<br /><br />alert(a.count());<br /><br />alert(a.contains(</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">bb</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">));<br /><br />alert(a.contains(</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">aa</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">));<br /><br />alert(a.items(</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">bb</span> <span style="color: rgb(0, 0, 0);">"</span> <span style="color: rgb(0, 0, 0);">));<br /><br /><br /></span> <span style="color: rgb(0, 0, 0);"></</span> <span style="color: rgb(0, 0, 0);">script</span> <span style="color: rgb(0, 0, 0);">></span> </div> <img src="http://ttyp.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" /> <span style="color: rgb(0, 0, 0);"> </span> <img src ="http://www.aygfsteel.com/leopallas/aggbug/44087.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/leopallas/" target="_blank">Leo</a> 2006-04-29 20:59 <a href="http://www.aygfsteel.com/leopallas/archive/2006/04/29/44087.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WEB打印分页¾c?JS)(è½?http://www.aygfsteel.com/leopallas/archive/2006/04/29/44086.htmlLeoLeoSat, 29 Apr 2006 12:57:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/04/29/44086.htmlhttp://www.aygfsteel.com/leopallas/comments/44086.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/04/29/44086.html#Feedback1http://www.aygfsteel.com/leopallas/comments/commentRss/44086.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/44086.html阅读全文

]]>
javascriptž®æŠ€å·§[转]http://www.aygfsteel.com/leopallas/archive/2006/04/29/44080.htmlLeoLeoSat, 29 Apr 2006 12:50:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/04/29/44080.htmlhttp://www.aygfsteel.com/leopallas/comments/44080.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/04/29/44080.html#Feedback2http://www.aygfsteel.com/leopallas/comments/commentRss/44080.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/44080.html阅读全文

]]>
分页的轻量实çŽ?/title><link>http://www.aygfsteel.com/leopallas/archive/2006/04/03/38791.html</link><dc:creator>Leo</dc:creator><author>Leo</author><pubDate>Sun, 02 Apr 2006 18:22:00 GMT</pubDate><guid>http://www.aygfsteel.com/leopallas/archive/2006/04/03/38791.html</guid><wfw:comment>http://www.aygfsteel.com/leopallas/comments/38791.html</wfw:comment><comments>http://www.aygfsteel.com/leopallas/archive/2006/04/03/38791.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.aygfsteel.com/leopallas/comments/commentRss/38791.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/leopallas/services/trackbacks/38791.html</trackback:ping><description><![CDATA[     摘要: ä¸?我们的项目写的一个轻量的分页API。目的在于将分页与数据查询的逻辑完全剥离。我以前看过robbin发的通过detachedCriteria实现çš?分页那片贴子åQŒé‡Œé¢æŠŠåˆ†é¡µå’Œæ•°æ®æŸ¥è¯¢ç»“合在一起了。而我觉得分开更轻量,而且替换也比较容易。但是这个实çŽîC¸­æœ‰ä¸€ä¸ªåæ¨¡å¼åQŒåœ¨é€»è¾‘中生成了代码åQŒæ— å¥ˆä¹‹ 选,ä¸ÞZº†½Ž€ä¾Ñ€‚其中字½W¦ç”Ÿæˆå¯ä»¥è‡ªå·±æ‰©å±•i18n实现åQŒåº”该非常容易。分™åµå®žçŽ°çš„æŽ¥å£åQšpackage c...  <a href='http://www.aygfsteel.com/leopallas/archive/2006/04/03/38791.html'>阅读全文</a><img src ="http://www.aygfsteel.com/leopallas/aggbug/38791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/leopallas/" target="_blank">Leo</a> 2006-04-03 02:22 <a href="http://www.aygfsteel.com/leopallas/archive/2006/04/03/38791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向Webçš„JMS应用¾pȝ»Ÿhttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32185.htmlLeoLeoThu, 23 Feb 2006 11:07:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32185.htmlhttp://www.aygfsteel.com/leopallas/comments/32185.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32185.html#Feedback0http://www.aygfsteel.com/leopallas/comments/commentRss/32185.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/32185.html

作者:朱骐

作者简�/h4>

朱骐åQŒç”·åQŒæ±Ÿè‹å—京ähåQŒè®²å¸ˆï¼Œä¸»è¦ç ”究方向åQšä¿¡æ¯ç³»¾lŸä¸Žé›†æˆæŠ€æœ¯ã€‚您可以通过qizhu003@msn.com和作者取得联¾p…R€?/p>

内容摘要


JMS面向Web的应用与面向桌面的应用相比,有特ŒDŠçš„用户环境要求åQšåŒä¸€ä¸ªæ¶ˆæ¯å¿…™å»èƒ½è¢«è‹¥òq²æœªçŸ¥çš„用户消费åQŒå› æ­¤åœ¨æ¶ˆæ¯æŽ¥æ”¶æ–¹å¿…™åÀLœ‰"接收而不¼‹®è®¤"的提交机åˆÓž¼›æœ¬æ–‡ä»¥CWNF校务¾pȝ»Ÿä¸ºå®žçŽ°æ¡ˆä¾‹ï¼Œè®¨è®ºé¢å‘Webçš„JMS应用¾pȝ»Ÿæ¶ˆæ¯æäº¤åŽŸç†åŠé‡‡ç”¨çš„å…³é”®æŠ€æœ¯ã€?/p>

消息传递是一¿Uåœ¨è½¯äšg¾l„äšg或应用之间进行分布式通信的松散耦合æ–ÒŽ³•åQŒä¸Žå„种紧密耦合通信技术(如CORBA、Java RMI、COM/DCOMåQ‰ç›¸æ¯”,不同之处在于åQšâ‘ æ¶ˆæ¯¾pȝ»Ÿæ˜¯ä¸€¿Uå¯¹½{‰å®žæ–½ï¼Œé€šä¿¡åŒæ–¹åÏx¶ˆæ¯çš„发送者和接受者都是该¾pȝ»Ÿä¸­çš„客户端,彼此不呈C/S关系åQ? ②通信双方的工作是异步的;③基于消息格式一è‡ß_¼Œé€šä¿¡åŒæ–¹åªéœ€ä¸€ä¸ªä¸­ä»‹æ¥å­˜å‚¨òq¶ç®¡ç†æ¶ˆæ¯å°±å¯ä»¥å®žçŽ°é€šä¿¡åQŒè€Œç´§å¯†è€¦åˆæŠ€æœ¯åˆ™éœ€è¦çŸ¥é“远½E‹æ–¹æ³•在本地的接口ã€? 因自íw«ç‰¹ç‚¹ï¼Œæ¶ˆæ¯ä¼ é€’技术在企业中和企业间有较广泛的应用需求ã€?/p>

JMSåQˆJava Message ServiceåQ‰æ˜¯J2EE企业òq›_°çš„Java消息服务åQŒç›®å‰ä¸»‹¹J2EE产品的JMS都实çŽîCº†å­˜å‚¨åŠŸèƒ½åQŒJMS客户端通过JMS API创徏åQŒå½¼æ­¤é—´é€šè¿‡ç›®çš„圎ͼˆDestinationåQ‰å¯¹è±¡è¿›è¡Œé€šä¿¡åQ›å¯æ˜¯JMS消息¾pȝ»Ÿå¤šè§äºŽæ¡Œé¢åº”用,而Web应用鲜见åQŒæœ¬æ–‡ä»¥½W”者开发的CWNF 校务¾pȝ»Ÿä¸ºæ¡ˆä¾‹ï¼Œè®¨è®ºé¢å‘Webçš„JMS应用¾pȝ»Ÿçš„实现原理及采用的关键技术ã€?/p>

1  é¢å‘Webçš„JMS应用¾pȝ»Ÿå®žçŽ°åŽŸç†

1.1  JMS应用¾pȝ»Ÿæ¶ˆæ¯ä¼ é€’原ç?/h4>

JMS应用¾pȝ»Ÿæœ?个部分:①JMS提供者(JMS ProvideråQ‰ï¼Œæ˜¯ä¸€ä¸ªé€»è¾‘数据存储体,òq¶æä¾›ç®¡ç†å·¥å…·å’ŒæŽ§åˆ¶ç‰ÒŽ€§ï¼›â‘¡JMS客户端,是用Java语言¾~–写的发送或接收消息的组件或应用åQ›â‘¢æ¶ˆæ¯åQŒæ˜¯ JMS客户端间被传递的承蝲信息的对象;④被½Ž¡ç†å¯¹è±¡åQŒæ˜¯¾pȝ»Ÿ½Ž¡ç†å‘˜äؓ客户端预¾|®çš„JMS对象åQŒåŒ…括目的地对象和连接工厂对象,其中目的地对象是客户端间 的消息中介。这4个部分通过JNDI相关联:½Ž¡ç†å‘˜é€šè¿‡½Ž¡ç†å·¥å…·æŠŠç›®çš„地对象和连接工厂对象绑定到一个JNDI API命名½Iºé—´ä¸­ï¼ŒJMS客户端就可以在命名空间中查找˜q™äº›å¯¹è±¡åQŒåƈ通过JMS提供者徏立与˜q™äº›å¯¹è±¡çš„逻辑˜qžæŽ¥åQŒä»Žè€Œå½¼æ­¤ä¹‹é—´å®žçŽ°é€šä¿¡åQˆå›¾1åQ‰ã€‚JMSæ”? æŒ?¿Uæ¶ˆæ¯ä¼ é€’域åQšç‚¹åˆ°ç‚¹ã€å‘å¸?订阅åQŒä¸Žä¹‹ç›¸å¯¹åº”的消息目的地对象也有2¿Uï¼šé˜Ÿåˆ—、主题ã€?/p>

1.2  Web应用的消息提交机åˆ?/h4>

通常åQŒæ— è®ºæ˜¯æ¶ˆæ¯å‘送方˜q˜æ˜¯æŽ¥æ”¶æ–¹ï¼Œæ¡Œé¢åº”用都不容许消息丢失或重复,JMS消息提交机制是基于这个要求的åQŒå®ƒä»¬ä»Žä¸åŒæ–šw¢ä¿è¯è¯¥è¦æ±‚的实现åQšâ‘ åœ? 接收æ–ÒŽŽ§åˆ¶æ¶ˆæ¯çš„¼‹®è®¤ã€‚通过¼‹®è®¤ä¿è¯ä¸€ä¸ªæŽ¥æ”¶è€…对一个消息只消费一‹Æ¡ï¼Œåœ¨éžäº‹åŠ¡æ€§çš„ä¼šè¯ä¸­ï¼Œæ¶ˆæ¯¼‹®è®¤æ–¹å¼å–决于create×××Sessionæ–ÒŽ³•½W¬äºŒ 个参数的å€û|¼›åœ¨äº‹åŠ¡æ€§ä¼šè¯ä¸­åQŒæ— è®ºç”±Bean½Ž¡ç†äº‹åŠ¡˜q˜æ˜¯ç”±Bean容器½Ž¡ç†äº‹åŠ¡åQŒæ¶ˆæ¯ç¡®è®¤éƒ½ç”±Bean容器自动完成。②在发送方指定消息的提交模式和ç”? 存期。提交模式有两种åQšPERSISTENT(½E›_®šå­˜å‚¨)å’ŒNON_PERSISTENT(非稳定存å‚?åQŒç¨³å®šå­˜å‚¨ä¿è¯åœ¨æ•…障情况下消息不会丢失;生存æœ? 军_®šä¸€ä¸ªæ¶ˆæ¯åœ¨å­˜å‚¨ä¸­ä»‹ä¸­çš„存在寿命åQŒJMS提供者会自动摧毁到期的消息。③创徏持久定阅的接收方。在发布/订阅¾pȝ»Ÿä¸­ï¼ŒæŒä¹…订阅者可以接收到在订阅者关 闭阶ŒD‰|¶ˆæ¯å‘送方发布的消息ã€?/p>

但是Web应用¾pȝ»Ÿåœ¨æ¶ˆæ¯æŽ¥æ”¶æ–¹æœ‰Webç‰ÒŽœ‰çš„用æˆïLŽ¯å¢ƒè¦æ±‚ï¼šâ‘ è‹¥òq²ä¸ªç”¨æˆ·å…Þq”¨ä¸€ä¸ªJMS客户端组ä»Óž¼Œå› æ­¤æ¶ˆæ¯ž®±åº”向一个消息接收者提交而不需¼‹? 认,å…ähœ‰å®¹å™¨è‡ªåЍ¼‹®è®¤åŠŸèƒ½çš„Bean是无法实现这一要求的;在一个组件内如果把会话设¾|®æˆäº‹åŠ¡æ€§çš„åQŒè€Œè¿™ä¸ªç»„件的容器又不å…ähœ‰äº‹åŠ¡½Ž¡ç†èƒ½åŠ›åQŒåˆ™˜q™ä¸ª¾l„äšgž®? 能做åˆ?接收而不¼‹®è®¤"åQŒåœ¨Web应用¾pȝ»Ÿä¸­åªæœ‰Servlet¾l„äšg½W¦åˆ˜q™ä¸€è¦æ±‚。②JMS客户端的消息接收者经常关闭,ä¸ÞZº†æŽ¥æ”¶åœ¨å…³é—­æœŸé—´å‘送来的消 息,消息接收者必定是åŸÞZºŽä¸»é¢˜çš„æŒä¹…定阅者,所以面向Webçš„JMS应用¾pȝ»Ÿå¿…定采用发布/订阅消息传递域ã€?/p>

2  CWNF校务¾pȝ»Ÿæ¨¡åž‹


CWNF是一个面向Webçš„JMS校务¾pȝ»ŸåQŒç”¨äºŽæ ¡å›­å‘布通知及征求意见等校务工作åQŒé€šçŸ¥åˆ†äØ“2¾c»ï¼šæ™®é€šé€šçŸ¥å’Œå¾æ±‚意见性通知ã€?/p>

该系¾lŸç”¨æˆ·åˆ†æˆ?¾c»ï¼Œç”¨æˆ·ä¸åŒåQŒå¤„理模型也不同åQŒåŸºæœ¬æƒ…å†µå¦‚ä¸‹ï¼šâ‘ å‘å¸ƒç”¨æˆøP¼Œæ‹¥æœ‰é€šçŸ¥å‘布权,向主题发布通知åQ›â‘¡¾|²åç”¨æˆ·åQŒæŸ¥é˜…通知åQŒä¹Ÿå¯å‘è¡¨å¯¹å¾æ±‚æ„è§æ€§é€šçŸ¥çš„åé¦ˆæ„è§ï¼›â‘¢åŒ¿åç”¨æˆøP¼ŒåªæŸ¥é˜…通知ã€?/p>

2.1  æ•°æ®ä¸Žæ•°æ®æµæ¨¡åž‹


¾pȝ»Ÿä¸­çš„æ•°æ®å› æ­¤æœ?¾c»ï¼šé€šçŸ¥ã€åé¦ˆã€‚接收方接收的数据将形成一个XML文档对象åQŒä»¥ä¾¿å‘å¾€Web‹¹è§ˆå™¨æ˜¾½Cºï¼›åŸÞZºŽ˜q™æ ·çš„要求,考察下面2个问题:①系¾lŸä¸­å„方之间的数据关¾p»ï¼Œâ‘¡å„æ–ÒŽ•°æ®çš„形式ã€?/p>

主要的数据关¾pÀLœ‰3个:①通知发送方与通知接收方的数据关系åQŒâ‘¡åé¦ˆå‘送方与反馈接收方的数据关¾p»ï¼Œâ‘¢é€šçŸ¥æŽ¥æ”¶æ–¹ä¸Žåé¦ˆæŽ¥æ”¶æ–¹çš„æ•°æ®å…³ç³»ã€‚(如图 2åQ‰åœ¨å‘送方åQŒæ•°æ®ï¼ˆé€šçŸ¥æˆ–反馈)是一件一件的发送,在接收方åQŒæ•°æ®ï¼ˆé€šçŸ¥æˆ–反馈)则是æ‰ÒŽŽ¥æ”Óž¼Œæ˜¯å¯¹åº”发送方数据的集合,因此在发送方没有必要把数据直æŽ? 加工成XML文档对象形式åQŒåªè¦ç”Ÿæˆèƒ½æž„成XML文档对象的元素对象即可;而通知接收方与反馈接收方的数据关系则是åQšæ¯ä¸€æ¡å¾æ±‚æ„è§æ€§é€šçŸ¥éƒ½æœ‰ç›¸å…³çš„ä¸€ä¸? 反馈集合ã€?/p>

¾pȝ»Ÿçš„æ•°æ®æµæ¨¡åž‹å¦‚下åQ?br> ①通知发送方åQšè¡¨å•数据→XML元素åQˆé€šçŸ¥åQ‰â†’主题(存储)
②通知接收方:主题(存储)→XML元素åQˆé€šçŸ¥åQ‰â†’XML文档åQˆé€šçŸ¥åQ‰â†’XSL昄¡¤ºåQˆå«è¡¨å•åQ?br> ③通知接收方到反馈接收æ–? XSL昄¡¤ºåQˆå«è¡¨å•åQ‰â†’主题åQˆå­˜å‚¨ï¼‰
④反馈接收方åQšä¸»é¢?存储)→XML元素åQˆåé¦ˆï¼‰â†’XML文档åQˆåé¦ˆï¼‰â†’XSL昄¡¤ºåQˆå«è¡¨å•åQ?br> ⑤反馈发送方åQšè¡¨å•数据→XML元素åQˆåé¦ˆï¼‰â†’主é¢?存储)

2.2  ¾l„äšg模型


¾pȝ»Ÿ¾l„äšg模型如图3åQšä¸»é¢˜CWNFTopic是消息传递中介,NoticerServlet¾l„äšg向发布用户发送表单,òq¶ä»Žè¡¨å•接收数据åQŒç„¶åŽç”Ÿæˆ? XML元素对象åQŒè¯¥å…ƒç´ å¯¹è±¡å’Œå…¶å®ƒä¸€äº›æ•°æ®è¢«ä½œäؓ参数调用PublisherBean¾l„äšgæ–ÒŽ³•åQŒå‘ä¸»é¢˜å‘é€ä»¥è¯¥å…ƒç´ å¯¹è±¡äØ“æ¶ˆæ¯ä½“çš„æ¶ˆæ¯åQ? ReaderServlet¾l„äšg处理¾|²åç”¨æˆ·å’ŒåŒ¿åç”¨æˆähŸ¥é˜…通知的业务,它从表单获得用户ž®†æŸ¥é˜…什么方面通知的有关信息后åQŒä¾¿ä½¿ç”¨receiveæ–ÒŽ³•限时 é˜Õd¡žåœîC»Žä¸»é¢˜æŽ¥æ”¶æ¶ˆæ¯òq¶å¯¹æ¶ˆæ¯˜q›è¡Œ½{›é€‰ï¼ŒæŠŠç­›é€‰å‡ºçš„è‹¥òq²æ¶ˆæ¯çš„æ¶ˆæ¯ä½“取出,然后加工成XML文档对象åQˆæ ¹å…ƒç´ æ˜¯é€šçŸ¥é›†ï¼‰åQŒæœ€åŽè¾“出ã€? FeedbackerPubServlet用于反馈发送方的业务处理,功能与NoticerServletç›æ€¼¼åQ? FeedbackerSubServlet用于反馈接收方的业务处理åQŒåŠŸèƒ½ä¸ŽReaderServletç›æ€¼¼åQ›PublisherBean¾l„äšgè¢? NoticerServlet¾l„äšgå’ŒFeedbackerPubServlet¾l„äšg调用åQŒç”¨äºŽå‘送消息,容器½Ž¡ç†å‘送事务,å…ähœ‰å¾ˆé«˜çš„可靠性ã€?/p>

3  å…³é”®çš„实现技æœ?/h4>

3.1  JDOM建立、输出XML文档


JDOM是一个开放源代码的纯Java树式APIåQŒç”¨äºŽåˆ†æžã€å¾ç«‹ã€å¤„理和序列化XML文档。在数据‹¹æ¨¡åž‹ä¸­åQŒXML元素和XML文档都由JDOM API建立åQŒåœ¨å‘送方åQŒé€šè¿‡ç”¨æˆ·æäº¤çš„表单取得名/值对若干åQŒè¿™äº›æ•°æ®ç»˜q‡JDOMæ–ÒŽ³•处理生成XML元素对象åQŒå…ƒç´ å¯¹è±¡è¢«ä½œäؓ消息的消息体发往主题å­? 储;在接收方åQŒæŒä¹…订阅者接收到若干XML元素对象后,¾l§ç®‹é€šè¿‡JDOMæ–ÒŽ³•建立XML文档对象。且XML文档向Web‹¹è§ˆå™¨è¾“å‡ÞZ¹Ÿä¾èµ–于JDOMçš? XMLOutputte对象æ–ÒŽ³•åQ?/p>

XMLOutputter serializer=new XMLOutputter();

PrintWriter out
=response.getWriter();    // out æ˜¯ServletResponse的输出流对象
serializer.output(xmldoc,out);            //通过out把XML文档输出到页é?/span>


3.2  XSL定义XML文档昄¡¤ºæ ·å¼


XSL是可扩展的样式单语言åQŒé€šçŸ¥é›†çš„XML文档和反馈集的XML文档都有相关的XSL文档军_®šå…‰™¡µé¢æ˜¾½Cºï¼Œå¦‚通知集XML文档的XSL样式定义如下åQ?/p>

<?xml version="1.0" encoding="GBK"?>
<xsl:stylesheet>
<xsl:template match="/">

<HTML>
<BODY>

<DIV><xsl:apply-templates select="通知é›?/></DIV>    
</BODY>
</HTML>

</xsl:template>
<xsl:template match="通知é›?>
<xsl:for-each select="通知">

</xsl:for-each>
</xsl:template>
</xsl:stylesheet> 

3.3  Servlet间数据的传é€?/h4>

3.3.1  æ³¨å†Œ/ç™Õd½•


用户的一些处理工作需要注å†?ç™Õd½•后才能进行,因此注册/ç™Õd½•的获准信息必™å»èƒ½åœ¨æœ‰å…³Servlet¾l„äšg之间传递。ServletContext 对象可设¾|®å’Œè¯Õd–属性,使不同Servletä¹‹é—´ç›æ€º’通信åQŒåœ¨¾pȝ»Ÿä¸­è¢«ç”¨äºŽæœ‰å…³¾l„äšg对用戯‚ín份的验证ã€?/p>

3.3.2  é€šçŸ¥ä¸Žåé¦ˆçš„æ•°æ®å…Œ™”


每一条征求意见性通知都有一个相兌™”的反馈集合,兌™”可通过讄¡½®æ¶ˆæ¯å±žæ€§å®žçŽ°ã€‚JMS消息åQˆåŒ…括通知¾cÀL¶ˆæ¯ï¼‰éƒ½æœ‰¾pȝ»Ÿ¾U§JMSMessageIDå±? 性,其值是唯一的,可用于表征每一条征求意见性通知åQŒå› æ­¤å¯¹ä»ÖM½•反馈消息也可以设¾|®ä¸€ä¸ªåº”用çñ”属性(CWNF中是FeedbackSNåQ‰ï¼Œè®©å®ƒå–与之相å…? 联的征求意见性通知的JMSMessageID属性倹{€‚这样就建立了两者间的数据关联ã€?/p>

因此数据‹¹æ¨¡åž?③通知接收方到反馈接收æ–? XSL昄¡¤ºåQˆå«è¡¨å•åQ‰â†’主题åQˆå­˜å‚¨ï¼‰"的实现流½E‹å¦‚下:用户在页面上选择一条征求意见性通知后,该通知的JMSMessageID属性值将被传递给 FeedbackerSubServlet¾l„äšgåQŒè¯¥¾l„äšgž®†ä‹É用这个属性值去匚w…ä»Žä¸»é¢˜å–出的反馈消息的FeedbackSN属性,从而筛选出相关联的反馈 消息ã€?/p>

那么一条征求意见性通知的JMSMessageID属性值又如何传递给FeedbackerSubServlet¾l„äšg呢?通过 ServletContext对象只能传递可预知信息åQŒCWNF的做法是åQšç”±XSL为每一条征求意见性通知讄¡½®ä¸€ä¸ªç‹¬ç«‹çš„表单åQŒåƈ把该通知çš? JMSMessageID属性值写在表单的TEXTAREA元素框内åQŒè¿™æ ïL”¨æˆ·åœ¨è¡¨å•上选择一条征求意见性通知后,该通知的JMSMessageID属æ€? 值就随表单一èµähäº¤ç»™FeedbackerSubServlet¾l„äšg。XSL有关代码如下åQ?/p>

<xsl:if test="string(意见反馈)='on'">
<FORM method="post" action="http://localhost:6888/Feedbacker/servlet
/FeedbackerSubServlet"
>
<BUTTON type="submit">意见反馈</BUTTON>
<TEXTAREA name="序列å? rows="1" cols="40">
<xsl:value-of select="序列å?/>
</TEXTAREA>
</FORM>
</xsl:if>

4  ¾l“束è¯?/h4>

JMS应用¾pȝ»Ÿä¸Žæ•°æ®åº“¾pȝ»Ÿæœ‰ç›¸ä¼¼æ€§ï¼Œä»Žæ•°æ®æ–¹é¢çœ‹åQŒJMS消息体的数据¾cÕdž‹æ”¯æŒæ–‡æœ¬å’Œå¯¹è±¡ï¼Œæ‰€ä»¥JMS更灵‹z»ï¼Œä¸ŽXML集成应用的空间更大;但从 ½Ž¡ç†ä¸Šçœ‹åQŒJMS Provider向管理员提供的管理功能远˜qœä½ŽäºŽDBMS提供的管理功能,因此在面向Web的应用中åQŒJMS宜作ä¸ÞZ¸­ž®æµé‡ã€ç®¡ç†å‘˜å‚与度较低的信息¾pȝ»Ÿ 解决æ–ÒŽ¡ˆã€?br>

转蝲自:http://gceclub.sun.com.cn/yuanchuang/2004_Q4/jms.html



]]>Java虚拟机的深入研究http://www.aygfsteel.com/leopallas/archive/2006/02/23/32182.htmlLeoLeoThu, 23 Feb 2006 11:00:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32182.htmlhttp://www.aygfsteel.com/leopallas/comments/32182.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32182.html#Feedback0http://www.aygfsteel.com/leopallas/comments/commentRss/32182.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/32182.html

作者:刘学­‘?

1  Java技术与Java虚拟æœ?/b>

说è“vJavaåQŒäh们首先想到的是Java¾~–程语言åQŒç„¶è€Œäº‹å®žä¸ŠåQŒJava是一¿UæŠ€æœ¯ï¼Œå®ƒç”±å››æ–¹é¢ç»„æˆ? Java¾~–程语言、Java¾cÀL–‡ä»¶æ ¼å¼ã€Java虚拟机和Java应用½E‹åºæŽ¥å£(Java API)。它们的关系如下图所½Cºï¼š

å›?  Java四个斚w¢çš„å…³¾p?/p>

˜qè¡ŒæœŸçŽ¯å¢ƒä»£è¡¨ç€Javaòq›_°åQŒå¼€å‘äh员编写Java代码(.javaæ–‡äšg)åQŒç„¶åŽå°†ä¹‹ç¼–译成字节ç ?.class æ–‡äšg)。最后字节码被装入内存,一旦字节码˜q›å…¥è™šæ‹Ÿæœºï¼Œå®ƒå°±ä¼šè¢«è§£é‡Šå™¨è§£é‡Šæ‰§è¡Œï¼Œæˆ–者是被即时代码发生器有选择的è{换成机器码执行。从上图也可以看å‡? Javaòq›_°ç”±Java虚拟机和Java应用½E‹åºæŽ¥å£æ­å¾åQŒJava语言则是˜q›å…¥˜q™ä¸ªòq›_°çš„通道åQŒç”¨Java语言¾~–写òq¶ç¼–译的½E‹åºå¯ä»¥˜qè¡Œåœ¨è¿™ä¸ªåã^åîC¸Šã€? ˜q™ä¸ªòq›_°çš„结构如下图所½Cºï¼š

在Javaòq›_°çš„结构中, 可以看出åQŒJava虚拟æœ?JVM) 处在核心的位¾|®ï¼Œæ˜¯ç¨‹åºä¸Žåº•层操作¾pȝ»Ÿå’Œç¡¬ä»¶æ— å…³çš„关键。它的下æ–ÒŽ˜¯¿UÀL¤æŽ¥å£åQŒç§»æ¤æŽ¥å£ç”±ä¸¤éƒ¨åˆ†ç»„成:适配器和Java操作¾pȝ»Ÿ, 其中依赖于åã^台的部分¿UîCؓ适配器;JVM 通过¿UÀL¤æŽ¥å£åœ¨å…·ä½“çš„òq›_°å’Œæ“ä½œç³»¾lŸä¸Šå®žçްåQ›åœ¨JVM 的上æ–ÒŽ˜¯Java的基本类库和扩展¾cÕdº“以及它们的APIåQ?利用Java API¾~–写的应用程åº?application) 和小½E‹åº(Java applet) 可以在ä“Q何Javaòq›_°ä¸Šè¿è¡Œè€Œæ— éœ€è€ƒè™‘底层òq›_°, ž®±æ˜¯å› äؓ有Java虚拟æœ?JVM)实现了程序与操作¾pȝ»Ÿçš„分¼›»ï¼Œä»Žè€Œå®žçŽîCº†Java çš„åã^台无å…Ïx€§ã€?

那么到底什么是Java虚拟æœ?JVM)呢?通常我们谈论JVMæ—Óž¼Œæˆ‘们的意思可能是åQ?

  1. 对JVM规范的的比较抽象的说明;
  2. 对JVM的具体实玎ͼ›
  3. 在程序运行期间所生成的一个JVM实例�

对JVM规范的的抽象说明是一些概å¿ëŠš„集合åQŒå®ƒä»¬å·²¾låœ¨ä¹¦ã€ŠThe Java Virtual Machine Specification》(《Javaè™šæ‹Ÿæœø™§„范》)中被详细地描˜qîCº†åQ›å¯¹JVM的具体实现要么是软äšgåQŒè¦ä¹ˆæ˜¯è½¯äšg和硬件的¾l„合åQŒå®ƒå·²ç»è¢«è®¸å¤šç”Ÿäº§åŽ‚ 商所实现åQŒåƈ存在于多¿Uåã^åîC¹‹ä¸Šï¼›˜qè¡ŒJava½E‹åºçš„ä“Q务由JVM的运行期实例单个承担。在本文中我们所讨论的Java虚拟æœ?JVM)主要针对½W¬ä¸‰¿Uæƒ… 况而言。它可以被看成一个想象中的机器,在实际的计算æœÞZ¸Šé€šè¿‡è½¯äšg模拟来实玎ͼŒæœ‰è‡ªå·±æƒ³è±¡ä¸­çš„硬ä»Óž¼Œå¦‚处理器、堆栈、寄存器½{‰ï¼Œ˜q˜æœ‰è‡ªå·±ç›¸åº”的指令系¾lŸã€?/p>

JVM在它的生存周期中有一个明¼‹®çš„ä»ÕdŠ¡åQŒé‚£ž®±æ˜¯˜qè¡ŒJava½E‹åºåQŒå› æ­¤å½“Java½E‹åºå¯åŠ¨çš„æ—¶å€™ï¼Œž®×ƒñ”生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面我们从JVM的体¾pȝ»“构和它的˜qè¡Œ˜q‡ç¨‹˜q™ä¸¤ä¸ªæ–¹é¢æ¥å¯¹å®ƒ˜q›è¡Œæ¯”较深入的研½I¶ã€?

2  Java虚拟机的体系¾l“æž„

刚才已经提到åQŒJVM可以ç”׃¸åŒçš„åŽ‚å•†æ¥å®žçŽ°ã€‚ç”±äºŽåŽ‚å•†çš„ä¸åŒå¿…ç„¶å¯ÆD‡´JVM在实çŽîC¸Šçš„一些不同,然而JVM˜q˜æ˜¯å¯ä»¥å®žçŽ°è·¨åã^台的ç‰ÒŽ€§ï¼Œ˜q™å°±è¦å½’功于设计JVM时的体系¾l“构了ã€?/p>

我们知道åQŒä¸€ä¸ªJVM实例的行ä¸ÞZ¸å…‰æ˜¯å®ƒè‡ªå·Þqš„事,˜q˜æ¶‰åŠåˆ°å®ƒçš„子系¾lŸã€å­˜å‚¨åŒºåŸŸã€æ•°æ®ç±»åž‹å’ŒæŒ‡ä×o˜q™äº›éƒ¨åˆ†åQŒå®ƒä»¬æ ˜qîCº†JVM的一个抽象的内部体系¾l“æž„åQŒå…¶ç›®çš„不光规定实现JVM时它内部的体¾pȝ»“构,更重要的是提供了一¿Uæ–¹å¼ï¼Œç”¨äºŽä¸¥æ ¼å®šä¹‰å®žçŽ°æ—¶çš„å¤–éƒ¨è¡ŒäØ“ã€‚æ¯ä¸? JVM都有两种机制åQŒä¸€ä¸ªæ˜¯è£…蝲å…ähœ‰åˆé€‚名¿U°çš„¾c?¾cÀLˆ–是接å?åQŒå«åšç±»è£…蝲子系¾lŸï¼›å¦å¤–的一个负责执行包含在已装载的¾cÀLˆ–接口中的指ä×oåQŒå«åšè¿è¡Œå¼•擎ã€? 每个JVM又包括方法区、堆、Java栈、程序计数器和本地方法栈˜q™äº”个部分,˜q™å‡ ä¸ªéƒ¨åˆ†å’Œ¾c»è£…载机制与˜qè¡Œå¼•擎机制一èµïL»„成的体系¾l“æž„å›¾äØ“åQ?/p>

å›?  JVM的体¾pȝ»“æž?/p>

JVM的每个实例都有一个它自己的方法域和一个堆åQŒè¿è¡ŒäºŽJVM内的所有的¾U¿ç¨‹éƒ½å…±äº«è¿™äº›åŒºåŸŸï¼›å½“虚拟机装蝲¾cÀL–‡ä»? 的时候,它解析其中的二进制数据所包含的类信息åQŒåƈ把它们放到方法域中;当程序运行的时候,JVM把程序初始化的所有对象置于堆上;而每个线½E‹åˆ›å»ºçš„æ—? 候,都会拥有自己的程序计数器和Java栈,其中½E‹åºè®¡æ•°å™¨ä¸­çš„值指向下一条即ž®†è¢«æ‰§è¡Œçš„æŒ‡ä»¤ï¼Œ¾U¿ç¨‹çš„Javaæ ˆåˆ™å­˜å‚¨ä¸ø™¯¥¾U¿ç¨‹è°ƒç”¨Javaæ–ÒŽ³•的状态; 本地æ–ÒŽ³•调用的状态被存储在本地方法栈åQŒè¯¥æ–ÒŽ³•栈依赖于具体的实现ã€?/p>

下面分别对这几个部分˜q›è¡Œè¯´æ˜Žã€?/p>

执行引擎处于JVM的核心位¾|®ï¼Œåœ¨Javaè™šæ‹Ÿæœø™§„范中åQŒå®ƒçš„行为是由指令集所军_®šçš„。尽½Ž¡å¯¹äºŽæ¯æ¡æŒ‡ä»¤ï¼Œè§„范很详 ¾l†åœ°è¯´æ˜Žäº†å½“JVM执行字节码遇到指令时åQŒå®ƒçš„实现应该做什么,但对于怎么做却­a€ä¹‹ç”šž®‘ã€‚Java虚拟机支持大¾U?48个字节码。每个字节码执行一¿UåŸºæœ? çš„CPU˜qç®—,例如,把一个整数加到寄存器,子程序è{¿Uȝ­‰ã€‚Java指ä×o集相当于Java½E‹åºçš„æ±‡¾~–语­a€ã€?/p>

Java指ä×o集中的指令包含一个单字节的操作符,用于指定要执行的操作,˜q˜æœ‰0个或多个操作æ•?提供操作所需的参数或数据。许多指令没有操作数,仅由一个单字节的操作符构成ã€?/p>

虚拟机的内层循环的执行过½E‹å¦‚ä¸? 
do{
取一个操作符字节;
æ ÒŽ®æ“ä½œ½W¦çš„值执行一个动ä½?
}while(½E‹åºæœªç»“æ?

ç”׃ºŽæŒ‡ä×o¾pȝ»Ÿçš„简单æ€?使得虚拟机执行的˜q‡ç¨‹ååˆ†½Ž€å?从而有利于提高执行的效率。指令中操作数的数量和大ž®æ˜¯ç”±æ“ä½œç¬¦å†›_®šçš„。如果操作数比一个字节大,那么它存储的™åºåºæ˜¯é«˜ä½å­—节优先。例å¦?一ä¸?6位的参数存放时占用两个字èŠ?å…¶å€égØ“:

½W¬ä¸€ä¸ªå­—èŠ?256+½W¬äºŒä¸ªå­—节字节码ã€?

指ä×o‹¹ä¸€èˆ¬åªæ˜¯å­—节对齐的。指令tableswitchå’Œlookup是例å¤?在这两条指ä×o内部要求强制çš?字节边界寚w½ã€?

对于本地æ–ÒŽ³•接口åQŒå®žçްJVMòq¶ä¸è¦æ±‚一定要有它的支持,甚至可以完全没有。Sun公司实现Java本地æŽ? å?JNI)是出于可¿UÀL¤æ€§çš„考虑åQŒå½“然我们也可以设计出其它的本地接口来代替Sun公司的JNI。但是这些设计与实现是比较复杂的事情åQŒéœ€è¦ç¡®ä¿åžƒåœ‘Ö›ž 收器不会ž®†é‚£äº›æ­£åœ¨è¢«æœ¬åœ°æ–ÒŽ³•调用的对象释放掉ã€?

Java的堆是一个运行时数据åŒ?¾cȝš„实例(对象)从中分配½Iºé—´åQŒå®ƒçš„管理是由垃圑֛žæ”¶æ¥è´Ÿè´£çš?不给½E‹åºå‘˜æ˜¾å¼é‡Šæ”‘Ö¯¹è±¡çš„能力。Java不规定具体ä‹É用的垃圾回收½Ž—法,可以æ ÒŽ®¾pȝ»Ÿçš„需求ä‹É用各¿Uå„æ ïLš„½Ž—法ã€?

Javaæ–ÒŽ³•åŒÞZ¸Žä¼ ç»Ÿè¯­è¨€ä¸­çš„¾~–译后代码或是Unix˜q›ç¨‹ä¸­çš„æ­£æ–‡ŒD늱»ä¼¹{€‚它保存æ–ÒŽ³•代码(¾~–译后的 java代码)和符可‚¡¨ã€‚在当前的Java实现ä¸?æ–ÒŽ³•代码不包括在垃圾回收堆中,但计划在ž®†æ¥çš„版本中实现。每个类文äšg包含了一个Java¾cÀLˆ–一ä¸? Java界面的编译后的代码。可以说¾cÀL–‡ä»¶æ˜¯Javaè¯­è¨€çš„æ‰§è¡Œä»£ç æ–‡ä»¶ã€‚äØ“äº†ä¿è¯ç±»æ–‡äšgçš„åã^台无å…Ïx€?Javaè™šæ‹Ÿæœø™§„范中对类文äšg的格式也作了详细çš? 说明。其具体¾l†èŠ‚è¯·å‚è€ƒSun公司的Javaè™šæ‹Ÿæœø™§„范ã€?

Java虚拟机的寄存器用于保存机器的˜qè¡Œçжæ€?与微处理器中的某些专用寄存器¾cÖM¼¼ã€‚Java虚拟机的寄存器有四种:

  1. pc: Java½E‹åºè®¡æ•°å™¨ï¼›
  2. optop: 指向操作数栈™å¶ç«¯çš„æŒ‡é’ˆï¼›
  3. frame: 指向当前执行æ–ÒŽ³•的执行环境的指针åQ›ã€?
  4. vars: 指向当前执行æ–ÒŽ³•的局部变量区½W¬ä¸€ä¸ªå˜é‡çš„æŒ‡é’ˆã€?

在上˜qîC½“¾pȝ»“构图中,我们所说的是第一¿Uï¼Œå³ç¨‹åºè®¡æ•°å™¨åQŒæ¯ä¸ªçº¿½E‹ä¸€æ—¦è¢«åˆ›å¾ž®±æ‹¥æœ‰äº†è‡ªå·±çš„程序计数器。当¾U¿ç¨‹æ‰§è¡ŒJavaæ–ÒŽ³•的时候,它包含该¾U¿ç¨‹æ­£åœ¨è¢«æ‰§è¡Œçš„æŒ‡ä×o的地址。但是若¾U¿ç¨‹æ‰§è¡Œçš„æ˜¯ä¸€ä¸ªæœ¬åœ°çš„æ–ÒŽ³•åQŒé‚£ä¹ˆç¨‹åºè®¡æ•°å™¨çš„值就不会被定义ã€?

Java虚拟机的栈有三个区域:局部变量区、运行环境区、操作数区�/p>

局部变量区

每个Javaæ–ÒŽ³•使用一个固定大ž®çš„局部变量集。它们按照与vars寄存器的字偏¿U»é‡æ¥å¯»å€ã€‚局部变量都æ˜?2ä½? 的。长整数和双¾_‘Öº¦‹¹®ç‚¹æ•°å æ®äº†ä¸¤ä¸ªå±€éƒ¨å˜é‡çš„½Iºé—´,却按照第一个局部变量的索引来寻址ã€?例如,一个具有烦引n的局部变é‡?如果是一个双¾_‘Öº¦‹¹®ç‚¹æ•?é‚? 么它实际占据了烦引nå’Œn+1所代表的存储空é—?è™šæ‹Ÿæœø™§„èŒƒåÆˆä¸è¦æ±‚åœ¨å±€éƒ¨å˜é‡ä¸­çš?4位的值是64ä½å¯¹é½çš„ã€‚è™šæ‹Ÿæœºæä¾›äº†æŠŠå±€éƒ¨å˜é‡ä¸­çš„å€ÆD£…载到操作æ•? 栈的指ä×o,也提供了把操作数栈中的值写入局部变量的指ä×oã€?/p>

˜qè¡ŒçŽ¯å¢ƒåŒ?/b>

在运行环境中包含的信息用于动态链�正常的方法返回以及异常捕捉�

动态链�/b>

˜qè¡ŒçŽ¯å¢ƒåŒ…æ‹¬å¯ÒŽŒ‡å‘当前类和当前方法的解释器符可‚¡¨çš„æŒ‡é’?用于支持æ–ÒŽ³•代码的动态链接。方法的class æ–‡äšg代码在引用要调用的方法和要访问的变量时ä‹É用符受÷€‚动态链接把½W¦å·å½¢å¼çš„æ–¹æ³•调用翻译成实际æ–ÒŽ³•调用,装蝲必要的类以解释还没有定义的符å?òq¶æŠŠå˜é‡ 讉K—®¾˜»è¯‘成与˜q™äº›å˜é‡˜qè¡Œæ—¶çš„存储¾l“构相应的偏¿UÕdœ°å€ã€‚动态链接方法和变量使得æ–ÒŽ³•中ä‹É用的其它¾cȝš„变化不会影响到本½E‹åºçš„代码ã€?

正常的方法返�/b>

如果当前æ–ÒŽ³•正常地结束了,在执行了一条具有正¼‹®ç±»åž‹çš„˜q”回指ä×oæ—?调用的方法会得到一个返回倹{€‚执行环境在正常˜q”回的情况下用于恢复调用者的寄存å™?òq¶æŠŠè°ƒç”¨è€…çš„½E‹åºè®¡æ•°å™¨å¢žåŠ ä¸€ä¸ªæ°å½“çš„æ•°å€?以蟩˜q‡å·²æ‰§è¡Œ˜q‡çš„æ–ÒŽ³•调用指ä×o,然后在调用者的执行环境中ç‘ô¾l­æ‰§è¡Œä¸‹åŽ…R€?

异常捕捉

异常情况在Java中被¿UîC½œError(错误)或Exception(异常),是Throwable¾cȝš„子类,在程序中的原因是:①动态链接错,如无法找到所需的classæ–‡äšg。②˜qè¡Œæ—‰™”™,如对一个空指针的引用。程序ä‹É用了throw语句ã€?

当异常发生时,Java虚拟机采取如下措�

  • ‹‚€æŸ¥ä¸Žå½“前æ–ÒŽ³•相联¾pȝš„catch子句表。每个catch子句包含其有效指令范å›?能够处理的异常类åž?以及处理异常的代码块地址ã€?
  • 与异常相匚w…çš„catch子句应该½W¦åˆä¸‹é¢çš„æ¡ä»?造成异常的指令在其指令范围之å†?发生的异常类型是其能处理的异常类型的子类型。如 果找åˆîCº†åŒšw…çš„catch子句,那么¾pȝ»Ÿè½¬ç§»åˆ°æŒ‡å®šçš„异常处理块处执行;如果没有扑ֈ°å¼‚常处理å?重复å¯ÀL‰¾åŒšw…çš„catch子句的过½E?直到当前æ–ÒŽ³•的所 有嵌套的catch子句都被‹‚€æŸ¥è¿‡ã€?
  • ç”׃ºŽè™šæ‹ŸæœÞZ»Ž½W¬ä¸€ä¸ªåŒ¹é…çš„catch子句处ç‘ô¾l­æ‰§è¡?所以catch子句表中的顺序是很重要的。因为Java代码是结构化çš?å› æ­¤æ€? 可以把某个方法的所有的异常处理器都按序排列åˆîC¸€ä¸ªè¡¨ä¸?对ä“Q意可能的½E‹åºè®¡æ•°å™¨çš„å€?都可以用¾U¿æ€§çš„™åºåºæ‰‘Öˆ°åˆé€‚的异常处理å?以处理在该程序计数器å€? 下发生的异常情况ã€?
  • 如果找不到匹配的catch子句,那么当前æ–ÒŽ³•得到一ä¸?未截获异å¸?çš„ç»“æžœåÆˆ˜q”回到当前方法的调用è€?好像异常刚刚在其调用者中å? 生一栗÷€‚如果在调用者中仍然没有扑ֈ°ç›¸åº”的异常处理块,那么˜q™ç§é”™è¯¯ž®†è¢«ä¼ æ’­ä¸‹åŽ»ã€‚å¦‚æžœé”™è¯¯è¢«ä¼ æ’­åˆ°æœ€™å¶å±‚,那么¾pȝ»Ÿž®†è°ƒç”¨ä¸€ä¸ªç¼ºçœçš„异常处理块ã€?

操作数栈�/b>

机器指ä×o只从操作数栈中取操作æ•?对它们进行操ä½?òq¶æŠŠ¾l“æžœ˜q”回到栈中。选择栈结构的原因æ˜?在只有少量寄存器或非 通用寄存器的机器(如Intel486)ä¸?ä¹Ÿèƒ½å¤Ÿé«˜æ•ˆåœ°æ¨¡æ‹Ÿè™šæ‹Ÿæœºçš„è¡ŒäØ“ã€‚æ“ä½œæ•°æ ˆæ˜¯32位的。它用于¾l™æ–¹æ³•传递参æ•?òq¶ä»Žæ–ÒŽ³•接收¾l“æžœ,也用于支持操 作的参数,òq¶ä¿å­˜æ“ä½œçš„¾l“果。例å¦?iadd指ä×ož®†ä¸¤ä¸ªæ•´æ•°ç›¸åŠ ã€‚ç›¸åŠ çš„ä¸¤ä¸ªæ•´æ•°åº”è¯¥æ˜¯æ“ä½œæ•°æ ˆé¡¶çš„ä¸¤ä¸ªå­—ã€‚è¿™ä¸¤ä¸ªå­—æ˜¯ç”±å…ˆå‰çš„æŒ‡ä×o压进堆栈的。这两个æ•? 数将从堆栈弹出、相åŠ?òq¶æŠŠ¾l“果压回到操作数栈中ã€?

每个原始数据¾cÕdž‹éƒ½æœ‰ä¸“门的指令对它们˜q›è¡Œå¿…须的操作。每个操作数在栈中需要一个存储位¾|?除了long å’Œdoubleåž?它们需要两个位¾|®ã€‚操作数只能被适用于其¾cÕdž‹çš„æ“ä½œç¬¦æ‰€æ“ä½œã€‚例å¦?压入两个int¾cÕdž‹çš„æ•°,如果把它们当作是一个long¾cÕdž‹çš„æ•°åˆ? 是非法的。在Sun的虚拟机实现ä¸?˜q™ä¸ªé™åˆ¶ç”±å­—节码验证器强制实行。但æ˜?有少数操ä½?操作½W¦dupeå’Œswap),ç”¨äºŽå¯¹è¿è¡Œæ—¶æ•°æ®åŒø™¿›è¡Œæ“ä½œæ—¶æ˜¯ä¸ 考虑¾cÕdž‹çš„ã€?

本地æ–ÒŽ³•栈,当一个线½E‹è°ƒç”¨æœ¬åœ°æ–¹æ³•æ—¶åQŒå®ƒž®×ƒ¸å†å—到虚拟机关于¾l“构和安全限制方面的¾U¦æŸåQŒå®ƒæ—¢å¯ä»¥è®¿é—? 虚拟机的˜qè¡ŒæœŸæ•°æ®åŒºåQŒä¹Ÿå¯ä»¥ä½¿ç”¨æœ¬åœ°å¤„理器以及ä“Q何类型的栈。例如,本地栈是一个C语言的栈åQŒé‚£ä¹ˆå½“C½E‹åºè°ƒç”¨C函数æ—Óž¼Œå‡½æ•°çš„参æ•îC»¥æŸç§™åºåºè¢«åŽ‹å…? 栈,¾l“果则返回给调用函数。在实现Java虚拟机时åQŒæœ¬åœ°æ–¹æ³•接口ä‹É用的是C语言的模型栈åQŒé‚£ä¹ˆå®ƒçš„æœ¬åœ°æ–¹æ³•栈的调度与使用则完全与C语言的栈相同ã€?/p>

3  Java虚拟机的˜qè¡Œ˜q‡ç¨‹

上面对虚拟机的各个部分进行了比较详细的说明,下面通过一个具体的例子来分析它的运行过½E‹ã€?/p>

虚拟机通过调用某个指定¾cÈš„æ–ÒŽ³•main启动åQŒä¼ é€’ç»™main一个字½W¦ä¸²æ•°ç»„参数åQŒä‹É指定的类被装载,同时链接该类所使用的其它的¾cÕdž‹åQŒåƈ且初始化它们。例如对于程序:

class HelloApp 
{
    
public static void main(String[] args) 
    {
        System.out.println(
"Hello World!"); 
        
for (int i = 0; i < args.length; i++ )
        {
            System.out.println(args[i]);
        }
    }
}

¾~–译后在命ä×o行模式下键入åQ?java HelloApp run virtual machine

ž®†é€šè¿‡è°ƒç”¨HelloApp的方法main来启动java虚拟机,传递给main一个包含三个字½W¦ä¸²"run"ã€?virtual"ã€?machine"的数¾l„。现在我们略˜q°è™šæ‹Ÿæœºåœ¨æ‰§è¡ŒHelloApp时可能采取的步骤ã€?

开始试图执行类HelloAppçš„mainæ–ÒŽ³•åQŒå‘现该¾cÕdƈ没有被装载,也就是说虚拟机当前不包含该类的二 ˜q›åˆ¶ä»£è¡¨åQŒäºŽæ˜¯è™šæ‹Ÿæœºä½¿ç”¨ClassLoader试图å¯ÀL‰¾˜q™æ ·çš„二˜q›åˆ¶ä»£è¡¨ã€‚如果这个进½E‹å¤±è´¥ï¼Œåˆ™æŠ›å‡ÞZ¸€ä¸ªå¼‚常。类被装载后同时在mainæ–ÒŽ³•被调用之 前,必须对类HelloApp与其它类型进行链接然后初始化。链接包含三个阶ŒDµï¼š‹‚€éªŒï¼Œå‡†å¤‡å’Œè§£æžã€‚检验检查被装蝲的主¾cȝš„½W¦å·å’Œè¯­ä¹‰ï¼Œå‡†å¤‡åˆ™åˆ›å»ºç±»æˆ–接 å£çš„é™æ€åŸŸä»¥åŠæŠŠè¿™äº›åŸŸåˆå§‹åŒ–äØ“æ ‡å‡†çš„é»˜è®¤å€û|¼Œè§£æžè´Ÿè´£‹‚€æŸ¥ä¸»¾cÕd¯¹å…¶å®ƒ¾cÀLˆ–接口的符号引用,在这一步它是可选的。类的初始化是对¾cÖM¸­å£°æ˜Žçš„静态初始化函数 和静态域的初始化构造方法的执行。一个类在初始化之前它的父类必须被初始化。整个过½E‹å¦‚下:

å›?åQšè™šæ‹Ÿæœºçš„运行过½E?/p>

4  ¾l“束è¯?/b>

本文通过对JVM的体¾pȝ»“构的深入研究以及一个Java½E‹åºæ‰§è¡Œæ—¶è™šæ‹Ÿæœºçš„运行过½E‹çš„详细分析åQŒæ„åœ¨å‰–析清楚Java虚拟机的机理ã€?br>

转蝲自:http://gceclub.sun.com.cn/staticcontent/html/2004-04-09/jvm.html



]]>
Java¾c»è£…载体¾pÖM¸­çš„éš”¼›ÀL€?/title><link>http://www.aygfsteel.com/leopallas/archive/2006/02/23/32181.html</link><dc:creator>Leo</dc:creator><author>Leo</author><pubDate>Thu, 23 Feb 2006 10:43:00 GMT</pubDate><guid>http://www.aygfsteel.com/leopallas/archive/2006/02/23/32181.html</guid><wfw:comment>http://www.aygfsteel.com/leopallas/comments/32181.html</wfw:comment><comments>http://www.aygfsteel.com/leopallas/archive/2006/02/23/32181.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/leopallas/comments/commentRss/32181.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/leopallas/services/trackbacks/32181.html</trackback:ping><description><![CDATA[ <p align="center">作者:<a >盛戈æ­?/a></p> <a name="author"></a> <p><b>作者简ä»?/b></p> <p class="normal">盛戈歆,软äšg工程师,你可以通过<a href="mailto:shenggexin@topwaver.com">shenggexin@topwaver.com</a>与他联系ã€?/p> <p><b>正文</b></p> <p class="normal">Java中类的查找与装蝲出现的问题æ€ÀL˜¯ä¼šæ—¶ä¸æ—¶å‡ºçŽ°åœ¨Java½E‹åºå‘˜é¢å‰ï¼Œ˜q™åƈ不是什么丢脸的事情åQŒç›¸ä¿¡æ²¡æœ‰ä¸€ä¸? Java½E‹åºå‘˜æ²¡é‡åˆ°˜q‡ClassNotException,å› æ­¤ä¸è¦ä¸ø™¢«äººçž…见自å·×ƒ¹ŸçŠ¯è¿™æ ïLš„错误而觉得不自然åQŒä½†æ˜¯åœ¨å¦‚果出现äº? ClassNotFoundException后异常后一脸的茫然åQŒé‚£æˆ‘想你该了解一下java的类装蝲的体制了åQŒåŒæ—¶äؓ了进行下面的关于¾c»è£…载器之间çš? 隔离性的讨论åQŒæˆ‘们先½Ž€å•介¾lä¸€ä¸‹ç±»è£…蝲的体¾pȝ»“æž„ã€?/p> <p><b>1. Java¾c»è£…载体¾pȝ»“æž?/b></p> <p class="normal">装蝲¾cȝš„˜q‡ç¨‹éžå¸¸½Ž€å•:查找¾cÀL‰€åœ¨ä½¾|®ï¼Œòq¶å°†æ‰‘Öˆ°çš„Java¾cȝš„字节码装入内存,生成对应的Class对象ã€? Java的类装蝲器专门用来实现这æ ïLš„˜q‡ç¨‹åQŒJVMòq¶ä¸æ­¢æœ‰ä¸€ä¸ªç±»è£…蝲器,事实上,如果你愿意的话,你可以让JVM拥有无数个类装蝲器,当然˜q™é™¤äº†æµ‹è¯? JVM外,我想不出˜q˜æœ‰å…¶ä»–的用途。你应该已经发现åˆîCº†˜q™æ ·ä¸€ä¸ªé—®é¢˜ï¼Œ¾c»è£…载器自èín也是一个类åQŒå®ƒä¹Ÿéœ€è¦è¢«è£…蝲到内存中来,那么˜q™äº›¾c»è£…载器ç”Þp°æ¥è£…è½? 呢,æ€Õd¾—有个根吧åQŸæ²¡é”™ï¼Œ¼‹®å®žå­˜åœ¨˜q™æ ·çš„æ ¹åQŒå®ƒž®±æ˜¯¼œžé¾™è§é¦–不见ž®„¡š„Bootstrap ClassLoader. ä¸ÞZ»€ä¹ˆè¯´å®ƒç¥žé¾™è§é¦–ä¸è§å°¾å‘¢ï¼Œå› äØ“ä½ æ ¹æœ¬æ— æ³•åœ¨Java代码中抓住哪怕是它的一点点的尾å·ß_¼Œž®½ç®¡ä½ èƒ½æ—¶æ—¶åˆÕdˆ»ä½“ä¼šåˆ°å®ƒçš„å­˜åœ¨ï¼Œå› äØ“java的运行环境所需 要的所有类库,都由它来装蝲åQŒè€Œå®ƒæœ¬èín是C++写的½E‹åºåQŒå¯ä»¥ç‹¬ç«‹è¿è¡?可以说是JVM的运行è“vç‚?伟大吧。在Bootstrap完成它的ä»ÕdŠ¡åŽï¼Œä¼šç”Ÿæˆ? 一个AppClassLoader(实际上之前系¾lŸè¿˜ä¼šä‹É用扩展类装蝲器ExtClassLoaderåQŒå®ƒç”¨äºŽè£…蝲Java˜qè¡ŒçŽ¯å¢ƒæ‰©å±•åŒ…ä¸­çš„ç±»),˜q™ä¸ª ¾c»è£…载器才是我们¾lå¸¸ä½¿ç”¨çš„,可以调用ClassLoader.getSystemClassLoader() 来获得,我们假定½E‹åºä¸­æ²¡æœ‰ä‹É用类装蝲器相å…Ïx“ä½œè®¾å®šæˆ–者自定义新的¾c»è£…载器åQŒé‚£ä¹ˆæˆ‘们编写的所有java¾c»é€šé€šä¼šç”±å®ƒæ¥è£…载,值得ž®Šæ•¬å§ã€? AppClassLoader查找¾cȝš„区域ž®±æ˜¯è€³ç†Ÿèƒ½è¯¦çš„ClasspathåQŒä¹Ÿæ˜¯åˆå­¦è€…å¿…™å»è·¨˜q‡çš„门槛åQŒæœ‰æ²¡æœ‰çµå…‰ä¸€é—ªçš„æ„Ÿè§‰åQŒæˆ‘们按照它的类查找范围 ¾l™å®ƒå–名为类路径¾c»è£…载器。还是先前假定的情况åQŒå½“Java中出现新的类åQŒAppClassLoader首先在类传递给它的父类¾c»è£…载器åQŒä¹Ÿž®±æ˜¯ Extion ClassLoaderåQŒè¯¢é—®å®ƒæ˜¯å¦èƒ½å¤Ÿè£…蝲该类åQŒå¦‚果能åQŒé‚£AppClassLoaderž®×ƒ¸òq²è¿™‹zÖMº†åQŒåŒæ ·Extion ClassLoader在装载时åQŒä¹Ÿä¼šå…ˆé—®é—®å®ƒçš„父类装蝲器。我们可以看出类装蝲器实际上是一个树状的¾l“构图,每个¾c»è£…载器有自å·Þqš„父亲åQŒç±»è£…蝲器在装蝲 ¾cÀL—¶åQŒæ€ÀL˜¯å…ˆè®©è‡ªå·±çš„父¾c»è£…载器装蝲(多么ž®Šæ•¬é•¿è¾ˆ),如果父类装蝲器无法装载该¾cÀL—¶åQŒè‡ªå·±å°±ä¼šåŠ¨æ‰‹è£…è½½ï¼Œå¦‚æžœå®ƒä¹Ÿè£…è²ä¸äº†åQŒé‚£ä¹ˆå¯¹ä¸è“våQŒå®ƒä¼šå¤§å–Šä¸€å£ŽÍ¼š ExceptionåQŒclass not found。有必要提一句,当由直接使用¾c»èµ\径装载器装蝲¾cÕd¤±è´¥æŠ›å‡ºçš„æ˜¯NoClassDefFoundException异常。如果ä‹É用自定义的类装蝲 器loadClassæ–ÒŽ³•或者ClassLoaderçš„findSystemClassæ–ÒŽ³•装蝲¾c»ï¼Œå¦‚果你不åŽÕdˆ»æ„æ”¹å˜ï¼Œé‚£ä¹ˆæŠ›å‡ºçš„æ˜¯ ClassNotFoundExceptionã€?/p> <p class="normal">我们½Ž€çŸ­æ€È»“一下上面的讨论åQ?/p> <p class="normal">1.JVM¾c»è£…载器的体¾pȝ»“构可以看作是树状¾l“æž„ã€?/p> <p class="normal">2.父类装蝲器优先装载。在父类装蝲器装载失败的情况下再装蝲åQŒå¦‚果都装蝲å¤ÞpÓ|则抛出ClassNotFoundException或者NoClassDefFoundError异常ã€?/p> <p class="normal">那么我们的类在什么情况下被装载的呢?</p> <b>2. ¾cÕd¦‚何被装蝲</b> <p class="normal">在java2中,JVM是如何装载类的呢åQŒå¯ä»¥åˆ†ä¸ÞZ¸¤¿Uç±»åž‹ï¼Œä¸€¿Uæ˜¯éšå¼çš„类装蝲åQŒä¸€¿Uå¼æ˜‘Ö¼çš„类装蝲ã€?/p> <b>2.1 隐式的类装蝲</b> <p class="normal">隐式的类装蝲是编码中最常用得方式:</p> <pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">A b </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> A();</span></div><br></pre> <p class="normal">如果½E‹åº˜qè¡Œåˆ°è¿™ŒDµä»£ç æ—¶˜q˜æ²¡æœ‰A¾c»ï¼Œé‚£ä¹ˆJVM会请求装载当前类的类装器来装载类ã€? 问题来了åQŒæˆ‘把代码弄得复杂一点点åQŒä½†ä¾æ—§æ²¡æœ‰ä»ÖM½•隑ֺ¦åQŒè¯·æ€è€ƒJVM得装载次序:</p> <pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);"> test;<br></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);">Public </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> A{<br></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> main(String args[]){<br></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">        B b åQ?nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> B();<br></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">    }<br></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 0, 0);">}<br></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> B{C c;}<br></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> C{}</span></div><br></pre> <p class="normal">揭晓½{”案åQŒç±»è£…è²çš„æ¬¡åºäØ“A->BåQŒè€Œç±»Cæ ÒŽœ¬ä¸ä¼šè¢«JVM理会,先不要惊è®Óž¼Œä»”细æƒÏxƒ³åQŒè¿™ä¸æ­£æ˜¯æˆ‘们最需è¦? 得到的结果。我们仔¾l†äº†è§£ä¸€ä¸‹JVM装蝲™åºåºã€‚当使用Java A命ä×o˜qè¡ŒA¾cÀL—¶åQŒJVM会首先要求类路径¾c»è£…载器(AppClassLoader)装蝲A¾c»ï¼Œä½†æ˜¯˜q™æ—¶åªè£…è½½AåQŒä¸ä¼šè£…è½½A中出现的其他¾c?B¾c?åQŒæŽ¥ 着它会调用A中的main函数åQŒç›´åˆ°è¿è¡Œè¯­å¥b åQ?new B()æ—Óž¼ŒJVM发现必须装蝲B¾cȝ¨‹åºæ‰èƒ½ç‘ô¾l­è¿è¡Œï¼ŒäºŽæ˜¯¾c»èµ\径类装蝲器会去装载B¾c»ï¼Œè™½ç„¶æˆ‘们可以看到B中有有C¾cȝš„声明åQŒä½†æ˜¯åƈ不是实际的执行语句, æ‰€ä»¥åÆˆä¸åŽ»è£…è²C¾c»ï¼Œä¹Ÿå°±æ˜¯è¯´JVM按照˜qè¡Œæ—¶çš„æœ‰æ•ˆæ‰§è¡Œè¯­å¥åQŒæ¥å†›_®šæ˜¯å¦éœ€è¦è£…载新¾c»ï¼Œä»Žè€Œè£…载尽可能ž®‘çš„¾c»ï¼Œ˜q™ä¸€ç‚¹å’Œ¾~–译¾cÀL˜¯ä¸ç›¸åŒçš„ã€?/p> <p><b>2.2 昑ּçš„类装蝲</b></p> <p class="normal">使用昄¡¤ºçš„类装蝲æ–ÒŽ³•很多åQŒæˆ‘们都装蝲¾c»test.Aä¸ÞZ¾‹ã€?/p> <p class="normal">使用Class¾cȝš„forNameæ–ÒŽ³•。它可以指定装蝲器,也可以ä‹É用装载当前类的装载器。例如:</p> <pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">Class.forName(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">test.A</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);</span></div><br>它的效果å’?br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">Class.forName(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">test.A</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.getClass().getClassLoader());</span></div><br>是一æ ïLš„ã€?br></pre> <p class="normal">使用¾c»èµ\径类装蝲装蝲.</p> <pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">ClassLoader.getSystemClassLoader().loadClass(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">test.A</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);</span></div><br></pre> <p class="normal">使用当前˜q›ç¨‹ä¸Šä¸‹æ–‡çš„使用的类装蝲器进行装载,˜q™ç§è£…蝲¾cÈš„æ–ÒŽ³•常常被有着复杂¾c»è£…载体¾pȝ»“构的¾pȝ»Ÿæ‰€ä½¿ç”¨ã€?/p> <pre><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">Thread.currentThread().getContextClassLoader().loadClass(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">test.A</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">)</span></div><br></pre> <p class="normal">使用自定义的¾c»è£…载器装蝲¾c?/p> <div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);">1</span> <span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> MyClassLoader </span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);"> URLClassLoader{<br></span><span style="color: rgb(0, 128, 128);">2</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> MyClassLoader() {<br></span><span style="color: rgb(0, 128, 128);">3</span> <span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">super</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> URL[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]);<br></span><span style="color: rgb(0, 128, 128);">4</span> <span style="color: rgb(0, 0, 0);">    }<br></span><span style="color: rgb(0, 128, 128);">5</span> <span style="color: rgb(0, 0, 0);">}<br></span><span style="color: rgb(0, 128, 128);">6</span> <span style="color: rgb(0, 0, 0);">MyClassLoader myClassLoader </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> MyClassLoader();<br></span><span style="color: rgb(0, 128, 128);">7</span> <span style="color: rgb(0, 0, 0);">myClassLoader.loadClass(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">test.A</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);</span></div> <p class="normal">MyClassLoader¾l§æ‰¿äº†URLClassLoader¾c»ï¼Œ˜q™æ˜¯JDK核心包中的类装蝲器,在没有指定父¾c»è£…载器的情况下åQŒç±»è·¯å¾„¾c»è£…载器ž®±æ˜¯å®ƒçš„父类装蝲器,MyClassLoaderòq¶æ²¡æœ‰å¢žåŠ ç±»çš„æŸ¥æ‰¾èŒƒå›ß_¼Œå› æ­¤å®ƒå’Œ¾c»èµ\径装载器有相同的效果ã€?/p> <p class="normal">我们已经知道Java的类装蝲器体¾pȝ»“æž„äØ“æ ‘çŠ¶åQŒå¤šä¸ªç±»è£…è²å™¨å¯ä»¥æŒ‡å®šåŒä¸€ä¸ªç±»è£…è²å™¨ä½œä¸ø™‡ªå·Þqš„父类åQŒæ¯ä¸ªå­¾c»è£…è½? 器就是树状结构的一个分支,当然它们又可以个有子¾c»è£…载器¾c»è£…载器åQŒç±»è£…蝲器也可以没有父类装蝲器,˜q™æ—¶Bootstrap¾c»è£…载器ž®†ä½œä¸ºå®ƒçš„隐含父¾c»ï¼Œ 实际上Bootstrap¾c»è£…载器是所有类装蝲器的¼œ–å…ˆåQŒä¹Ÿæ˜¯æ ‘状结构的栏V€‚è¿™¿Uæ ‘状体¾pȝ»“构,以及父类装蝲器优先的机制åQŒäؓ我们¾~–写自定义的¾c»è£…载器æ? 供了便利åQŒåŒæ—¶å¯ä»¥è®©½E‹åºæŒ‰ç…§æˆ‘们希望的方式进行类的装载。例如某个程序的¾c»è£…载器体系¾l“构囑֦‚下:</p> <p align="center"><img src="http://gceclub.sun.com.cn/yuanchuang/week-9/classloader.gif" alt="" border="0" height="287" width="427"></p> <p align="center">å›?åQšæŸä¸ªç¨‹åºçš„¾c»è£…载器的结æž?/p> <p class="normal">解释一下上面的图,ClassLoaderA䏸™‡ªå®šä¹‰çš„ç±»è£…è²å™¨ï¼Œå®ƒçš„çˆ¶ç±»è£…è²å™¨äØ“¾c»èµ\径装载器åQŒå®ƒæœ‰ä¸¤ä¸ªå­¾c»è£…è½? 器ClassLoaderAAå’ŒClassLaderABåQŒClassLoaderB为程序ä‹É用的另外一个类装蝲器,它没有父¾c»è£…载器åQŒä½†æœ‰ä¸€ä¸ªå­¾c»è£…è½? 器ClassLoaderBB。你可能会说åQŒè§é¬û|¼Œæˆ‘çš„½E‹åºæ€Žä¹ˆä¼šä‹É用这么复杂的¾c»è£…载器¾l“æž„ã€‚äØ“äº†è¿›è¡Œä¸‹é¢çš„è®¨è®ºåQŒæš‚且委屈一下ã€?/p> <p><b>3. 奇怪的隔离æ€?/b></p> <p class="normal">我们不难发现åQŒå›¾2中的¾c»è£…载器AAå’ŒABåQ? ABå’ŒBBåQŒAAå’ŒB½{‰ç­‰ä½äºŽä¸åŒåˆ†æ”¯ä¸‹ï¼Œä»–们之间没有父子关系åQŒæˆ‘不知道如何定义这¿Uå…³¾p»ï¼Œå§‘且¿UîC»–们位于不同分支下。两个位于不同分支的¾c»è£…载器å…ähœ‰ 隔离性,˜q™ç§éš”离性ä‹É得在分别使用它们装蝲同一个类åQŒä¹Ÿä¼šåœ¨å†…存中出çŽîC¸¤ä¸ªClass¾cȝš„å®žä¾‹ã€‚å› ä¸ø™¢«å…ähœ‰éš”离性的¾c»è£…载器装蝲的类不会å…׃ín内存½Iºé—´åQŒä‹É å¾—ä‹É用一个类装蝲器不可能完成的ä“Q务变得可以轻而易举,例如¾cȝš„静态变量可能同时拥有多个å€û|¼ˆè™½ç„¶å¥½åƒä½œç”¨ä¸å¤§åQ‰ï¼Œå› äØ“ž®Þq®—是被装蝲¾cȝš„同一静态变量,å®? 们也ž®†è¢«ä¿å­˜ä¸åŒçš„内存空é—ß_¼Œåˆä¾‹å¦‚程序需要ä‹É用某些包åQŒä½†åˆä¸å¸Œæœ›è¢«ç¨‹åºå¦å¤–一些包所使用åQŒå¾ˆ½Ž€å•,¾~–写自定义的¾c»è£…载器。类装蝲器的˜q™ç§éš”离性在许多 大型的èÊY件应用和服务½E‹åºå¾—åˆ°äº†å¾ˆå¥½çš„åº”ç”¨ã€‚ä¸‹é¢æ˜¯åŒä¸€ä¸ªç±»é™æ€å˜é‡äØ“ä¸åŒå€¼çš„ä¾‹å­ã€?/p><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);"> 1</span> <span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);"> test;<br></span><span style="color: rgb(0, 128, 128);"> 2</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> A {<br></span><span style="color: rgb(0, 128, 128);"> 3</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> main( String[] args ) {<br></span><span style="color: rgb(0, 128, 128);"> 4</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">try</span><span style="color: rgb(0, 0, 0);"> {<br></span><span style="color: rgb(0, 128, 128);"> 5</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">定义两个¾c»è£…载器</span><span style="color: rgb(0, 128, 0);"><br></span><span style="color: rgb(0, 128, 128);"> 6</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">      MyClassLoader aa</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> MyClassLoader();<br></span><span style="color: rgb(0, 128, 128);"> 7</span> <span style="color: rgb(0, 0, 0);">      MyClassLoader bb </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> MyClassLoader();<br></span><span style="color: rgb(0, 128, 128);"> 8</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);"> 9</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">用类装蝲器aa装蝲testb.B¾c?/span><span style="color: rgb(0, 128, 0);"><br></span><span style="color: rgb(0, 128, 128);">10</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">      Class clazz</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">aa.loadClass(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">testb. B</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br></span><span style="color: rgb(0, 128, 128);">11</span> <span style="color: rgb(0, 0, 0);">      Constructor constructor</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> <br></span><span style="color: rgb(0, 128, 128);">12</span> <span style="color: rgb(0, 0, 0);">        clazz.getConstructor(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Class[]{Integer.</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">});<br></span><span style="color: rgb(0, 128, 128);">13</span> <span style="color: rgb(0, 0, 0);">      Object object </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> <br></span><span style="color: rgb(0, 128, 128);">14</span> <span style="color: rgb(0, 0, 0);">        constructor.newInstance(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Object[]{</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Integer(</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)});<br></span><span style="color: rgb(0, 128, 128);">15</span> <span style="color: rgb(0, 0, 0);">      Method method </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> <br></span><span style="color: rgb(0, 128, 128);">16</span> <span style="color: rgb(0, 0, 0);">        clazz.getDeclaredMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">printB</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Class[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]);<br></span><span style="color: rgb(0, 128, 128);">17</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">18</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">用类装蝲器bb装蝲testb.B¾c?/span><span style="color: rgb(0, 128, 0);"><br></span><span style="color: rgb(0, 128, 128);">19</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">      Class clazz2</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">bb.loadClass(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">testb. B</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br></span><span style="color: rgb(0, 128, 128);">20</span> <span style="color: rgb(0, 0, 0);">      Constructor constructor2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> <br></span><span style="color: rgb(0, 128, 128);">21</span> <span style="color: rgb(0, 0, 0);">        clazz2.getConstructor(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Class[]{Integer.</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">});<br></span><span style="color: rgb(0, 128, 128);">22</span> <span style="color: rgb(0, 0, 0);">      Object object2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> <br></span><span style="color: rgb(0, 128, 128);">23</span> <span style="color: rgb(0, 0, 0);">        constructor2.newInstance(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Object[]{</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Integer(</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">)});<br></span><span style="color: rgb(0, 128, 128);">24</span> <span style="color: rgb(0, 0, 0);">      Method method2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> <br></span><span style="color: rgb(0, 128, 128);">25</span> <span style="color: rgb(0, 0, 0);">        clazz2.getDeclaredMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">printB</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Class[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]);<br></span><span style="color: rgb(0, 128, 128);">26</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">27</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">昄¡¤ºtest.B中的静态变量的å€?nbsp;</span><span style="color: rgb(0, 128, 0);"><br></span><span style="color: rgb(0, 128, 128);">28</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);">      method.invoke( object,</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Object[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]);<br></span><span style="color: rgb(0, 128, 128);">29</span> <span style="color: rgb(0, 0, 0);">      method2.invoke( object2,</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Object[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]);<br></span><span style="color: rgb(0, 128, 128);">30</span> <span style="color: rgb(0, 0, 0);">    } </span><span style="color: rgb(0, 0, 255);">catch</span><span style="color: rgb(0, 0, 0);"> ( Exception e ) {<br></span><span style="color: rgb(0, 128, 128);">31</span> <span style="color: rgb(0, 0, 0);">      e.printStackTrace();<br></span><span style="color: rgb(0, 128, 128);">32</span> <span style="color: rgb(0, 0, 0);">    }<br></span><span style="color: rgb(0, 128, 128);">33</span> <span style="color: rgb(0, 0, 0);">  }<br></span><span style="color: rgb(0, 128, 128);">34</span> <span style="color: rgb(0, 0, 0);">}<br></span><span style="color: rgb(0, 128, 128);">35</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">36</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">37</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">Class B å¿…须位于MyClassLoader的查找范围内åQ?br></span><span style="color: rgb(0, 128, 128);">38</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">而不应该在MyClassLoader的父¾c»è£…载器的查找范围内ã€?/span><span style="color: rgb(0, 128, 0);"><br></span><span style="color: rgb(0, 128, 128);">39</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);"> testb;<br></span><span style="color: rgb(0, 128, 128);">40</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> B {<br></span><span style="color: rgb(0, 128, 128);">41</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> b ;<br></span><span style="color: rgb(0, 128, 128);">42</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">43</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> B(Integer testb) {<br></span><span style="color: rgb(0, 128, 128);">44</span> <span style="color: rgb(0, 0, 0);">        b </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> testb.intValue();<br></span><span style="color: rgb(0, 128, 128);">45</span> <span style="color: rgb(0, 0, 0);">    }<br></span><span style="color: rgb(0, 128, 128);">46</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">47</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> printB() {<br></span><span style="color: rgb(0, 128, 128);">48</span> <span style="color: rgb(0, 0, 0);">        System.out.print(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">my static field b is </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, b);<br></span><span style="color: rgb(0, 128, 128);">49</span> <span style="color: rgb(0, 0, 0);">    }<br></span><span style="color: rgb(0, 128, 128);">50</span> <span style="color: rgb(0, 0, 0);">}<br></span><span style="color: rgb(0, 128, 128);">51</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">52</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">53</span> <span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> MyClassLoader </span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);"> URLClassLoader{<br></span><span style="color: rgb(0, 128, 128);">54</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> File file </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> File(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">c:\\classes </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br></span><span style="color: rgb(0, 128, 128);">55</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">该èµ\径存攄¡€class BåQŒä½†æ˜¯æ²¡æœ‰class A</span><span style="color: rgb(0, 128, 0);"><br></span><span style="color: rgb(0, 128, 128);">56</span> <span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">57</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> MyClassLoader() {<br></span><span style="color: rgb(0, 128, 128);">58</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">super</span><span style="color: rgb(0, 0, 0);">(getUrl());<br></span><span style="color: rgb(0, 128, 128);">59</span> <span style="color: rgb(0, 0, 0);">  }<br></span><span style="color: rgb(0, 128, 128);">60</span> <span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">61</span> <span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> URL[] getUrl() {<br></span><span style="color: rgb(0, 128, 128);">62</span> <span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">try</span><span style="color: rgb(0, 0, 0);"> {<br></span><span style="color: rgb(0, 128, 128);">63</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> URL[]{file.toURL()};<br></span><span style="color: rgb(0, 128, 128);">64</span> <span style="color: rgb(0, 0, 0);">    } </span><span style="color: rgb(0, 0, 255);">catch</span><span style="color: rgb(0, 0, 0);"> ( MalformedURLException e ) {<br></span><span style="color: rgb(0, 128, 128);">65</span> <span style="color: rgb(0, 0, 0);">      </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> URL[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">];<br></span><span style="color: rgb(0, 128, 128);">66</span> <span style="color: rgb(0, 0, 0);">    }<br></span><span style="color: rgb(0, 128, 128);">67</span> <span style="color: rgb(0, 0, 0);">  }<br></span><span style="color: rgb(0, 128, 128);">68</span> <span style="color: rgb(0, 0, 0);">}</span></div><br> ½E‹åºçš„è¿è¡Œç»“æžœäØ“åQ? <pre>my static field b is 1<br>my static field b is 2<br></pre> <p class="normal">½E‹åºçš„结果非常有意思,从编½E‹è€…的角度åQŒæˆ‘们甚臛_¯ä»¥æŠŠä¸åœ¨åŒä¸€ä¸ªåˆ†æ”¯çš„¾c»è£…载器看作不同的javaè™šæ‹Ÿæœºï¼Œå› äØ“å®? 们彼此觉察不到对方的存在。程序在使用å…ähœ‰åˆ†æ”¯çš„类装蝲的体¾pȝ»“构时要非常小心,弄清楚每个类装蝲器的¾cÀLŸ¥æ‰¾èŒƒå›ß_¼Œž®½é‡é¿å…çˆ¶ç±»è£…蝲器和子类装蝲器的¾cÀLŸ¥ 找范围中有相同类名的¾c»ï¼ˆåŒ…括包名和类名)åQŒä¸‹é¢è¿™ä¸ªä¾‹å­å°±æ˜¯ç”¨æ¥è¯´æ˜Žè¿™¿Uæƒ…况可能带来的问题ã€?/p> <p class="normal">假设有相同名字却不同版本的接å?AåQ?/p> <pre>版本 1åQ?br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);"> test;<br>Intefer Same{ </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getVersion(); }</span></div><br>版本 2åQ?br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">Package test;<br>Intefer Same{ </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getName(); }</span></div><br></pre> <p class="normal">接口A两个版本的实玎ͼš</p> <pre>版本1的实çŽ?br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);"> test;<br></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Same1Impl </span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);"> Same {<br></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getVersion(){ </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">A version 1</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;}<br>}</span></div><br>版本2的实çŽ?br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Same 2Impl </span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);"> Same {<br></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getName(){ </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">A version 2</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;}<br>}</span></div><br></pre> <p class="normal">我们依然使用å›?的类装蝲器结构,首先ž®†ç‰ˆæœ?çš„Sameå’ŒSame的实现类Same1Impl打成åŒ? same1.jaråQŒå°†ç‰ˆæœ¬2çš„Sameå’ŒSame的实现类Same1Impl打成包same2.jar。现在,做这æ ïLš„事情åQŒæŠŠsame1.jar攑օ¥ ¾c»è£…载器ClassLoaderA的类查找范围中,把same2.jar攑օ¥¾c»è£…器ClassLoaderAB的类查找范围中。当你兴冲冲的运行下面这ä¸? 看似正确的程序ã€?/p> <p class="normal">实际上这个错误的是由父类载器优先装蝲的机刉™€ æˆåQŒå½“¾c»è£…载器ClassLoaderAB在装载Same2Impl ¾cÀL—¶å‘现必须装蝲接口test.SameåQŒäºŽæ˜¯æŒ‰è§„定è¯äh±‚父类装蝲器装载,父类装蝲器发çŽîCº†ç‰ˆæœ¬1çš„test.Same接口òq¶å…´å†²å†²çš„装载,但是却想不到 Same2Impl所希望的是版本2 çš„test.SameåQŒåŽé¢çš„事情可想而知了,异常被抛出ã€?/p> <p class="normal">我们很难责怪Javaä¸­æš‚æ—¶åÆˆæ²¡æœ‰æä¾›åŒºåˆ†ç‰ˆæœ¬çš„æœºåˆÓž¼Œå¦‚果使用了比较复杂的¾c»è£…载器体系¾l“æž„åQŒåœ¨å‡ºçŽ°äº†æŸä¸ªåŒ…æˆ–è€…ç±»çš„å¤šä¸ªç‰ˆæœ¬æ—¶åQŒåº”特别注意ã€?/p> 掌握和灵‹z»è¿ç”¨Java的类装蝲器的体系¾l“æž„åQŒå¯¹½E‹åºçš„ç³»¾lŸè®¾è®¡ï¼Œ½E‹åºçš„实玎ͼŒå·²ç»½E‹åºçš„调试,都有相当大的帮助。希望以上的内容能够å¯ÒŽ‚¨æœ‰æ‰€å¸®åŠ©.<br> <br> 转蝲自:http://gceclub.sun.com.cn/yuanchuang/week-9/classloader.html<br> <img src ="http://www.aygfsteel.com/leopallas/aggbug/32181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/leopallas/" target="_blank">Leo</a> 2006-02-23 18:43 <a href="http://www.aygfsteel.com/leopallas/archive/2006/02/23/32181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WebLogic的类装蝲机制详解http://www.aygfsteel.com/leopallas/archive/2006/02/23/32180.htmlLeoLeoThu, 23 Feb 2006 10:37:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32180.htmlhttp://www.aygfsteel.com/leopallas/comments/32180.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32180.html#Feedback0http://www.aygfsteel.com/leopallas/comments/commentRss/32180.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/32180.html 作者:juxtapose


 如果大家对一般类的装载器熟悉的话åQŒå°±çŸ¥é“在java中类的装载采用“代理机制”,卛_­è£…蝲器如果需要装载一个类文äšgåQŒé¦–先会ž®†æ­¤ä»ÕdŠ¡æäº¤¾l™çˆ¶ 装蝲器,如果父装载器找不到此¾cÀL–‡ä»Óž¼Œæ‰æœ‰å­è£…载器来装载类文äšgåQŒå¦‚果子装蝲器也找不刎ͼŒé‚£ä¹ˆž®×ƒ¼šæŠ¥å‘ŠClassNotFoundExceptionå¼? 常。下面简单谈一下我对weblogic server的类装蝲器原理的了解åQŒå¸Œæœ›èƒ½å’Œå¤§å®¶åˆ†äº«ã€?

1åQŽWeblogic允许定制的类装蝲器,同时也有一个默认的¾c»è£…载器。其默认的装载器的结构分层如下:

 

  当部¾|²ä¸€ä¸ªåº”用的时候,weblogic server会自动创å»ÞZ¸€ä¸ªå…·æœ‰å±‚‹Æ¡ç»“构的¾c»è£…载器。在图中åQ?/strong>a.Application Classloader负责装蝲应用中的所有的EJB JARæ–‡äšgåQ?/p>

  b.Web Application Classloader负责装蝲所有的Web application 中的WAR æ–‡äšgåQˆæ‰€æœ‰å¾—jspæ–‡äšg除外åQ‰ï¼›

  c.Jsp Classloader 负责装蝲Web application 中的所有的jsp æ–‡äšgåQ?/p>

  ˜q™æ ·çš„分层结构有一个好处,ž®±æ˜¯åœ¨JspåQŒServlet中可以直接访问EJB的接口。这¿Uä¸Šå±‚装载EJB,下层装蝲servlet½{‰ï¼Œæœ€ä¸‹é¢è£…蝲jspæ–‡äšg的结构,使得¾lå¸¸å˜åŠ¨çš„jspåQŒservlet½{‰å¯ä»¥è¢«é‡æ–°è£…蝲而不会涉及到EJB层ã€?/p>

在这¿Ué»˜è®¤çš„¾c»è£…载器¾l“构下,有一炚wœ€è¦æå‡ºçš„æ˜¯ï¼š

  a. 我们的应用必™åÀL‰“包成一个EARæ–‡äšgåQŒæ‰ä¼šå…è®¸æˆ‘们应用中的jspå’Œservletæ–‡äšg直接讉K—®ejb;如果ž®†WAR与JARæ–‡äšg分别打包ã€? Weblogic serverä¼šäØ“ä»–ä»¬åˆ†åˆ«ç”Ÿæˆä¸€ä¸ªç±»è£…è²å™¨ï¼Œä½œäØ“å…„å¼ŸèŠ‚ç‚¹åQŒè¿™æ—¶å¦‚果需要在jsp或者servlet中ä‹É用ejb,ž®±å¿…™åÕd°†EJBçš„Home接口ä¸? remote接口打包到WAR中才可以。后面这¿Uæƒ…况,适合用在ž®†EJB的客æˆïL«¯å’ŒEJB部çÖv在不同的JVM中;

  b.web application classloader中,不会装蝲jspæ–‡äšgåQŒjspæ–‡äšgç”±web application classloader的子装蝲器Jsp classloader负责装蝲åQŒå› ä¸ºjspæ–‡äšg¾lå¸¸çš„变动,通过为jsp讄¡«‹ä¸€ä¸ªå•独的classloader可以避免对jsp的装载媄响到其他çš? java class或者ejbåQ?/p>

默认装蝲器的优点åQ?/strong>

  a. 调用ejb的时候可以采用call-by-referrence的方式;

  b. 允许web module独立的装载,不媄响其它的web module;

  • 通过在将整个应用打包成一个EARæ–‡äšgåQŒå¯ä»¥æ–¹ä¾¿çš„不用再web module中包含EJBçš„homeå’Œremote接口åQŒå°±å¯ä»¥æ–¹ä¾¿çš„通过call-by-referrence来调用ejb;

2. 定制classloader
  如果觉得默认的类装蝲器不能满­‘³éœ€è¦ï¼Œweblogic server支持定制的类装蝲器。在weblogic的文档中指出åQŒè‡ªå®šä¹‰çš„classloader多用于开发者ä‹É用,当应用发布之后,不推荐ä‹É用。自å®? 义的¾c»è£…载器通过xmlæ–‡äšg来描˜q°ã€‚描˜q°æ–‡ä»¶æ”¾åœ¨weblogic-application.xml中。Weblogic官方提供的DTD描述文äšg如下åQ?/p>

<classloader-structure> 
    
<module-ref> 
        
<module-uri>ejba.jar</module-uri> 
    
</module-ref> 
    
<module-ref> 
        
<module-uri>webc.war</module-uri> 
    
</module-ref>
    
<classloader-structure> 
        
<module-ref> 
            
<module-uri>weba.war</module-uri> 
        
</module-ref> 
    
</classloader-structure>
    
<classloader-structure> 
        
<module-ref> 
            
<module-uri>ejbc.jar</module-uri> 
        
</module-ref> 
        
<module-ref> 
            
<module-uri>webb.war</module-uri> 
        
</module-ref>
        
<classloader-structure> 
            
<module-ref> 
    
<module-uri>webd.war</module-uri> 
            
</module-ref> 
        
</classloader-structure> 
        
<classloader-structure> 
            
<module-ref> 
    
<module-uri>ejbb.jar</module-uri> 
            
</module-ref> 
        
</classloader-structure>
    
</classloader-structure>
</classloader-structure>

  通过我们¾l™å‡ºçš„配¾|®æ–‡ä»Óž¼Œæˆ‘们自定义的classloader的层‹Æ¡ç»“构如下图åQ?/p>

 

  在J2EE的规范中明确的指出,J2EE应用不应该依赖于ä»ÖM¸€ä¸ªç»™å®šçš„¾c»è£…载器。所以,我们自定义的¾c»è£…载器åQŒåœ¨å¼€å‘过½E‹ä¸­˜q˜æ˜¯å¯ä»¥ä½¿ç”¨çš„,但一定不要应用于发布后的应用中ã€?/p>

自定义的¾c»è£…载器有如下得限制åQ?/strong>
  a.不能够装载servlet;

  b.åµŒå¥—çš„æ·±åº¦æœ€å¤§äØ“3åQŒä¹Ÿž®±æ˜¯è¯ß_¼Œæœ€å¤šåªèƒ½å¤ŸåµŒå¥—三层åQ?/p>

  c.自定义装载器的module¾cÕdž‹ä»…限äº?Webå’?EJB˜q™ä¸¤¿Uï¼›

  d.Jsp Classloader不受此自定义¾c»è£…载器的媄响,它永˜qœéƒ½æ˜¯web module的子¾c»è£…载器åQ?/p>

  • ç›¸åŒçš„ç±»å¯èƒ½å¯ÆD‡´éƒ¨çÖv异常åQ?/li>
  • 在自定义的类装蝲器中åQŒå¦‚果要使用EJBåQŒå°±å¿…é¡»ž®†EJBçš„homeå’Œremote接口打包到相应的web module中去åQ?/li>
  •  

3åQŽEjb的单独加è½?br>   有时候我们可能需要单独加载某个EJB,˜q™ä¸ªæ—¶å€™æˆ‘们可以通过以下两种æ–ÒŽ³•来实玎ͼš

  ½W¬ä¸€åQšå°†åº”用需要的jaræ–‡äšg攑֜¨APP-INF/lib中,或者将¾cÀL–‡ä»¶æ”¾åœ¨APP-INF/classes中,˜q™äº›¾cÀL–‡ä»¶å’ŒJARæ–‡äšg会被root classloader˜q›è¡Œè£…蝲åQŒå¯ä»¥è¢«å¤šä¸ªåº”用å…׃ínåQ?/p>

  ½W¬äºŒåQšå¯ä»¥é€šè¿‡META-INF/MANIFEST.MFæ–‡äšg来指定需要的classes。通常的用法是在META-INF/MANIFEST.MFæ–‡äšg中增加Class-Path:一行。ä‹D例如下:

  Class-Path:/d:ejb/add.jar

  ˜q™æ ·ž®×ƒ¼šåœ¨å½“前的jar包中可以扑ֈ°æˆ‘们需要的add.jaræ–‡äšg。需要说明的是,在Class-Path:行的最后一定要有一个换行,否则会发生错误。还有,通过Class-Path只能指定本地的JARæ–‡äšgã€?/p>

  如果能对应用服务器的¾c»è£…载原理有了较清楚åœîCº†è§£ï¼Œä¼šå¯¹æˆ‘们的应用移植,在开发中避免不必要的¾c»è£…载的错误会有很大的帮助ã€?br>

转蝲自:http://dev2dev.bea.com.cn/bbsdoc/20051104121.html



]]>
Java虚拟机类装蝲åQšåŽŸç†ã€å®žçŽîC¸Žåº”用http://www.aygfsteel.com/leopallas/archive/2006/02/23/32179.htmlLeoLeoThu, 23 Feb 2006 10:31:00 GMThttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32179.htmlhttp://www.aygfsteel.com/leopallas/comments/32179.htmlhttp://www.aygfsteel.com/leopallas/archive/2006/02/23/32179.html#Feedback0http://www.aygfsteel.com/leopallas/comments/commentRss/32179.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/32179.html作者:刘学­‘?/p>

一、引­a€

Java虚拟æœ?JVM)的类装蝲ž®±æ˜¯æŒ‡å°†åŒ…含在类文äšg中的字节码装载到JVMä¸? òq¶ä‹É其成为JVM一部分的过½E‹ã€‚JVM的类动态装载技术能够在˜qè¡Œæ—¶åˆ»åŠ¨æ€åœ°åŠ è²æˆ–è€…æ›¿æ¢ç³»¾lŸçš„æŸäº›åŠŸèƒ½æ¨¡å—, 而不影响¾pȝ»Ÿå…¶ä»–功能模块的正常运行。本文将分析JVM中的¾c»è£…载系¾lŸï¼ŒæŽ¢è®¨JVM中类装蝲的原理、实çŽîC»¥åŠåº”用ã€?/p>

二、Java虚拟机的¾c»è£…载实çŽîC¸Žåº”用

2.1  è£…蝲˜q‡ç¨‹½Ž€ä»?/b>

所谓装载就是寻找一个类或是一个接口的二进制åÅžå¼åÆˆç”¨è¯¥äºŒè¿›åˆ¶åŞ式来构造代表这个类或是˜q™ä¸ªæŽ¥å£çš„class对象的过½E‹ï¼Œå…¶ä¸­¾cÀLˆ–接口的名¿U°æ˜¯¾l™å®šäº†çš„。当然名¿UîC¹Ÿå¯ä»¥é€šè¿‡è®¡ç®—得到åQŒä½†æ˜¯æ›´å¸¸è§çš„æ˜¯é€šè¿‡æœçƒ¦æºä»£ç ç»˜q‡ç¼–译器¾~–译后所得到的二˜q›åˆ¶å½¢å¼æ¥æž„造ã€?/p>

在Java中,¾c»è£…载器把一个类装入Java虚拟æœÞZ¸­åQŒè¦¾lè¿‡ä¸‰ä¸ªæ­¥éª¤æ¥å®Œæˆï¼šè£…蝲、链接和初始化,其中链接又可以分成校验、准备和解析三步åQŒé™¤äº†è§£æžå¤–åQŒå…¶å®ƒæ­¥éª¤æ˜¯ä¸¥æ ¼æŒ‰ç…§™åºåºå®Œæˆçš„,各个步骤的主要工作如下:

  • 装蝲åQšæŸ¥æ‰‘Ö’Œå¯¼å…¥¾cÀLˆ–接口的二˜q›åˆ¶æ•°æ®åQ?
  • 链接åQšæ‰§è¡Œä¸‹é¢çš„æ ¡éªŒã€å‡†å¤‡å’Œè§£æžæ­¥éª¤åQŒå…¶ä¸­è§£æžæ­¥éª¤æ˜¯å¯ä»¥é€‰æ‹©çš„ï¼›
  • 校验åQšæ£€æŸ¥å¯¼å…¥ç±»æˆ–æŽ¥å£çš„äºŒè¿›åˆ¶æ•°æ®çš„æ­£ç¡®æ€§ï¼›
  • 准备åQšç»™¾cȝš„é™æ€å˜é‡åˆ†é…åÆˆåˆå§‹åŒ–å­˜å‚¨ç©ºé—ß_¼›
  • 解析åQšå°†½W¦å·å¼•用转成直接引用åQ?
  • 初始化:‹È€‹zȝ±»çš„静态变量的初始化Java代码和静态Java代码块ã€?

至于在类装蝲和虚拟机启动的过½E‹ä¸­çš„具体细节和可能会抛出的错误åQŒè¯·å‚看《Javaè™šæ‹Ÿæœø™§„范》以及《深入Java虚拟机》,它们在网¾lœä¸Šé¢çš„资源地址是: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Preface.doc.html å’? http://www.artima.com/insidejvm/ed2/index.htmlã€?ç”׃ºŽæœ¬æ–‡çš„讨论重点不在此ž®×ƒ¸å†å¤šå™è¿°ã€?/p>

2.2  è£…蝲的实çŽ?/b>

JVM中类的装载是由ClassLoader和它的子¾cÀL¥å®žçްçš?Java ClassLoader 是一个重要的Java˜qè¡Œæ—¶ç³»¾lŸç»„件。它负责在运行时查找和装入类文äšg的类ã€?/p>

在Java中,ClassLoader是一个抽象类åQŒå®ƒåœ¨åŒ…java.langä¸?可以˜q™æ ·è¯ß_¼Œåªè¦äº†è§£äº†åœ¨ ClassLoader中的一些重要的æ–ÒŽ³•åQŒå†¾l“合上面所介绍的JVM中类装蝲的具体的˜q‡ç¨‹åQŒå¯¹åŠ¨æ€è£…è½½ç±»˜q™é¡¹æŠ€æœ¯å°±æœ‰äº†ä¸€ä¸ªæ¯”较大概的掌握åQŒè¿™äº›é‡è¦çš„ æ–ÒŽ³•包括以下几个:

â‘ loadCassæ–ÒŽ³•  loadClass(String name ,boolean resolve)其中name参数指定了JVM需要的¾cȝš„名称,该名¿UîC»¥åŒ…表½Cºæ³•表示,如Java.lang.ObjectåQ›resolve参数告诉æ–ÒŽ³• 是否需要解析类åQŒåœ¨åˆå§‹åŒ–类之前,应考虑¾c»è§£æžï¼Œòq¶ä¸æ˜¯æ‰€æœ‰çš„¾c»éƒ½éœ€è¦è§£æžï¼Œå¦‚æžœJVM只需要知道该¾cÀL˜¯å¦å­˜åœ¨æˆ–扑ևºè¯¥ç±»çš„è¶…¾c?那么ž®×ƒ¸éœ€è¦è§£æžã€‚è¿™ä¸? æ–ÒŽ³•是ClassLoader 的入口点ã€?/p>

â‘¡defineClassæ–ÒŽ³•  ˜q™ä¸ªæ–ÒŽ³•接受¾cÀL–‡ä»¶çš„字节数组òq¶æŠŠå®ƒè{换成Class对象。字节数¾l„可以是从本地文件系¾lŸæˆ–¾|‘络装入的数据。它把字节码分析成运行时数据¾l“构、校验有效性等½{‰ã€?/p>

â‘¢findSystemClassæ–ÒŽ³•  findSystemClassæ–ÒŽ³•从本地文件系¾lŸè£…入文件。它在本地文 ä»¶ç³»¾lŸä¸­å¯ÀL‰¾¾cÀL–‡ä»?如果存在,ž®×ƒ‹É用defineClassž®†å­—节数¾l„è{换成Class对象,以将该文件è{换成¾c…R€‚当˜qè¡ŒJava应用½E‹åºæ—?˜q™æ˜¯ JVM 正常装入¾cȝš„¾~ºçœæœºåˆ¶ã€?/p>

â‘£resolveClassæ–ÒŽ³•  resolveClass(Class c)æ–ÒŽ³•解析装入的类,如果该类已经被解析过那么ž®†ä¸åšå¤„理。当调用loadClassæ–ÒŽ³•æ—?通过它的resolve 参数军_®šæ˜¯å¦è¦è¿›è¡Œè§£æžã€?/p>

⑤findLoadedClassæ–ÒŽ³•  å½“调用loadClassæ–ÒŽ³•装入¾cÀL—¶,调用 findLoadedClass æ–ÒŽ³•来查看ClassLoader是否已装入这个类,如果已装å…?那么˜q”回Class对象,否则˜q”回NULL。如果强行装载已存在的类,ž®†ä¼šæŠ›å‡ºé“¾æŽ¥é”? 误ã€?/p>

2.3  è£…蝲的应ç”?/b>

一般来è¯ß_¼Œæˆ‘们使用虚拟机的¾c»è£…载时需要ç‘ô承抽象类java.lang.ClassLoader,其中必须实现的方 法是loadClass()åQŒå¯¹äºŽè¿™ä¸ªæ–¹æ³•需要实现如下操ä½?(1) ¼‹®è®¤¾cȝš„名称;(2) ‹‚€æŸ¥è¯·æ±‚要装蝲的类是否已经被装è½?(3) ‹‚€æŸ¥è¯·æ±‚加载的¾cÀL˜¯å¦æ˜¯¾pȝ»Ÿ¾c?(4) ž®è¯•ä»Žç±»è£…è²å™¨çš„å­˜å‚¨åŒø™Ž·å–所è¯äh±‚的类;(5) 在虚拟机中定义所è¯äh±‚的类;(6) 解析所è¯äh±‚的类;(7) ˜q”回所è¯äh±‚的类ã€?/p>

所有的Java 虚拟机都包括一个内¾|®çš„¾c»è£…载器åQŒè¿™ä¸ªå†…¾|®çš„¾cÕdº“装蝲器被¿UîCؓ根装载器(bootstrap ClassLoader)。根装蝲器的ç‰ÒŽ®Šä¹‹å¤„是它只能够装载在设计时刻已知的类,因此虚拟机假定由根装载器所装蝲的类都是安全的、可信ä“Qçš?可以不经˜q? 安全认证而直接运行。当应用½E‹åºéœ€è¦åŠ è½½åÆˆä¸æ˜¯è®¾è®¡æ—¶å°±çŸ¥é“çš„ç±»æ—?必须使用用户自定义的装蝲å™?user-defined ClassLoader)。下面我们ä‹D例说明它的应用ã€?br>

 1 public abstract class MultiClassLoader extends ClassLoader{
 2     
 3     public synchronized Class loadClass(String s, boolean flag)
 4         throws ClassNotFoundException
 5     {
 6         /* ‹‚€æŸ¥ç±»s是否已经在本地内å­?/span>*/
 7         Class class1 = (Class)classes.get(s);
 8 
 9         /* ¾c»s已经在本地内å­?/span>*/
10         if(class1 != null)  return class1; 
11         try/*用默认的ClassLoader è£…å…¥¾c?/span>*/  {
12             class1 = super.findSystemClass(s);
13             return class1;
14         }
15         catch(ClassNotFoundException _ex)  {
16             System.out.println(">> Not a system class.");
17         }
18 
19         /* å–å¾—¾c»s的字节数¾l?/span>*/
20         byte abyte0[] = loadClassBytes(s);
21         if(abyte0 == null)   throw new ClassNotFoundException();
22 
23         /* ž®†ç±»å­—节数组转换为类*/
24         class1 = defineClass(null, abyte0, 0, abyte0.length);
25         if(class1 == nullthrow new ClassFormatError();
26         if(flag)   resolveClass(class1); /*解析¾c?/span>*/
27 
28         /* ž®†æ–°åŠ è²çš„ç±»æ”‘Ö…¥æœ¬åœ°å†…å­˜*/
29         classes.put(s, class1);
30         System.out.println(">> Returning newly loaded class.");
31 
32         /* ˜q”回已装载、解析的¾c?/span>*/
33         return class1;
34     }
35     
36 }

三、Java虚拟机的¾c»è£…载原ç?/b>

前面我们已经知道åQŒä¸€ä¸ªJava应用½E‹åºä½¿ç”¨ä¸¤ç§¾cÕdž‹çš„类装蝲器:根装载器(bootstrap)和用户定义的装蝲 å™?user-defined)。根装蝲器是Java虚拟机实现的一部分åQŒä‹D个例子来è¯ß_¼Œå¦‚果一个Java虚拟机是在现在已¾lå­˜åœ¨åƈ且正在被使用的操作系 ¾lŸçš„™å‰™ƒ¨ç”¨C½E‹åºæ¥å®žçŽ°çš„åQŒé‚£ä¹ˆæ ¹è£…蝲器将是那些C½E‹åºçš„一部分。根装蝲器以某种默认的方式将¾c»è£…入,包括那些Java API的类。在˜qè¡ŒæœŸé—´ä¸€ä¸ªJava½E‹åºèƒ½å®‰è£…用戯‚‡ªå·±å®šä¹‰çš„¾c»è£…载器。根装蝲器是虚拟机固有的一部分åQŒè€Œç”¨æˆ·å®šä¹‰çš„¾c»è£…载器则不是,它是用Java语言 写的åQŒè¢«¾~–译成classæ–‡äšg之后然后再被装入到虚拟机åQŒåƈ像其它的ä»ÖM½•对象一样可以被实例化ã€?Java¾c»è£…载器的体¾pȝ»“构如下所½Cºï¼š

å›?  Java的类装蝲的体¾pȝ»“æž?/b>

Java的类装蝲模型是一¿Uä»£ç?delegation)模型。当JVM 要求¾c»è£…载器CL(ClassLoader)装蝲一个类æ—?CL首先ž®†è¿™ä¸ªç±»è£…蝲è¯äh±‚转发¾l™ä»–的父装蝲器。只有当父装载器没有装蝲òq¶æ— æ³•装载这个类æ—? CL才获得装载这个类的机会。这æ ? 所有类装蝲器的代理关系构成了一¿Uæ ‘状的关系。树的根是类的根装蝲å™?bootstrap ClassLoader) , 在JVM 中它ä»?null"表示。除根装载器以外的类装蝲器有且仅有一个父装蝲器。在创徏一个装载器æ—? 如果没有昑ּåœ°ç»™å‡ºçˆ¶è£…蝲å™? 那么JVMž®†é»˜è®¤ç³»¾lŸè£…载器为其父装载器。Java的基本类装蝲器代理结构如å›?所½Cºï¼š

å›?  Java¾c»è£…载的代理¾l“æž„

下面针对各种¾c»è£…载器分别˜q›è¡Œè¯¦ç»†çš„说明ã€?

æ ?Bootstrap) 装蝲å™?该装载器没有父装载器åQŒå®ƒæ˜¯JVM实现的一部分åQŒä»Žsun.boot.class.path装蝲˜qè¡Œæ—¶åº“的核心代码ã€?

扩展(Extension) 装蝲å™?¾l§æ‰¿çš„çˆ¶è£…è²å™¨äØ“æ ¹è£…è½½å™¨åQŒä¸åƒæ ¹è£…蝲器可能与˜qè¡Œæ—¶çš„æ“ä½œ¾pȝ»Ÿæœ‰å…³åQŒè¿™ä¸ªç±»è£…蝲器是用纯Java代码实现的,它从java.ext.dirs (扩展目录)中装载代码ã€?

¾pȝ»Ÿ(System or Application) 装蝲å™?è£…è²å™¨äØ“æ‰©å±•è£…è²å™¨ï¼Œæˆ‘ä»¬éƒ½çŸ¥é“åœ¨å®‰è£…JDK的时候要讄¡½®çŽ¯å¢ƒå˜é‡(CLASSPATH )åQŒè¿™ä¸ªç±»è£…蝲器就是从java.class.path(CLASSPATH 环境变量)中装载代码的åQŒå®ƒä¹Ÿæ˜¯ç”¨çº¯Java代码实现的,同时˜q˜æ˜¯ç”¨æˆ·è‡ªå®šä¹‰ç±»è£…蝲器的¾~ºçœçˆ¶è£…载器ã€?

ž®åº”用程åº?Applet) 装蝲å™? è£…è²å™¨äØ“¾pȝ»Ÿè£…蝲器,它从用户指定的网¾lœä¸Šçš„特定目录装载小应用½E‹åºä»£ç ã€?

在设计一个类装蝲器的时候,应该满èƒö以下两个条äšgåQ?/p>

  1. 对于相同的类名,¾c»è£…载器所˜q”回的对象应该是同一个类对象
  2. 如果¾c»è£…载器CL1ž®†è£…载类C的请求è{¾l™ç±»è£…蝲器CL2åQŒé‚£ä¹ˆå¯¹äºŽä»¥ä¸‹çš„¾cÀLˆ–接口,CL1å’ŒCL2应该˜q”回同一个类对象:a)S为Cçš? 直接­‘…ç±»;b)S为C的直接超接口;c)S为C的成员变量的¾cÕdž‹;d)S为C的成员方法或构徏器的参数¾cÕdž‹;e)S为C的成员方法的˜q”回¾cÕdž‹ã€?

每个已经装蝲到JVM中的¾c»éƒ½éšå¼å«æœ‰è£…蝲它的¾c»è£…载器的信息。类æ–ÒŽ³•getClassLoader 可以得到装蝲˜q™ä¸ª¾cȝš„¾c»è£…载器。一个类装蝲器认识的¾cÕdŒ…括它的父装蝲器认识的¾cÕd’Œå®ƒè‡ªå·Þp£…载的¾c»ï¼Œå¯è§¾c»è£…载器认识的类是它自己装蝲的类的超集。注意我ä»? 可以得到¾c»è£…载器的有关的信息åQŒä½†æ˜¯å·²¾lè£…载到JVM中的¾cÀL˜¯ä¸èƒ½æ›´æ”¹å®ƒçš„¾c»è£…载器的ã€?

Java中的¾cȝš„装蝲˜q‡ç¨‹ä¹Ÿå°±æ˜¯ä»£ç†è£…载的˜q‡ç¨‹ã€‚比å¦?Web‹¹è§ˆå™¨ä¸­çš„JVM需要装载一个小应用½E‹åº TestApplet。JVM调用ž®åº”用程序装载器ACL(Applet ClassLoader)来完成装载。ACL首先è¯äh±‚它的父装载器, 即系¾lŸè£…载器装蝲TestApplet是否装蝲了这个类, ç”׃ºŽTestApplet不在¾pȝ»Ÿè£…蝲器的装蝲路径ä¸? 所以系¾lŸè£…载器没有扑ֈ°˜q™ä¸ª¾c? 也就没有装蝲成功。接着ACL自己装蝲TestApplet。ACL通过¾|‘络成功地找åˆîCº†TestApplet.class æ–‡äšgòq¶å°†å®ƒå¯¼å…¥åˆ°äº†JVM中。在装蝲˜q‡ç¨‹ä¸? JVM发现TestAppet是从­‘…ç±»java.applet.Applet¾l§æ‰¿çš„。所以JVM再次调用ACL来装è½? java.applet.Applet¾c…R€‚ACL又再‹Æ¡æŒ‰ä¸Šé¢çš„顺序装载Applet¾c? ¾l“æžœACL发现他的父装载器已经装蝲了这个类, 所以ACLž®Þq›´æŽ¥å°†˜q™ä¸ªå·²ç»è£…蝲的类˜q”回¾l™äº†JVM , 完成了Applet¾cȝš„装蝲。接下来,Applet¾cÈš„­‘…类也一样处理。最å? TestApplet及所有有关的¾c»éƒ½è£…蝲åˆîCº†JVM中ã€?/p>

四、结�/b>

¾cȝš„动态装载机制是JVM的一™åÒŽ ¸å¿ƒæŠ€æœ? 也是å®ÒŽ˜“被忽视而引起很多误解的地方。本文介¾läº†JVM中类装蝲的原理、实çŽîC»¥åŠåº”用,ž®¤å…¶åˆ†æžäº†ClassLoader的结构、用途以及如何利用自定义 çš„ClassLoader装蝲òq¶æ‰§è¡ŒJava¾c»ï¼Œå¸Œæœ›èƒ½ä‹É读者对JVM中的¾c»è£…载有一个比较深入的理解ã€?br>

转蝲自:http://gceclub.sun.com.cn/yuanchuang/week-8/jvm.html



]]>
Spring MVC与Veclocity¾l“合中文问题及常用中文问题æ€È»“http://www.aygfsteel.com/leopallas/archive/2005/09/14/12985.htmlLeoLeoWed, 14 Sep 2005 02:37:00 GMThttp://www.aygfsteel.com/leopallas/archive/2005/09/14/12985.htmlhttp://www.aygfsteel.com/leopallas/comments/12985.htmlhttp://www.aygfsteel.com/leopallas/archive/2005/09/14/12985.html#Feedback3http://www.aygfsteel.com/leopallas/comments/commentRss/12985.htmlhttp://www.aygfsteel.com/leopallas/services/trackbacks/12985.html昨天在整合Spring MVCå’ŒVelocityåQŒSitemeshæ—Óž¼Œåˆç¢°åˆîCº†ä¹…违的中文问题。唉åQŒJSP, mysql, strutsåQŒæ¯‹Æ¡éƒ½ä¼šç¢°åˆ°è¿™æ ïLš„问题åQŒæ€ÀL˜¯ä»¥äØ“˜q™ç§ä»¥åŽä¸ä¼š¼„°åˆ°˜q™ç§çœ‹ä¼¼åˆçñ”的问题了åQŒç»“果还是躲不过。网上没查到相关资料åQŒäºŽæ˜¯å¼€å§‹åŠ¨æ‰‹è·ŸítªSpringå’ŒVelocity的源码,弄了一天终于搞定。后来一个同学告诉我˜q™ä¸ªé—®é¢˜åœ¨Spring中文论坛里有¾_‘֍Žè´ß_¼Œè·Ÿæˆ‘最后的解决æ–ÒŽ¡ˆä¸€æ ïLš„åQŒæ°”æ­ÀLˆ‘也。不˜q‡è·ŸítªSpring的源代码收获˜q˜æ˜¯ä¸é”™çš„,现在又对Springçš„MVC framework有了更深的认识。这里把以前¼„°åˆ°çš„中文问题大概列一下,方便以后参考ã€?/FONT>

1、JSP™åµé¢æ˜„¡¤ºçš„中文问é¢?BR>˜q™æ˜¯æœ€åˆçñ”的东西,¾|‘上到处都有åQŒä¸˜q‡è¿˜æ˜¯åˆ—一下吧åQ?BR>Page的第一行改成:<%@ page contentType="text/html; charset=gb2312" %>
Head里加åQ?BR>2、页面Form 内容提交的中文问é¢?BR>在web.xml里加入:

CharacterEncodingFilter
Character Encoding Filter
no description
org.springframework.web.filter.CharacterEncodingFilter

encoding
GB2312


forceEncoding
true



CharacterEncodingFilter
/*

呵呵åQŒè¿™æ˜¯ä¸ª½Ž€å•得要命的filteråQŒå¦‚果不用Spring的话åQŒå®Œå…¨å¯ä»¥è‡ªå·±å†™ä¸€ä¸ªã€‚其实ä“Q何的interceptor机制都可以处理这个的åQŒä¸½Ž¡ç”¨Webwork˜q˜æ˜¯Springçš„interceptoråQŒç”šè‡³ç”¨AOPåQŒåªè¦åœ¨å–参数前加那么一句:request.setCharacterEncoding("GB2312");ž®Þp¡Œäº†ã€‚以前我用strutsž®±æ˜¯åœ¨å®ƒçš„RequestProcessorçš„populate之前加了˜q™ä¹ˆä¸€è¡Œã€?BR>3、request çš„parameter里要传中文参数的问题
˜q™ä¸ªé—®é¢˜è·ŸWeb Container有关¾p»ï¼Œè®°å¾—以前我同学用WebLogic时好象没出现˜q™æ ·çš„问题。(我一般不传中文参敎ͼŒå‘µå‘µåQ‰ã€?BR>Tomcat里的解决æ–ÒŽ¡ˆæ˜¯åœ¨server.xml里Connector port="8080"çš„attribute里加URIEncoding="GB2312"
当然˜q˜æœ‰æœ€åœŸçš„解决æ–ÒŽ¡ˆåQŒè™½ç„¶ä¸å¤ªä¼šç”¨åˆ°åQŒä¸˜q‡è¿˜æ˜¯åˆ—出来åQŒä»¥å¤‡æœ€æ— å¥ˆçš„æ—¶å€™ä‹É用:
String encodeStr=new String(fieldValue.getBytes("8859_1"), "gb2312");
4、mysql的中文问é¢?BR>首先要修改mysql配置文äšgçš„encoding为GB2312åQŒè¿™éƒ¨åˆ†çš„æ“ä½œä¸è®°å¾—了,毕竟好久没用mysql了。不˜q‡æ®è¯´æ–°ç‰ˆçš„mysql里有wizard可以讄¡š„。然后把jdbc connectionæ”ÒŽˆå¦‚下åQ?BR>jdbc:mysql://localhost:3306/bsfbookstore?useUnicode=true;characterEncoding=GB2312
另外在写½E‹åºæˆå°½é‡ç”¨PrepareStatementåQŒå°‘用StatementåQŒå¥½è±¡jdbc驱动在解析statement里的SQL包含中文时会有问题。(用PrepareStatement也是好习惯, hibernate里全用PrepareStatement的,哈哈åQ?BR>5、Spring与Veclocity¾l“合的中文问é¢?BR>½W¬ä¸€æ­¥ï¼š
åœ?velocityConfig"里配¾|®velocity.propetiesæ–‡äšgåQŒåŠ ä¸‹é¢ä¸€è¡Œï¼š
/WEB-INF/velocity.properties
呵呵åQŒä¹Ÿå¯ä»¥åœ¨config里直接用Map把参数写˜q›åŽ»åQŒè¿™æ ·å°±ä¸ç”¨propertiesæ–‡äšgåQŒè¿™ä¸ªSpring的文档里都有ã€?BR>然后在velocity.properties里写åQ?BR>input.encoding=GB2312
output.encoding=GB2312
default.contentType=text/html; charset=GB2312åQˆms˜q™ä¸€è¡Œæ²¡æœ‰ç”¨å¤„,Spring有个地方读进˜q™ä¸ªå‚æ•°åQŒä¸˜q‡åŽæ¥åˆè¦†ç›–掉了åQ?BR>½W¬äºŒæ­¥ï¼š
接下来就是我昨天调了半天的那个地方,最后的解决æ–ÒŽ¡ˆå¾ˆç®€å•,在viewResolver配置里加一行:
text/html; charset=GB2312
呵呵åQŒå°±˜q™ä¹ˆä¸€è¡Œå®³æˆ‘debug了好久,跟踪了Velocityçš„Context讄¡½®åQŒç”šè‡Ïx”¹äº†Spring的源码,用了FilteråQŒSpringçš„Handler interceptor来设¾|®reponseçš„contentTypež®±æ˜¯æ²¡æ•ˆæžœï¼Œ¾l“果发现Spring在Velocity Viewçš„render里加了这么一行:
response.setContentType(getContentType());
呵呵åQŒåŽŸå…ˆè®¾å¥½çš„contentTypeéƒ½è¢«å†²æŽ‰äº†ï¼Œå› äØ“render的时机是在postHandler之后åQŒå‘µå‘üc€?BR>˜q™ä¸ªå‚数对jspæ˜¯æ²¡æœ‰ç”¨çš„ï¼Œå› äØ“jsp会根据自己页面的contentType讑֮šçš„,所以每个JSP必须讄¡½®è‡ªå·±çš„contentTypeåQŒVelocityž®×ƒ¸ç”¨å•¦ã€‚难怪以前用JSP的时候没¼„°åˆ°˜q™ä¸ªé—®é¢˜ã€?/FONT>



]]>
Ö÷Õ¾Ö©Öë³ØÄ£°å£º ÎÚÊ²ÏØ| ¶ë±ß| ÒÀÀ¼ÏØ| ÇØ°²ÏØ| Ó¢É½ÏØ| Õò¿µÏØ| È«ÖÝÏØ| òÔºÓÊÐ| ¼ªÊ×ÊÐ| ¸ßÒØÏØ| ¹®ÒåÊÐ| ´ëÇÚÏØ| ÃñÀÖÏØ| »¸ÈÊ| ¸£ÇåÊÐ| °²ÏçÏØ| Äϲ¿ÏØ| Í¨Î¼ÏØ| ÆÁ¶«ÏØ| ¸ÊµÂÏØ| Â«É½ÏØ| ´óÒØÏØ| Ô­ÑôÏØ| ººÔ´ÏØ| ÖÜ¿ÚÊÐ| ½ð̳ÊÐ| ÈôÇ¼ÏØ| µü²¿ÏØ| ÍþÔ¶ÏØ| °²Ô¶ÏØ| ÐËÂ¡ÏØ| ³¤É³ÏØ| ÕÄÆÖÏØ| ´ó·½ÏØ| ËçÀâÏØ| è÷äüÏØ| Ì«¹ÈÏØ| °²ÇìÊÐ| ÖÐɽÊÐ| Ë«°ØÏØ| ÎÚÀ¼²ì²¼ÊÐ|