SummaryBy Shashank Tiwari
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)
|
ava 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:
SQLException
into transient and non-transient typesIterable
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 SQLException
s 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-SQLException
s 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. RowId
s
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 RowId
s often are unique only for a table and not for the entire database; they may change and are not supported by all databases. RowId
s 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 RowId
s 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.
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
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
作者:朱éª
朱éªå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>
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>
通常å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>
CWNF是一个é¢å‘Webçš„JMSæ ¡åŠ¡¾pÈ»ŸåQŒç”¨äºŽæ ¡å›å‘布通知åŠå¾æ±‚æ„è§ç‰æ ¡åŠ¡å·¥ä½œåQŒé€šçŸ¥åˆ†äØ“2¾c»ï¼šæ™®é€šé€šçŸ¥å’Œå¾æ±‚æ„è§æ€§é€šçŸ¥ã€?/p>
该系¾lŸç”¨æˆ·åˆ†æˆ?¾c»ï¼Œç”¨æˆ·ä¸åŒåQŒå¤„ç†æ¨¡åž‹ä¹Ÿä¸åŒåQŒåŸºæœ¬æƒ…况如下:①å‘å¸ƒç”¨æˆøP¼Œæ‹¥æœ‰é€šçŸ¥å‘布æƒï¼Œå‘主题å‘布通知åQ›â‘¡¾|²å用户åQŒæŸ¥é˜…通知åQŒä¹Ÿå¯å‘è¡¨å¯¹å¾æ±‚æ„è§æ€§é€šçŸ¥çš„å馈æ„è§ï¼›â‘¢åŒ¿åç”¨æˆøP¼ŒåªæŸ¥é˜…通知ã€?/p>
¾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ˆå馈)→主é¢?å˜å‚¨)
¾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>
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>
XSLæ˜¯å¯æ‰©å±•çš„æ ·å¼å•è¯è¨€åQŒé€šçŸ¥é›†çš„XML文档和å馈集的XML文档都有相关的XSL文档军_®šå…‰™¡µé¢æ˜¾½Cºï¼Œå¦‚通知集XML文档的XSLæ ·å¼å®šä¹‰å¦‚下åQ?/p>
用户的一些处ç†å·¥ä½œéœ€è¦æ³¨å†?ç™Õd½•åŽæ‰èƒ½è¿›è¡Œï¼Œå› æ¤æ³¨å†Œ/ç™Õd½•的获准信æ¯å¿…™å»èƒ½åœ¨æœ‰å…³Servlet¾l„äšgä¹‹é—´ä¼ é€’ã€‚ServletContext 对象å¯è®¾¾|®å’Œè¯Õd–属性,使ä¸åŒServletä¹‹é—´ç›æ€º’通信åQŒåœ¨¾pÈ»Ÿä¸è¢«ç”¨äºŽæœ‰å…³¾l„äšg对用戯‚ín份的验è¯ã€?/p>
æ¯ä¸€æ¡å¾æ±‚æ„è§æ€§é€šçŸ¥éƒ½æœ‰ä¸€ä¸ªç›¸å…Œ™”çš„å馈集åˆï¼Œå…Œ™”å¯é€šè¿‡è®„¡½®æ¶ˆæ¯å±žæ€§å®žçŽ°ã€‚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>
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
作者:刘妑?
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?
对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虚拟机的寄å˜å™¨æœ‰å››ç§:
在上˜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虚拟机采å–如下措æ–?
æ“ä½œæ•°æ ˆåŒ?/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Œåƈ且åˆå§‹åŒ–它们。例如对于程åºï¼š
¾~–译åŽåœ¨å‘½ä×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
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;
2. 定制classloader
  如果觉得默认的类装è²å™¨ä¸èƒ½æ»¡‘³éœ€è¦ï¼Œweblogic
server支æŒå®šåˆ¶çš„类装è²å™¨ã€‚在weblogicçš„æ–‡æ¡£ä¸æŒ‡å‡ºåQŒè‡ªå®šä¹‰çš„classloader多用于开å‘者ä‹É用,当应用å‘布之åŽï¼Œä¸æŽ¨èä‹É用。自å®?
义的¾c»è£…载器通过xmlæ–‡äšgæ¥æ˜q°ã€‚æ˜q°æ–‡ä»¶æ”¾åœ¨weblogic-application.xmlä¸ã€‚Weblogic官方æä¾›çš„DTDæè¿°æ–‡äšg如下åQ?/p>
  通过我们¾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>
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
一ã€å¼•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Œå…¶å®ƒæ¥éª¤æ˜¯ä¸¥æ ¼æŒ‰ç…§™åºåºå®Œæˆçš„,å„个æ¥éª¤çš„主è¦å·¥ä½œå¦‚下:
至于在类装è²å’Œè™šæ‹Ÿæœºå¯åŠ¨çš„è¿‡½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>
三ã€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>
æ¯ä¸ªå·²ç»è£…è²åˆ°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
1ã€JSP™åµé¢æ˜„¡¤ºçš„䏿–‡é—®é¢?BR>˜q™æ˜¯æœ€åˆçñ”的东西,¾|‘上到处都有åQŒä¸˜q‡è¿˜æ˜¯åˆ—一下å§åQ?BR>Page的第一行改æˆï¼š<%@ page contentType="text/html; charset=gb2312" %>
Headé‡ŒåŠ åQ?BR>2ã€é¡µé¢Form 内容æäº¤çš„䏿–‡é—®é¢?BR>在web.xmlé‡ŒåŠ å…¥ï¼š
呵呵å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ŒåР䏋é¢ä¸€è¡Œï¼š
呵呵å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é…ç½®é‡ŒåŠ ä¸€è¡Œï¼š
呵呵å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>