java sm框架怎么网站如何实现在线支付付

developerWorks 社区
从本系列前面的文章中,您了解到反射的性能比直接访问要慢许多倍,并了解了用 Javassist 和 Apache Byte Code Engineering Library (BCEL)进行classworking。Java 顾问 Dennis Sosnoski 通过演示如何使用运行时 classworking,来用全速前进的生成代码取代反射代码,从而结束他的 Java 编程的动态性 系列。
Dennis Sosnoski 是西雅图地区 Java 咨询公司 Sosnoski Software Solutions, Inc. 的创始人和首席顾问,他是
方面的专家。他已经有 30 多年专业软件开发经验,最近几年他集中研究服务器端的 Java 技术。Dennis 经常在全国性的会议上就 XML 和 Java 技术发表演讲,他还是
Seattle Java-XML SIG和
Eclipse SIG的主席。可以通过
与 Dennis 联系。
既然您已经看到了如何使用 Javassist 和 BCEL 框架来进行 classworking (请参阅
我将展示一个实际的 classworking 应用程序。这个应用程序用运行时生成的、并立即装载到 JVM 的类来取代反射。在综合讨论的过程中,我将引用本系列的前两篇文章,以及对
Javassist 和 BCEL 的讨论,这样本文就成为了对这个很长的系列文章的一个很好的总结。
反射的性能
, 我展示了无论是对于字段访问还是方法调用,反射都比直接代码慢很多倍。这种延缓对于许多应用程序来说不算是问题,但是总是会遇到性能非常关键的情况。在这种情况下,反射可能成为真正的瓶颈。但是,用静态编译的代码取代反射可能会非常混乱,并且在有些情况下(如在这种框架中:反射访问的类或者项目是在运行时提供的,而不是作为这一编译过程的一部分提供的),如果不重新构建整个应用程序就根本不可能取代。
Classworking 使我们有机会将静态编译的代码的性能与反射的灵活性结合起来。这里的基本方法是,在运行时,以一种可以被一般性代码使用的方式,构建一个自定义的类,其中将包装对目标类的访问(以前是通过反射达到的)。将这个自定义类装载到
JVM 中后,就可以全速运行了。设置阶段
清单 1 给出了应用程序的起点。这里定义了一个简单的 bean 类
HolderBean 和一个访问类
ReflectAccess 。访问类有一个命令行参数,该参数必须是一个值为
int 的 bean 类属性的名字(
value1 或者
value2 )。它增加指定属性的值,然后在退出前打印出这两个属性值。
清单 1. 反射一个 beanpublic class HolderBean
private int m_value1;
private int m_value2;
public int getValue1() {
return m_value1;
public void setValue1(int value) {
m_value1 =
public int getValue2() {
return m_value2;
public void setValue2(int value) {
m_value2 =
public class ReflectAccess
public void run(String[] args) throws Exception {
if (args.length == 1 && args[0].length() & 0) {
// create property name
char lead = args[0].charAt(0);
String pname = Character.toUpperCase(lead) +
args[0].substring(1);
// look up the get and set methods
Method gmeth = HolderBean.class.getDeclaredMethod
("get" + pname, new Class[0]);
Method smeth = HolderBean.class.getDeclaredMethod
("set" + pname, new Class[] { int.class });
// increment value using reflection
HolderBean bean = new HolderBean();
Object start = gmeth.invoke(bean, null);
int incr = ((Integer)start).intValue() + 1;
smeth.invoke(bean, new Object[] {new Integer(incr)});
// print the ending values
System.out.println("Result values " +
bean.getValue1() + ", " + bean.getValue2());
System.out.println("Usage: ReflectAccess value1|value2");
}下面是运行
ReflectAccess 的两个例子,用来展示结果:
[dennis]$ java -cp . ReflectAccess value1
Result values 1, 0
[dennis]$ java -cp . ReflectAccess value2
Result values 0, 1构建 glue 类
我已经展示了反射版本的代码,现在要展示如何用生成的类来取代反射。要想让这种取代可以正确工作,会涉及到一个微妙的问题,它可追溯到本系列
中对类装载的讨论。这个问题是:我想要在运行时生成一个可从访问类的静态编译的代码进行访问的类,但是因为对编译器来说生成的类不存在,因此没办法直接引用它。
那么如何将静态编译的代码链接到生成的类呢?基本的解决方案是定义可以用静态编译的代码访问的基类或者接口,然后生成的类扩展这个基类或者实现这个接口。这样静态编译的代码就可以直接调用方法,即使方法只有到了运行时才能真正实现。在清单 2 中,我定义了一个接口
IAccess ,目的是为生成的代码提供这种链接。这个接口包括三个方法。第一个方法只是设置要访问的目标对象。另外两个方法是用于访问一个
int 属性值的 get 和 set 方法的代理。
清单 2. 到 glue 类的接口public interface IAccess
public void setTarget(Object target);
public int getValue();
public void setValue(int value);
}这里的意图是让
IAccess 接口的生成实现提供调用目标类的相应 get 和 set 方法的代码。清单 3 显示了实现这个接口的一个例子,假定我希望访问
中 HolderBean 类的
value1 属性:
清单 3. Glue 类示例实现public class AccessValue1 implements IAccess
private HolderBean m_
public void setTarget(Object target) {
m_target = (HolderBean)
public int getValue() {
return m_target.getValue1();
public void setValue(int value) {
m_target.setValue1(value);
} 接口设计为针对特定类型对象的特定属性使用。这个接口使实现代码简单了 —— 在处理字节码时这总是一个优点 —— 但是也意味着实现类是非常特定的。对于要通过这个接口访问的每一种类型的对象和属性,都需要一个单独的实现类,这限制了将这种方法作为反射的一般性替代方法。
如果选择只在反射性能真正成为瓶颈的情况下才使用这种技术,那么这种限制就不是一个问题。
用 Javassist 生成
用 Javassist 为
IAccess 接口生成实现类很容易 —— 只需要创建一个实现了这个接口的新类、为目标对象引用添加一个成员变量、最后再添加一个无参构造函数和简单实现方法。清单
4 显示了完成这些步骤的 Javassist 代码,它构造一个方法调用,这个方法以目标类和 get/set 方法信息为参数、并返回所构造的类的二进制表示:
清单 4. Javassist glue 类构造/** Parameter types for call with no parameters. */
private static final CtClass[] NO_ARGS = {};
/** Parameter types for call with single int value. */
private static final CtClass[] INT_ARGS = { CtClass.intType };
protected byte[] createAccess(Class tclas, Method gmeth,
Method smeth, String cname) throws Exception {
// build generator for the new class
String tname = tclas.getName();
ClassPool pool = ClassPool.getDefault();
CtClass clas = pool.makeClass(cname);
clas.addInterface(pool.get("IAccess"));
CtClass target = pool.get(tname);
// add target object field to class
CtField field = new CtField(target, "m_target", clas);
clas.addField(field);
// add public default constructor method to class
CtConstructor cons = new CtConstructor(NO_ARGS, clas);
cons.setBody(";");
clas.addConstructor(cons);
// add public setTarget method
CtMethod meth = new CtMethod(CtClass.voidType, "setTarget",
new CtClass[] { pool.get("java.lang.Object") }, clas);
meth.setBody("m_target = (" + tclas.getName() + ")$1;");
clas.addMethod(meth);
// add public getValue method
meth = new CtMethod(CtClass.intType, "getValue", NO_ARGS, clas);
meth.setBody("return m_target." + gmeth.getName() + "();");
clas.addMethod(meth);
// add public setValue method
meth = new CtMethod(CtClass.voidType, "setValue", INT_ARGS, clas);
meth.setBody("m_target." + smeth.getName() + "($1);");
clas.addMethod(meth);
// return binary representation of completed class
return clas.toBytecode();
}我不准备详细讨论这些代码,因为如果您一直跟着学习本系列,这里的大多数操作都是所熟悉的(如果您
看过本系列,请现在阅读
,了解使用 Javassist 的概述)。
用 BCEL 生成
用 BCEL 生成
IAccess 的实现类不像使用 Javassist 那样容易,但是也不是很复杂。清单 5 给出了相应的代码。
这段代码使用与清单 4 Javassist 代码相同的一组操作,但是运行时间要长一些,因为需要为 BCEL 拼出每一个字节码指令。与使用 Javassist
时一样,我将跳过实现的细节(如果有不熟悉的地方,请参阅
对 BCEL 的概述)。
清单 5. BCEL glue 类构造/** Parameter types for call with single int value. */
private static final Type[] INT_ARGS = { Type.INT };
/** Utility method for adding constructed method to class. */
private static void addMethod(MethodGen mgen, ClassGen cgen) {
mgen.setMaxStack();
mgen.setMaxLocals();
InstructionList ilist = mgen.getInstructionList();
Method method = mgen.getMethod();
ilist.dispose();
cgen.addMethod(method);
protected byte[] createAccess(Class tclas,
java.lang.reflect.Method gmeth, java.lang.reflect.Method smeth,
String cname) {
// build generators for the new class
String tname = tclas.getName();
ClassGen cgen = new ClassGen(cname, "java.lang.Object",
cname + ".java", Constants.ACC_PUBLIC,
new String[] { "IAccess" });
InstructionFactory ifact = new InstructionFactory(cgen);
ConstantPoolGen pgen = cgen.getConstantPool();
//. add target object field to class
FieldGen fgen = new FieldGen(Constants.ACC_PRIVATE,
new ObjectType(tname), "m_target", pgen);
cgen.addField(fgen.getField());
int findex = pgen.addFieldref(cname, "m_target",
Utility.getSignature(tname));
// create instruction list for default constructor
InstructionList ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(ifact.createInvoke("java.lang.Object", "&init&",
Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
ilist.append(InstructionFactory.createReturn(Type.VOID));
// add public default constructor method to class
MethodGen mgen = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
Type.NO_ARGS, null, "&init&", cname, ilist, pgen);
addMethod(mgen, cgen);
// create instruction list for setTarget method
ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(InstructionConstants.ALOAD_1);
ilist.append(new CHECKCAST(pgen.addClass(tname)));
ilist.append(new PUTFIELD(findex));
ilist.append(InstructionConstants.RETURN);
// add public setTarget method
mgen = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
new Type[] { Type.OBJECT }, null, "setTarget", cname,
ilist, pgen);
addMethod(mgen, cgen);
// create instruction list for getValue method
ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(new GETFIELD(findex));
ilist.append(ifact.createInvoke(tname, gmeth.getName(),
Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
ilist.append(InstructionConstants.IRETURN);
// add public getValue method
mgen = new MethodGen(Constants.ACC_PUBLIC, Type.INT,
Type.NO_ARGS, null, "getValue", cname, ilist, pgen);
addMethod(mgen, cgen);
// create instruction list for setValue method
ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(new GETFIELD(findex));
ilist.append(InstructionConstants.ILOAD_1);
ilist.append(ifact.createInvoke(tname, smeth.getName(),
Type.VOID, INT_ARGS, Constants.INVOKEVIRTUAL));
ilist.append(InstructionConstants.RETURN);
// add public setValue method
mgen = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
INT_ARGS, null, "setValue", cname, ilist, pgen);
addMethod(mgen, cgen);
// return bytecode of completed class
return cgen.getJavaClass().getBytes();
已经介绍了 Javassist 和 BCEL 版本的方法构造,现在可以试用它们以了解它们工作的情况。在运行时生成代码的根本理由是用一些更快的的东西取代反射,所以最好加入性能比较以了解在这方面的改进。为了更加有趣,我还将比较用两种框架构造
glue 类所用的时间。清单 6 显示用于检查性能的测试代码的主要部分。
runReflection() 方法运行测试的反射部分,
runAccess()
运行直接访问部分,
run() 控制整个进程(包括打印时间结果)。
runReflection()
runAccess() 都取要执行的次数作为参数,这个参数是以命令行的形式传递的(使用的代码没有在清单中显示,但是包括在下载中)。
DirectLoader
类(在清单 6 的结尾)只提供了装载生成的类的一种容易的方式。
清单 6. 性能测试代码/** Run timed loop using reflection for access to value. */
private int runReflection(int num, Method gmeth, Method smeth,
Object obj) {
int value = 0;
Object[] gargs = new Object[0];
Object[] sargs = new Object[1];
for (int i = 0; i & i++) {
// messy usage of Integer values required in loop
Object result = gmeth.invoke(obj, gargs);
value = ((Integer)result).intValue() + 1;
sargs[0] = new Integer(value);
smeth.invoke(obj, sargs);
} catch (Exception ex) {
ex.printStackTrace(System.err);
System.exit(1);
/** Run timed loop using generated class for access to value. */
private int runAccess(int num, IAccess access, Object obj) {
access.setTarget(obj);
int value = 0;
for (int i = 0; i & i++) {
value = access.getValue() + 1;
access.setValue(value);
public void run(String name, int count) throws Exception {
// get instance and access methods
HolderBean bean = new HolderBean();
String pname =
char lead = pname.charAt(0);
pname = Character.toUpperCase(lead) + pname.substring(1);
Method gmeth =
Method smeth =
gmeth = HolderBean.class.getDeclaredMethod("get" + pname,
new Class[0]);
smeth = HolderBean.class.getDeclaredMethod("set" + pname,
new Class[] { int.class });
} catch (Exception ex) {
System.err.println("No methods found for property " + pname);
ex.printStackTrace(System.err);
// create the access class as a byte array
long base = System.currentTimeMillis();
String cname = "IAccess$impl_HolderBean_" + gmeth.getName() +
"_" + smeth.getName();
byte[] bytes = createAccess(HolderBean.class, gmeth, smeth, cname);
// load and construct an instance of the class
Class clas = s_classLoader.load(cname, bytes);
IAccess access =
access = (IAccess)clas.newInstance();
} catch (IllegalAccessException ex) {
ex.printStackTrace(System.err);
System.exit(1);
} catch (InstantiationException ex) {
ex.printStackTrace(System.err);
System.exit(1);
System.out.println("Generate and load time of " +
(System.currentTimeMillis()-base) + " ms.");
// run the timing comparison
long start = System.currentTimeMillis();
int result = runReflection(count, gmeth, smeth, bean);
long time = System.currentTimeMillis() -
System.out.println("Reflection took " + time +
" ms. with result " + result + " (" + bean.getValue1() +
", " + bean.getValue2() + ")");
bean.setValue1(0);
bean.setValue2(0);
start = System.currentTimeMillis();
result = runAccess(count, access, bean);
time = System.currentTimeMillis() -
System.out.println("Generated took " + time +
" ms. with result " + result + " (" + bean.getValue1() +
", " + bean.getValue2() + ")");
/** Simple-minded loader for constructed classes. */
protected static class DirectLoader extends SecureClassLoader
protected DirectLoader() {
super(TimeCalls.class.getClassLoader());
protected Class load(String name, byte[] data) {
return super.defineClass(name, data, 0, data.length);
}为了进行简单的计时测试,我调用
run() 方法两次,对于
HolderBean 类中的每个属性调用一次。运行两次测试对于测试的公正性是很重要的 —— 第一次运行代码要装载所有必要的类,这对于
Javassist 和 BCEL 类生成过程都会增加大量开销。不过,在第二次运行时不需要这种开销,这样就能更好地估计在实际的系统中使用时,类生成需要多长的时间。
下面是一个执行测试时生成的示例输出:
[dennis]$$ java -cp .:bcel.jar BCELCalls 2000
Generate and load time of 409 ms.
Reflection took 61 ms. with result , 0)
Generated took 2 ms. with result , 0)
Generate and load time of 1 ms.
Reflection took 13 ms. with result 00)
Generated took 2 ms. with result 00)图 1 显示了用从 2k 到 512k 次循环进行调用时计时测试的结果(在运行 Mandrake Linux 9.1 的 Athlon 2200+
XP 系统上运行测试,使用 Sun 1.4.2 JVM )。这里,我在每次测试运行中加入了第二个属性的反射时间和生成的代码的时间(这样首先是使用
Javassist 代码生成的两个时间,然后是使用 BCEL 代码生成时的同样两个时间)。不管是用 Javassist 还是 BCEL 生成
glue 类,执行时间大致是相同的,这也是我预计的结果 —— 但是确认一下总是好的!图 1. 反射速度与生成的代码的速度(时间单位为毫秒)从图 1 中可以看出,不管在什么情况下,生成的代码执行都比反射要快得多。生成的代码的速度优势随着循环次数的增加而增加,在 2k 次循环时大约为
5:1,在 512K 次循环时增加到大约 24:1。对于 Javassist,构造并装载第一个 glue 类需要大约 320 毫秒(ms),而对于
BCEL 则为 370 ms,而构造第二个 glue 类对于 Javassist 只用 4 ms,对于 BCEL 只用 2 ms(由于时钟分辨率只有
1ms,因此这些时间是非常粗略的)。如果将这些时间结合到一起,将会看到即使对于 2k 次循环,生成一个类也比使用反射有更好的整体性能(总执行时间为约
4 ms 到 6 ms,而使用反射时大约为 14 ms)。此外,实际情况比这个图中所表明的更有利于生成的代码。在循环减少至 25 次循环时,反射代码的执行仍然要用 6 ms 到 7 ms,而生成的代码运行得太快以致不能记录。针对相对较少的循环次数,反射所花的时间反映出,当达到一个阈值时在
JVM 中进行了某种优化,如果我将循环次数降低到少于 20,那么反射代码也会快得无法记录。加速上路
现在已经看到了运行时 classworking 可以为应用程序带来什么样的性能。下次面临难处理的性能优化问题时要记住它 —— 它可能就是避免大的重新设计的关键所在。不过,Classworking
不仅有性能上的有好处,它还是一种使应用程序适合运行时要求的灵活方式。即使没有理由在代码中使用它,我也认为它是使编程变得有趣的一种 Java
功能。对一个 classworking 的真实世界应用程序的探讨结束了“Java 编程的动态性”这一系列。但是不要失望 —— 当我展示一些为操纵
Java 字节码而构建的工具时,您很快就有机会在
developerWorks
中了解一些其他的 classworking 应用程序了。首先将是一篇关于
Goose直接推出的两个测试工具的文章。
参考资料 您可以参阅本文在 developerWorks 全球站点上的
在 Peter Haggar 的“
developerWorks,2001
年 7 月)中学习更多有关 Java 字节码设计的内容。
阅读 Nicholas Lesiecki 的 “
developerWorks,2002
年 1 月),以学习有关面向方面编程的更多内容。
请参阅 Bill Venners 的
the Java Virtual Machine(Artima Software, Inc.,2004 年)提供的关于 JVM
体系结构和指令集的很好参考。可以
,以便在购买之前对它有个了解。
,以获得对 JVM 操作的所有方面的权威说明。
开放源代码
提供了非常快速和高度兼容的 Java 编程语言编译器。用它以老式方式生成字节码 —— 从 Java 源代码生成。
以得到技术书籍的完整清单,包括数百本
上可以找到关于 Java 编程的各个方面的上百篇文章。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
免费下载、试用软件产品,构建应用并提升技能。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Java technologyArticleID=53388ArticleTitle=Java 编程的动态性,第 8 部分: 用代码生成取代反射publish-date=114网址导航java目前主流的数据库链接框架 - 开源中国社区
当前访客身份:游客 [
当前位置:
大多数软件公司在java项目中主流的数据库链接框架使用的是:ibatis,hibernate ?或者是其他的。。。
共有3个答案
<span class="a_vote_num" id="a_vote_num_
现在比较流行的java web项目架构是spring mvc框架 + mybatis映射数据库,从市场上来讲,php做中小型企业网站比较合适,性价比高,java偏大型。就性价比而言,很简单的php空间一年才几百块钱,而java空间一个月就得几百。而在语言方面,当然php和java都各领风骚,最主要看自己最擅长哪一种语言了,用过php一段时间,会发现很难习惯其语法,所以最代码也是用java开发的。从开发周期方面来说,性能上java会比php会更占优势。
对于java web开发框架,主要还有下面这些:
1.S2SH(struts2+spring+hibernate)
2.S2SM(struts2+spring+mybatis)
3.SSH(spring mvc+spring+hibernate或struts+spring+hibernate)
4.SSM(spring mvc+spring+mybatis)
5.JSJ(javabean+servlet+jsp)
Java常用框架介绍:
<span class="a_vote_num" id="a_vote_num_
主要还是2种 hibernate ,mybatis
<span class="a_vote_num" id="a_vote_num_
spring mvc+spring+mybatis或spring mvc+spring+hibernate最多.
更多开发者职位上
有什么技术问题吗?
hf20142...的其它问题
类似的话题您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
关于轻量级Java+EE开源框架的网络实验管理系统的设计和实现.pdf69页
本文档一共被下载:
次 ,您可免费全文在线阅读后下载本文档
文档加载中...广告还剩秒
需要金币:200 &&
你可能关注的文档:
··········
··········
基于轻量级Java旺开源框架的网络实验管理系统的设计与
EE JavaEnte叩riseEdition 是使用Java技术开发企业级应用
系统的一种事实上的工业标准,为应用Java技术开发服务器端应用
提供一个平台独立的、可移植的和基于标准的企业级平台,从而简化
了企业级应用的开发、管理和部署。传统JavaEE架构使用啪
Ente巾riseBean ,开发复杂、效率低,依赖第三方容器,测试困
难和部署复杂。轻量级Java
EE框架使用POJo PlajnOrdina哆Java
Object 实现业务逻辑,不会强迫业务对象遵循特定平台的专有接口,
EE应用复杂性和限制。
消除了传统Java
本文分析了轻量级JaVaEE框架的特点,介绍了JavaEE平台系
统的设计技术和设计模式,并对这些软件体系结构进行了比较,介绍
了基于轻量级框架的五层体系结构和各层次使用的流行的开源技术,
利用轻量级的JavaEE开源框架技术设计和实现了网络实验室管理
本文对网络实验管理系统进行了功能需求分析,选择了各个层
次使用的开源框架,表现层使用JSF框架、业务逻辑层使用Sp血g
框架、数据访问层使用Hib锄ate框架,系统各个层次之间实现松耦
合。对系统登录模块、管理员管理模块、日志管理模块等相关功能模
块进行系统设计和代码编写。
关键词:NEMS表现层业务逻辑层数据访问层数据库
ANDIM口LEMENTf盯IONOFNETWORK
EXPERIMENTⅣIANAGEMENTSYSTEMBASED
1ⅥELIGHTWEIGHT乩气 V:
正在加载中,请稍后...

我要回帖

更多关于 网站实现在线支付功能 的文章

 

随机推荐