- 浏览: 21351 次
- 性别:
- 来自: 广州
最新评论
-
ferreousbox:
这种插件模式还不如用java自己的service查找模式,慢是 ...
Nutz寻宝: 万能充电器-Nutz.Plugin -
ferreousbox:
没太觉得这种实现有什么好,这个所谓的插件必须是预知的。而一般的 ...
Nutz寻宝: 万能充电器-Nutz.Plugin -
zozoh:
在 Nutz 首页上我已经更新了
本博客不再更新, 启用自己的blog -
wendal:
zozoh 写道补充一下,nutz-ioc-0.1.xsd 在 ...
Nutz 1.a.27 最新变化之一 -- XML配置ioc -
zozoh:
补充一下,nutz-ioc-0.1.xsd 在:http:// ...
Nutz 1.a.27 最新变化之一 -- XML配置ioc
Aop听得太多了, 用过Aop的JEer也不少,什么Spring Aop,AspectJ等等.
换个角度,为啥不自己写一个Aop拦截器呢? 重新发明轮子又如何?
现在就用最基本的字节码工具来DIY一个Aop. 用反射就太没风度了,那东西,谁不会?!
效果预览:
原有的类
改造后
其中MethodInterceptor是方法拦截器接口:
好,开工!
实现步骤,用个接口来表达吧:
第一步,新建一个类Aop1$$Aop, 等一下, 是用你的字节码工具新建一个类哦,可不要打开eclipse的new class对话框了
asm示例代码:
其中,myName就是"Aop1$$Aop", enhancedSuperName就是父类的名字
第二步, 插入字段(回想一下改造后的类,可是有两个静态私有字段的哦)
asm示例代码:
第三步,继承父类的构造方法(除了private的构造方法),记得添加父类构造方法抛出的异常哦:
asm示例代码:
第四步,插入Aop模板方法(就是那几个private的_Nut_开头的方法)
asm示例代码:
例如插入_Nut_whenError
第五步,重头戏,覆写需要Aop拦截的方法:
首先,需要处理第一个难题: 有无返回值
对于无返回值的方法,解决方案比较简单:
asm示例代码:
对于有返回值的方法,分三种情况, 返回Object(单单指这类方法 public Object dz()),返回基本数据类型,返回其他对象(如返回数组,字符串,枚举,接口,除
Object外的对象)
返回值为Object时,把_Nut_after的返回值直接返回即可,当抛出异常等,则返回null
返回值为基本数据类型时,如int/long/double,把_Nut_after的返回值解包,当抛出异常等,则返回0/false
返回值为其他对象时, 把_Nut_after的返回值 check cast一下,进行强转即可.
解包的代码:
对了对了, 还有一个难点, 处理方法的参数列表,由于_Nut_XXX接受的是Object...args,即一个Object[].
问题就来了, 如果其中某个参数是基本类型呢?恩, 那就得封包了
封包的代码:
参数转为Object[]的代码:
其中visitX为
最后,完成!!
附具体实现(基于asm): [url]http://code.google.com/p/nutzlab/source/browse/#svn/trunk/Nutz.Aop-ASM/Nutz.Aop-ASM[/curl
或者参考另外一篇博文: http://wendal.iteye.com/blog/543681
再次,感谢一下Nutz社区和Peter的支持,没有你们就没有这博文了. O(∩_∩)O哈哈~
Nutz: http://code.google.com/p/nutz/
这么狠? 如果是的话, 得好好测试哦...
嗯,在 /test/org/nutz/aop 下多添几个单元测试
这么狠? 如果是的话, 得好好测试哦...
谁说你文档写的不好的, 我发现你文档写的很好嘛。
收了收了,哈哈
换个角度,为啥不自己写一个Aop拦截器呢? 重新发明轮子又如何?
现在就用最基本的字节码工具来DIY一个Aop. 用反射就太没风度了,那东西,谁不会?!
效果预览:
原有的类
public class Aop1{ public void doSomething() throws Throwable{ //打我啊,拍我啊! } }
改造后
public class Aop1$$Aop extend Aop1{ @Override public void doSomething() throws Throwable{ try { if (_Nut_before(188)) { super.doSomething(); } _Nut_after(188, null); } catch (Exception e) { if(_Nut_Exception(188, e)) throw e; } catch (Throwable e) { if(_Nut_Error(188, e)) throw e; } } private static Method[] _$$Nut_methodArray; private static List<MethodInterceptor>[] _$$Nut_methodInterceptorList; private boolean _Nut_before(int flag_int, Object... args) { Method method = _$$Nut_methodArray[flag_int]; List<MethodInterceptor> miList = _$$Nut_methodInterceptorList[flag_int]; boolean flag = true; for (MethodInterceptor methodInterceptor : miList) flag &= methodInterceptor.beforeInvoke(this, method, args); return flag; } private Object _Nut_after(int flag_int, Object src_return, Object... args) { Method method = _$$Nut_methodArray[flag_int]; List<MethodInterceptor> miList = _$$Nut_methodInterceptorList[flag_int]; for (MethodInterceptor methodInterceptor : miList) src_return = methodInterceptor.afterInvoke(this, src_return, method, args); return src_return; } private boolean _Nut_Exception(int flag_int, Exception e, Object... args) { Method method = _$$Nut_methodArray[flag_int]; List<MethodInterceptor> miList = _$$Nut_methodInterceptorList[flag_int]; boolean flag = true; for (MethodInterceptor methodInterceptor : miList) flag &= methodInterceptor.whenException(e, this, method, args); return flag; } private boolean _Nut_Error(int flag_int, Throwable e, Object... args) { Method method = _$$Nut_methodArray[flag_int]; List<MethodInterceptor> miList = _$$Nut_methodInterceptorList[flag_int]; boolean flag = true; for (MethodInterceptor methodInterceptor : miList) flag &= methodInterceptor.whenError(e, this, method, args); return flag; } }
其中MethodInterceptor是方法拦截器接口:
public interface MethodInterceptor { /** * 在被拦截方法调用之前,将调用该方法。 你可用通过这个方法的返回值,来控制是否真正的调用"被拦截方法"。 * * @param obj * 被调用实例 * @param method * 实例被调用方法 * @param args * 被调用方法所需参数 * @return true,继续调用被拦截方法。false 将不会调用被拦截方法 */ boolean beforeInvoke(Object obj, Method method, Object... args); /** * 你可以通过这个函数,修改被拦截方法的返回值。默认的,你直接将 returnObj 返回即可 * * @param obj * 被调用实例 * @param returnObj * 实例被调用方法的返回 * @param method * 实例被调用方法 * @param args * 被调用方法所需参数 * @return 调用者真正将拿到的对象。 如果,你返回的对象类型是错误的,比如调用者希望得到一个 long, 但是,你拦截了这个方法,并返回一个 * String,那么将发生一个类型转换的错误 */ Object afterInvoke(Object obj, Object returnObj, Method method, Object... args); /** * 当被拦截方法发生异常(Exception),这个方法会被调用。 * * @param e * 异常 * @param obj * 被调用实例 * @param method * 被调用方法 * @param args * 被调用方法所需参数 * * @return 是否继续抛出异常 */ boolean whenException(Exception e, Object obj, Method method, Object... args); /** * 当被拦截方法发生错误(Error),这个方法会被调用。 * * @param e * 错误 * @param obj * 被调用实例 * @param method * 被调用方法 * @param args * 被调用方法所需参数 * * @return 是否继续抛出错误 */ boolean whenError(Throwable e, Object obj, Method method, Object... args); }
好,开工!
实现步骤,用个接口来表达吧:
public interface ClassEnhander{ void addFields(); void addConstructors(); void addAopMethods(); void enhandMethod(); }
第一步,新建一个类Aop1$$Aop, 等一下, 是用你的字节码工具新建一个类哦,可不要打开eclipse的new class对话框了
asm示例代码:
ClassWriter cw= new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_6, ACC_PUBLIC, myName, "", enhancedSuperName, new String[]{});
其中,myName就是"Aop1$$Aop", enhancedSuperName就是父类的名字
第二步, 插入字段(回想一下改造后的类,可是有两个静态私有字段的哦)
asm示例代码:
FieldVisitor fv = cv.visitField(ACC_PRIVATE + ACC_STATIC, "_$$Nut_methodArray", "[Ljava/lang/reflect/Method;", null, null); fv.visitEnd();
FieldVisitor fv = cv.visitField(ACC_PRIVATE + ACC_STATIC, "_$$Nut_methodInterceptorList", "[Ljava/util/List;", "[Ljava/util/List<Lorg/nutz/aop/MethodInterceptor;>;", null); fv.visitEnd();
第三步,继承父类的构造方法(除了private的构造方法),记得添加父类构造方法抛出的异常哦:
asm示例代码:
MethodVisitor mv = cw.visitMethod(access, "<init>", desc,null, expClasses); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); loadArgs(); mv.visitMethodInsn(INVOKESPECIAL, superClassName, "<init>", desc); mv.visitInsn(RETURN); mv.visitMaxs(2, 2); mv.visitEnd();
第四步,插入Aop模板方法(就是那几个private的_Nut_开头的方法)
asm示例代码:
例如插入_Nut_whenError
MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_VARARGS, "_Nut_Error", "(ILjava/lang/Throwable;[Ljava/lang/Object;)Z", null, null); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, _Nut_myName, "_$$Nut_methodArray", "[Ljava/lang/reflect/Method;"); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(AALOAD); mv.visitVarInsn(ASTORE, 4); mv.visitFieldInsn(GETSTATIC, _Nut_myName, "_$$Nut_methodInterceptorList", "[Ljava/util/List;"); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(AALOAD); mv.visitVarInsn(ASTORE, 5); mv.visitInsn(ICONST_1); mv.visitVarInsn(ISTORE, 6); mv.visitVarInsn(ALOAD, 5); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;"); mv.visitVarInsn(ASTORE, 8); Label l0 = new Label(); mv.visitJumpInsn(GOTO, l0); Label l1 = new Label(); mv.visitLabel(l1); mv.visitFrame(Opcodes.F_FULL, 9, new Object[] {_Nut_myName, Opcodes.INTEGER, "java/lang/Throwable", "[Ljava/lang/Object;", "java/lang/reflect/Method", "java/util/List", Opcodes.INTEGER, Opcodes.TOP, "java/util/Iterator"}, 0, new Object[] {}); mv.visitVarInsn(ALOAD, 8); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;"); mv.visitTypeInsn(CHECKCAST, "org/nutz/aop/MethodInterceptor"); mv.visitVarInsn(ASTORE, 7); mv.visitVarInsn(ILOAD, 6); mv.visitVarInsn(ALOAD, 7); mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 4); mv.visitVarInsn(ALOAD, 3); mv.visitMethodInsn(INVOKEINTERFACE, "org/nutz/aop/MethodInterceptor", "whenError", "(Ljava/lang/Throwable;Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Z"); mv.visitInsn(IAND); mv.visitVarInsn(ISTORE, 6); mv.visitLabel(l0); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 8); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z"); mv.visitJumpInsn(IFNE, l1); mv.visitVarInsn(ILOAD, 6); mv.visitInsn(IRETURN); mv.visitMaxs(6, 9); mv.visitEnd();
第五步,重头戏,覆写需要Aop拦截的方法:
首先,需要处理第一个难题: 有无返回值
对于无返回值的方法,解决方案比较简单:
asm示例代码:
MethodVisitor mv = cw.visitMethod(methodAccess, methodName,methodDesc,null, convertExp(method.getExceptionTypes())); mv.visitCode(); Label l0 = new Label(); Label l1 = new Label(); Label l2 = new Label(); mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); Label l3 = new Label(); mv.visitTryCatchBlock(l0, l1, l3, "java/lang/Throwable"); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); mv.visitIntInsn(SIPUSH, methodIndex); loadArgsAsArray(); mv.visitMethodInsn(INVOKESPECIAL, myName, "_Nut_before", "(I[Ljava/lang/Object;)Z"); Label l4 = new Label(); mv.visitJumpInsn(IFEQ, l4); mv.visitVarInsn(ALOAD, 0); loadArgs(); mv.visitMethodInsn(INVOKESPECIAL, enhancedSuperName, methodName, desc); mv.visitLabel(l4); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 0); mv.visitIntInsn(SIPUSH, methodIndex); mv.visitInsn(ACONST_NULL); loadArgsAsArray(); mv.visitMethodInsn(INVOKESPECIAL, myName, "_Nut_after", "(ILjava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitInsn(POP); mv.visitLabel(l1); Label l5 = new Label(); mv.visitJumpInsn(GOTO, l5); mv.visitLabel(l2); mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Exception"}); mv.visitVarInsn(ASTORE, lastIndex); mv.visitVarInsn(ALOAD, 0); mv.visitIntInsn(SIPUSH, methodIndex); mv.visitVarInsn(ALOAD, lastIndex); loadArgsAsArray(); mv.visitMethodInsn(INVOKESPECIAL, myName, "_Nut_Exception", "(ILjava/lang/Exception;[Ljava/lang/Object;)Z"); mv.visitJumpInsn(IFEQ, l5); mv.visitVarInsn(ALOAD, lastIndex); mv.visitInsn(ATHROW); mv.visitLabel(l3); mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"}); mv.visitVarInsn(ASTORE, lastIndex); mv.visitVarInsn(ALOAD, 0); mv.visitIntInsn(SIPUSH, methodIndex); mv.visitVarInsn(ALOAD, lastIndex); loadArgsAsArray(); mv.visitMethodInsn(INVOKESPECIAL, myName, "_Nut_Error", "(ILjava/lang/Throwable;[Ljava/lang/Object;)Z"); mv.visitJumpInsn(IFEQ, l5); mv.visitVarInsn(ALOAD, lastIndex); mv.visitInsn(ATHROW); mv.visitLabel(l5); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); // 自动计算 mv.visitEnd();
对于有返回值的方法,分三种情况, 返回Object(单单指这类方法 public Object dz()),返回基本数据类型,返回其他对象(如返回数组,字符串,枚举,接口,除
Object外的对象)
返回值为Object时,把_Nut_after的返回值直接返回即可,当抛出异常等,则返回null
返回值为基本数据类型时,如int/long/double,把_Nut_after的返回值解包,当抛出异常等,则返回0/false
返回值为其他对象时, 把_Nut_after的返回值 check cast一下,进行强转即可.
解包的代码:
if(type.equals(Type.BOOLEAN_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z"); }else if(type.equals(Type.BYTE_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B"); }else if(type.equals(Type.CHAR_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); }else if(type.equals(Type.SHORT_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S"); }else if(type.equals(Type.INT_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); }else if(type.equals(Type.LONG_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J"); }else if(type.equals(Type.FLOAT_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F"); }else if(type.equals(Type.DOUBLE_TYPE)){ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D"); }
对了对了, 还有一个难点, 处理方法的参数列表,由于_Nut_XXX接受的是Object...args,即一个Object[].
问题就来了, 如果其中某个参数是基本类型呢?恩, 那就得封包了
封包的代码:
if(type.equals(Type.BOOLEAN_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); }else if(type.equals(Type.BYTE_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); }else if(type.equals(Type.CHAR_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); }else if(type.equals(Type.SHORT_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); }else if(type.equals(Type.INT_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); }else if(type.equals(Type.LONG_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); }else if(type.equals(Type.FLOAT_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); }else if(type.equals(Type.DOUBLE_TYPE)){ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); }
参数转为Object[]的代码:
int index = getArgIndex(0); for (int i = 0; i < argumentTypes.length; i++) { mv.visitInsn(DUP); visitX(i); Type t = argumentTypes[i]; loadInsn(t, index); index += t.getSize(); packagePrivateData(t); mv.visitInsn(AASTORE); }
其中visitX为
void visitX(int i){ if(i < 6){ mv.visitInsn(i + ICONST_0); }else{ mv.visitIntInsn(BIPUSH, i); } }
最后,完成!!
附具体实现(基于asm): [url]http://code.google.com/p/nutzlab/source/browse/#svn/trunk/Nutz.Aop-ASM/Nutz.Aop-ASM[/curl
或者参考另外一篇博文: http://wendal.iteye.com/blog/543681
再次,感谢一下Nutz社区和Peter的支持,没有你们就没有这博文了. O(∩_∩)O哈哈~
Nutz: http://code.google.com/p/nutz/
评论
5 楼
vb2005xu
2009-12-09
Nutz 如果能够实现动态对象类型探测,那就太好了...
4 楼
zozoh
2009-12-08
wendal 写道
zozoh 写道
Nutz 1.a.24,要不然,我把 Javassist 删了,就用你这个实现得了
这么狠? 如果是的话, 得好好测试哦...
嗯,在 /test/org/nutz/aop 下多添几个单元测试
3 楼
wendal
2009-12-08
zozoh 写道
Nutz 1.a.24,要不然,我把 Javassist 删了,就用你这个实现得了
这么狠? 如果是的话, 得好好测试哦...
2 楼
zozoh
2009-12-08
Nutz 1.a.24,要不然,我把 Javassist 删了,就用你这个实现得了
1 楼
zozoh
2009-12-08
谁说你文档写的不好的, 我发现你文档写的很好嘛。
收了收了,哈哈
发表评论
-
本博客不再更新, 启用自己的blog
2010-10-26 17:24 1977我的新blog: http://wendal.net 使用v ... -
Nutz 1.a.27 最新变化之一 -- XML配置ioc
2010-04-28 08:15 3229刚刚发布的Nutz 1.a.27 , 正式支持使用XML来配置 ... -
Nutz寻宝: 万能充电器-Nutz.Plugin
2009-12-21 14:08 2042想了解更多,猛击http://nutzhome.appspot ... -
Nutz寻宝: 咖啡糖-Nutz.Lang
2009-12-21 14:00 3198想了解更多,猛击http://nutzhome.appspot ... -
Nutz:基于ASM的Nut.Aop实现
2009-12-07 22:21 5014Nutz: 一个很不错的SSH替代方案 http://code ...
相关推荐
【Nutz代码生成器】是基于Nutz框架开发的一款实用工具,主要用于自动化生成Action和实体类代码,极大地提高了开发效率,降低了手动编写这些基础代码的工作量。Nutz是一款轻量级、高性能的Java开发框架,它集合了ORM...
该项目为全栈Java开发,采用Nutz框架实现Mvc/Ioc/Aop/Dao/Json一体化设计,源码包含2307个文件,涵盖1742个Java源文件、208个man文档、143个png图片...Nutz框架旨在为所有Java开发者提供一个高效、易用的全栈解决方案。
在给定的压缩包"nutz生成javabean工具.zip"中,我们可以看到一个名为"NutzCodematic-master"的项目,这很可能是Nutz提供的一个用于自动化生成JavaBean类的工具。下面我们将详细探讨Nutz Codematic及其在Java开发中的...
Nutz是一个基于Java的轻量级框架,它提供了一系列实用工具和高质量的模块,使得Java开发者可以更加高效地进行Web应用开发。Nutz的核心特点包括轻量、快速、灵活,以及对现有Java生态系统的良好集成。这个压缩包文件...
标题“nutz学习资料2”表明这是一份关于Nutz框架的学习资源集合,Nutz是一个基于Java的轻量级框架,旨在提供全面的MVC支持和企业级开发工具。通过这个压缩包,我们可以期待深入理解Nutz框架的核心特性和使用方法。 ...
Nutz是一个轻量级、高性能的Java开发框架,它提供了丰富的功能,包括MVC、ORM、DAO、AOP、IOC等,使得Java开发者能够快速地构建应用系统。本篇文章将详细探讨Nutz框架中所需的jar包以及它们在项目中的作用。 首先,...
jBeanBox是一个微形但功能较齐全的IOC/AOP工具,用于Java6或以上环境。 jBeanBox项目的定位:需要一个功能较全的IOC/AOP工具,但是又不想引入臃肿的Spring。 其它IOC/AOP工具的问题: Spring: 源码臃肿,Java方式...
Nutz是一个轻量级、高性能的Java开发框架,它的设计目标是简化开发流程,提高开发效率。Nutzmore则是Nutz框架的一个扩展集合,包含了众多实用的插件和集成库,为开发者提供了更多的功能和便利。这个项目由Nutz社区...
Nutz是一个简洁高效的Java开发框架,它提供了ORM、DAO、IOC、AOP等功能,使得开发过程更为简便。Nutz的核心理念是“简单就是美”,它的API设计清晰,学习曲线平缓。要使用Nutz,首先需要在项目中引入Nutz的依赖库,...
“Nutz迷你项目”是一个基于Nutz框架的小型项目实例,旨在帮助开发者快速理解和应用Nutz这个轻量级Java开发框架。Nutz是由中国的一群开源爱好者开发的,它提供了包括ORM、HTTP客户端、JSON处理、缓存管理等在内的...
NUTZ是一个轻量级、高性能的Java开发框架,它为开发者提供了全面的工具和库,使得构建Web应用变得更加高效和便捷。这个压缩包“wendal-nutz-master.zip”包含了NUTZ框架的一个示例项目或者学习资源,帮助初学者理解...
Nutz是一个基于Java的轻量级、高性能的开源框架,它集合了IoC(Inversion of Control,控制反转)、AOP(Aspect Oriented Programming,面向切面编程)以及MVC(Model-View-Controller,模型-视图-控制器)等特性,...
今天,我们要探讨的是一个名为Nutz的Java框架,它以其轻量级、高效能和全面的特性,成为了众多开发者眼中的宝藏工具。通过这篇详细的文章,我们将深入理解Nutz的基本概念,了解其核心功能,并通过一个简单的...
Nutz是一个轻量级、高性能的Java开源框架,它提供了丰富的功能,包括MVC(Model-View-Controller)架构支持,使得开发者能够快速构建小型到中型的Web应用。本篇文章将详细介绍如何利用Nutz搭建MVC框架,并探讨其在...
- Nutz是一个基于Java的开源框架,它提供了一套全面的工具集,包括MVC、ORM、DAO、AOP等,以提高开发效率。 - Nutz的核心理念是简洁和高效,它鼓励开发者使用原生的Java代码,而不是过度依赖框架。 - Nutz的MVC...
### Nutz框架开发手册知识点详解 #### 一、引言 - **背景介绍**:随着Web开发技术的不断发展,Java虽然仍然占据着...对于寻求提高开发效率而又不想过度依赖复杂框架的Java开发者而言,Nutz无疑是一个值得尝试的选择。
Nutz 是一个全面的Java开发框架,旨在提供高效、稳定且易于使用的工具和服务。"nutz-1.r.61-发布包"是Nutz框架的一个版本更新,具体为1.r.61版本。这个发布包包含了该版本的文档、源代码、编译后的类库以及相关的...
在开发Java应用时,Nutz Redis模块是一个非常实用的工具,它使得我们能够方便地将Nutz框架与Redis键值存储系统相结合。本篇文章将详细阐述Nutz Redis集成过程中的关键知识点,以及如何避免因依赖包问题导致的困扰。 ...