- 浏览: 258854 次
- 性别:
- 来自: 未定
文章分类
最新评论
-
zl544434558:
最后一行</filter> 多余的
Springmvc 乱码问题 -
imknown:
方法有效,感谢博主!
Springmvc 乱码问题 -
notafreak:
方法有效,感谢博主
Springmvc 乱码问题 -
linvar:
ligangdufs 写道 what about resin ...
Springmvc 乱码问题 -
ligangdufs:
what about resin
Springmvc 乱码问题
java反射与代理
一. 关于数据库.
当今的数据处理大致可以分成两大类:联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。下表列出了OLTP与OLAP之间的比较。
OLTP OLAP
用户 操作人员,低层管理人员 决策人员,高级管理人员
功能 日常操作处理 分析决策
DB 设计 面向应用 面向主题
数据 当前的, 最新的细节的, 二维的分立的 历史的, 聚集的, 多维的集成的, 统一的
存取 读/写数十条记录 读上百万条记录
工作单位 简单的事务 复杂的查询
用户数 上千个 上百个
DB 大小 100MB-GB 100GB-TB
二. Java中的类反射:
反射就是把Java类中的各种成分映射成相应的java类.
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。
1.检测类:
1.1 reflection的工作机制
考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。
按如下语句执行:
java DumpMethods java.util.Stack
它的结果输出为:
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。
这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。
1.2 Java类反射中的主要方法
对于以下三类组件中的任何一类来说 -- 构造函数、字段和方法 -- java.lang.Class 提供四种独立的反射调用,以不同的方式来获得信息。调用都遵循一种标准格式。以下是用于查找构造函数的一组反射调用:
Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,
Constructor[] getConstructors() -- 获得类的所有公共构造函数
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)
获得字段信息的Class 反射调用不同于那些用于接入构造函数的调用,在参数类型数组中使用了字段名:
Field getField(String name) -- 获得命名的公共字段
Field[] getFields() -- 获得类的所有公共字段
Field getDeclaredField(String name) -- 获得类声明的命名的字段
Field[] getDeclaredFields() -- 获得类声明的所有字段
用于获得方法信息函数:
Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法
Method[] getMethods() -- 获得类的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法
Method[] getDeclaredMethods() -- 获得类声明的所有方法
1.3开始使用 Reflection:
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
下面就是获得一个 Class 对象的方法之一:
Class c = Class.forName("java.lang.String");
这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。
第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:
它将以文本方式打印出 String 中定义的第一个方法的原型。
2.处理对象:
如果要作一个开发工具像debugger之类的,你必须能发现filed values,以下是三个步骤:
a.创建一个Class对象
b.通过getField 创建一个Field对象
c.调用Field.getXXX(Object)方法(XXX是Int,Float等,如果是对象就省略;Object是指实例).
例如:
顾名思义,反射 (reflection) 机制就像是在吴承恩所写的西游记中所提及的「照妖镜」,可以让类别或对象 (object) 在执行时期「现出原形」。我们可以利用反射机制来深入了解某类(class) 的构造函数 (constructor)、方法 (method)、字段 (field),甚至可以改变字段的值、呼叫方法、建立新的对象。有了反射机制,程序员即使对所想使用的类别所知不多,也能照样写程序。反射机制能够用来呼叫方法,这正是反射机制能够取代函数指针的原因。
以 Java 来说,java.lang.reflect.Method (以下简称 Method) 类别是用来表示某类别的某方法。我们可以透过 java.lang.Class (以下简称 Class) 类别的许多方法来取得 Method 对象。Method 类别提供 invoke() 方法,透过 invoke(),此 Method 对象所表示的方法可以被呼叫,所有的参数则是被组织成一个数组,以方便传入 invoke()。
举个例子,下面是一个名为 Invoke 的程序,它会将命令列的 Java 类别名称和要呼叫的方法名称作为参数。为了简单起见,我假定此方法是静态的,且没有参数:
java Invoke java.lang.System CurrentTimeMillis执行的结果如下所示:
java.lang.System.currentTimeMillis() = 1049551169474我们的第一步就是用名称去寻找指定的 Class。我们用类别名称 (命令列的第一个参数) 去呼叫 forName() 方法,然后用方法名称 (命令列的第二个参数) 去取得方法。getMethod() 方法有两个参数:第一个是方法名称 (命令列的第二个参数),第二个是 Class 对象的数组,这个阵例指明了方法的 signature (任何方法都可能会被多载,所以必须指定 signature 来分辨。) 因为我们的简单程序只呼叫没有参数的方法,我们建立一个 Class 对象的匿名空数组。如果我们想要呼叫有参数的方法,我们可以传递一个类别数组,数组的内容是各个类别的型态,依顺序排列。
一旦我们有了 Method 对象,就呼叫它的 invoke() 方法,这会造成我们的目标方法被调用,并且将结果以 Object 对象传回。如果要对此对象做其它额外的事,你必须将它转型为更精确的型态。
invoke() 方法的第一个参数就是我们想要呼叫目标方法的对象,如果该方法是静态的,就没有对象,所以我们把第一个参数设为 null,这就是我们范例中的情形。第二个参数是要传给目标方法作为参数的对象数组,它们的型态要符合呼叫 getMethod() 方法中所指定的型态。因为我们呼叫的方法没有参数,所以我们传递 null 作为 invoke() 的第二个参数。
三. 代理(Proxy)
1.
我们直接从代码入手吧,我们可以使用一个动态代理类(Proxy),通过拦截一个对象的行为并添加我们需要的功能来完成。Java中的java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口为我们实现动态代理类提供了一个方案,但是该方案针对的对象要实现某些接口;如果针对的目的是类的话,cglib为我们提供了另外一个实现方案。等下会说明两者的区别。
一、接口的实现方案:
1)首先编写我们的业务接口(StudentInfoService.java):
2)现在我们需要一个日志功能,在findInfo行为之前执行并记录其行为,那么我们就首先要拦截该行为。在实际执行的过程中用一个代理类来替我们完成。Java中为我们提供了实现动态代理类的方案:
1'处理拦截目的的类(MyHandler.java)
3)基本的拦截与其工厂我们都实现了,现在测试(ClientTest.java):
[INFO]调用log日志方法findInfo
你目前输入的名字是:阿飞
这样我们需要的效果就出来了,业务处理自己在进行,但是我们实现了日志功能
2.再看一个例子:
假设系统由一系列的BusinessObject所完成业务逻辑功能,系统要求在每一次业务逻辑处理时要做日志记录。这里我们略去具体的业务逻辑代码。
这里处理商业逻辑的代码和日志记录代码混合在一起,这给日后的维护带来一定的困难,并且也会造成大量的代码重复。完全相同的log代码将出现在系统的每一个BusinessObject中。
按照AOP的思想,我们应该把日志记录代码分离出来。要将这些代码分离就涉及到一个问题,我们必须知道商业逻辑代码何时被调用,这样我们好插入日志记录代码。一般来说要截获一个方法,我们可以采用回调方法或者动态代理。动态代理一般要更加灵活一些,目前多数的AOP Framework也大都采用了动态代理来实现。这里我们也采用动态代理作为例子。
JDK1.2以后提供了动态代理的支持,程序员通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行商业方法,在商业方法被调用的同时,执行处理器会被自动调用。
有了JDK的这种支持,我们所要做的仅仅是提供一个日志处理器。
现在我们可以把BusinessObject里面的所有日志处理代码全部去掉了。
客户端调用商业方法的代码如下:
程序输出如下:
INFO: method stats...
here is business logic
INFO: method ends...
至此我们的第一次小尝试算是完成了。可以看到,采用AOP之后,日志记录和业务逻辑代码完全分开了,以后要改变日志记录的话只需要修改日志记录处理器就行了,而业务对象本身(BusinessObject)无需做任何修改。并且这个日志记录不会造成重复代码了,所有的商业处理对象都可以重用这个日志处理器。
一. 关于数据库.
当今的数据处理大致可以分成两大类:联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)。OLTP是传统的关系型数据库的主要应用,主要是基本的、日常的事务处理,例如银行交易。OLAP是数据仓库系统的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。下表列出了OLTP与OLAP之间的比较。
OLTP OLAP
用户 操作人员,低层管理人员 决策人员,高级管理人员
功能 日常操作处理 分析决策
DB 设计 面向应用 面向主题
数据 当前的, 最新的细节的, 二维的分立的 历史的, 聚集的, 多维的集成的, 统一的
存取 读/写数十条记录 读上百万条记录
工作单位 简单的事务 复杂的查询
用户数 上千个 上百个
DB 大小 100MB-GB 100GB-TB
二. Java中的类反射:
反射就是把Java类中的各种成分映射成相应的java类.
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。
1.检测类:
1.1 reflection的工作机制
考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。
import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); } } }
按如下语句执行:
java DumpMethods java.util.Stack
它的结果输出为:
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。
这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。
1.2 Java类反射中的主要方法
对于以下三类组件中的任何一类来说 -- 构造函数、字段和方法 -- java.lang.Class 提供四种独立的反射调用,以不同的方式来获得信息。调用都遵循一种标准格式。以下是用于查找构造函数的一组反射调用:
Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,
Constructor[] getConstructors() -- 获得类的所有公共构造函数
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)
获得字段信息的Class 反射调用不同于那些用于接入构造函数的调用,在参数类型数组中使用了字段名:
Field getField(String name) -- 获得命名的公共字段
Field[] getFields() -- 获得类的所有公共字段
Field getDeclaredField(String name) -- 获得类声明的命名的字段
Field[] getDeclaredFields() -- 获得类声明的所有字段
用于获得方法信息函数:
Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法
Method[] getMethods() -- 获得类的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法
Method[] getDeclaredMethods() -- 获得类声明的所有方法
1.3开始使用 Reflection:
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
下面就是获得一个 Class 对象的方法之一:
Class c = Class.forName("java.lang.String");
这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。
第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:
Class c = Class.forName("java.lang.String"); Method m[] = c.getDeclaredMethods(); System.out.println(m[0].toString());
它将以文本方式打印出 String 中定义的第一个方法的原型。
2.处理对象:
如果要作一个开发工具像debugger之类的,你必须能发现filed values,以下是三个步骤:
a.创建一个Class对象
b.通过getField 创建一个Field对象
c.调用Field.getXXX(Object)方法(XXX是Int,Float等,如果是对象就省略;Object是指实例).
例如:
import java.lang.reflect.*; import java.awt.*; class SampleGet { public static void main(String[] args) { Rectangle r = new Rectangle(100, 325); printHeight(r); } static void printHeight(Rectangle r) { Field heightField; Integer heightValue; Class c = r.getClass(); try { heightField = c.getField("height"); heightValue = (Integer) heightField.get(r); System.out.println("Height: " + heightValue.toString()); } catch (NoSuchFieldException e) { System.out.println(e); } catch (SecurityException e) { System.out.println(e); } catch (IllegalAccessException e) { System.out.println(e); } } }
顾名思义,反射 (reflection) 机制就像是在吴承恩所写的西游记中所提及的「照妖镜」,可以让类别或对象 (object) 在执行时期「现出原形」。我们可以利用反射机制来深入了解某类(class) 的构造函数 (constructor)、方法 (method)、字段 (field),甚至可以改变字段的值、呼叫方法、建立新的对象。有了反射机制,程序员即使对所想使用的类别所知不多,也能照样写程序。反射机制能够用来呼叫方法,这正是反射机制能够取代函数指针的原因。
以 Java 来说,java.lang.reflect.Method (以下简称 Method) 类别是用来表示某类别的某方法。我们可以透过 java.lang.Class (以下简称 Class) 类别的许多方法来取得 Method 对象。Method 类别提供 invoke() 方法,透过 invoke(),此 Method 对象所表示的方法可以被呼叫,所有的参数则是被组织成一个数组,以方便传入 invoke()。
举个例子,下面是一个名为 Invoke 的程序,它会将命令列的 Java 类别名称和要呼叫的方法名称作为参数。为了简单起见,我假定此方法是静态的,且没有参数:
import java.lang.reflect.*; class Invoke { public static void main(String[] args ) { try { Class c = Class.forName( args[0] ); Method m = c.getMethod( args[1], new Class [] { } ); Object ret = m.invoke( null, null ); System.out.println(args[0] + "." + args[1] +"() = " + ret ); } catch ( ClassNotFoundException ex ) { System.out.println("找不到此类别"); } catch (NoSuchMethodException ex ) { System.out.println("此方法不存在"); } catch (IllegalAccessException ex ) { System.out.println("没有权限调用此方法"); } catch (InvocationTargetException ex ) { System.out.println("调用此方法时发生下列例外:\n" + ex.getTargetException() ); } } }我们可以执行 Invoke 来取得系统的时间:
java Invoke java.lang.System CurrentTimeMillis执行的结果如下所示:
java.lang.System.currentTimeMillis() = 1049551169474我们的第一步就是用名称去寻找指定的 Class。我们用类别名称 (命令列的第一个参数) 去呼叫 forName() 方法,然后用方法名称 (命令列的第二个参数) 去取得方法。getMethod() 方法有两个参数:第一个是方法名称 (命令列的第二个参数),第二个是 Class 对象的数组,这个阵例指明了方法的 signature (任何方法都可能会被多载,所以必须指定 signature 来分辨。) 因为我们的简单程序只呼叫没有参数的方法,我们建立一个 Class 对象的匿名空数组。如果我们想要呼叫有参数的方法,我们可以传递一个类别数组,数组的内容是各个类别的型态,依顺序排列。
一旦我们有了 Method 对象,就呼叫它的 invoke() 方法,这会造成我们的目标方法被调用,并且将结果以 Object 对象传回。如果要对此对象做其它额外的事,你必须将它转型为更精确的型态。
invoke() 方法的第一个参数就是我们想要呼叫目标方法的对象,如果该方法是静态的,就没有对象,所以我们把第一个参数设为 null,这就是我们范例中的情形。第二个参数是要传给目标方法作为参数的对象数组,它们的型态要符合呼叫 getMethod() 方法中所指定的型态。因为我们呼叫的方法没有参数,所以我们传递 null 作为 invoke() 的第二个参数。
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; public class TestRef { public static void main(String[] args) throws Exception { TestRef testRef = new TestRef(); Class clazz = TestRef. class ; System.out.println( " getPackage() = " + clazz.getPackage().getName()); // getModifiers()的返回值可以包含类的种类信息。比如是否为public,abstract,static int mod = clazz.getModifiers(); System.out.println( " Modifier.isAbstract(mod) = " + Modifier.isAbstract(mod)); System.out.println( " getName() = " + clazz.getName()); System.out.println( " getSuperclass() = " + clazz.getSuperclass().getName()); System.out.println( " getInterfaces() = " + clazz.getInterfaces()); // 实现了哪些Interface System.out.println( " clazz.getDeclaredClasses() = " + clazz.getDeclaredClasses()); // 包含哪些内部类 System.out.println( " getDeclaringClass() = " + clazz.getDeclaringClass()); // 如果clazz是inner class 那么返回其outer class System.out.println( " ---------- " ); Constructor[] constructor = clazz.getDeclaredConstructors(); // 返回一组构造函数 Constructor[] if (constructor != null ) { for ( int i = 0 ; i < constructor.length; i ++ ) { System.out.println(constructor[i].getName()); } } System.out.println( " ---------- " ); Method[] method = clazz.getDeclaredMethods(); // Method[] if (method != null ) { for ( int i = 0 ; i < method.length; i ++ ) { System.out.println(method[i].getName()); } } System.out.println( " ---------- " ); Field[] field = clazz.getDeclaredFields(); // Field[] if (field != null ) { for ( int i = 0 ; i < field.length; i ++ ) { System.out.println(field[i].getName()); System.out.println(field[i].getType().getName()); System.out.println(field[i].get(testRef)); } } // 动态生成instance(无参数) Class clz = Class.forName( " reflection.TestRef " ); Object obj = clz.newInstance(); System.out.println(((TestRef)obj).getStr()); // 动态生成instance(有参数) Class[] params = new Class[] {String. class , int . class , double . class } ; Constructor construct = clz.getConstructor(params); // JDK1.5的情况下可以直接用{"haha",999,100.01}作为参数 Object obj2 = construct.newInstance(new Object[]{"haha",new Integer( 999 ), new Double( 100.01 )} ); System.out.println(((TestRef)obj2).getStr()); // 动态调用method(public method) Class[] params2 = new Class[] {String. class } ; Method methods = clz.getMethod( " setStr " , params2); methods.invoke(testRef, new Object[] { " invoke method " } ); System.out.println(testRef.getStr()); // 动态改变field内容(public field) Field fields = clz.getField( " str " ); fields.set(testRef, " set field's value " ); System.out.println(testRef.getStr()); } public TestRef() { System.out.println( " --- complete TestRef() --- " ); } public TestRef(String str, int i, double d) { this .str = str; this .i = i; this .d = d; System.out.println( " --- complete TestRef(String str, int i, double d) --- " ); } public String str = " I'm a string " ; int i = 1 ; double d = 3.14 ; HashMap map = new HashMap(); public double getD() { return d; } public void setD( double d) { this .d = d; } public int getI() { return i; } public void setI( int i) { this .i = i; } public HashMap getMap() { return map; } public void setMap(HashMap map) { this .map = map; } public String getStr() { return str; } public void setStr(String str) { this .str = str; } }
三. 代理(Proxy)
1.
我们直接从代码入手吧,我们可以使用一个动态代理类(Proxy),通过拦截一个对象的行为并添加我们需要的功能来完成。Java中的java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口为我们实现动态代理类提供了一个方案,但是该方案针对的对象要实现某些接口;如果针对的目的是类的话,cglib为我们提供了另外一个实现方案。等下会说明两者的区别。
一、接口的实现方案:
1)首先编写我们的业务接口(StudentInfoService.java):
public interface StudentInfoService{ void findInfo(String studentName); } 及其实现类(StudentInfoServiceImpl.java): public class StudentInfoServiceImpl implements StudentInfoService{ public void findInfo(String name){ System.out.println("你目前输入的名字是:"+name); } }
2)现在我们需要一个日志功能,在findInfo行为之前执行并记录其行为,那么我们就首先要拦截该行为。在实际执行的过程中用一个代理类来替我们完成。Java中为我们提供了实现动态代理类的方案:
1'处理拦截目的的类(MyHandler.java)
import org.apache.log4j.Logger; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.lang.reflect.Method; public class MyHandler implements InvocationHandler{ private Object proxyObj; private static Logger log=Logger.getLogger(MyHandler.class); public Object bind(Object obj){ this.proxyObj=obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this); } public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{ Object result=null; try{ //请在这里插入代码,在方法前调用 log.info("调用log日志方法"+method.getName()); result=method.invoke(proxyObj,args); //原方法 //请在这里插入代码,方法后调用 }catch(Exception e){ e.printStackTrace(); } return result; } } 2'我们实现一个工厂,为了方便我们使用该拦截类(AOPFactory.java): public class AOPFactory{ private static Object getClassInstance(String clzName){ Object obj=null; try{ Class cls=Class.forName(clzName); obj=(Object)cls.newInstance(); }catch(ClassNotFoundException cnfe){ System.out.println("ClassNotFoundException:"+cnfe.getMessage()); }catch(Exception e){ e.printStackTrace(); } return obj; } public static Object getAOPProxyedObject(String clzName){ Object proxy=null; MyHandler handler=new MyHandler(); Object obj=getClassInstance(clzName); if(obj!=null) { proxy=handler.bind(obj); }else{ System.out.println("Can't get the proxyobj"); //throw } return proxy; } }
3)基本的拦截与其工厂我们都实现了,现在测试(ClientTest.java):
public class ClientTest{ public static void main(String[] args){ StudentInfoService studentInfo=(StudentInfoService)AOPFactory.getAOPProxyedObject("StudentInfoServiceImpl"); studentInfo.findInfo("阿飞"); } }输出结果(看你的log4j设置):
[INFO]调用log日志方法findInfo
你目前输入的名字是:阿飞
这样我们需要的效果就出来了,业务处理自己在进行,但是我们实现了日志功能
2.再看一个例子:
假设系统由一系列的BusinessObject所完成业务逻辑功能,系统要求在每一次业务逻辑处理时要做日志记录。这里我们略去具体的业务逻辑代码。
public interface BusinessInterface { public void processBusiness(); } public class BusinessObject implements BusinessInterface { private Logger logger = Logger.getLogger(this.getClass().getName()); public void processBusiness(){ try { logger.info("start to processing..."); //business logic here. System.out.println(“here is business logic”); logger.info("end processing..."); } catch (Exception e){ logger.info("exception happends..."); //exception handling } } }
这里处理商业逻辑的代码和日志记录代码混合在一起,这给日后的维护带来一定的困难,并且也会造成大量的代码重复。完全相同的log代码将出现在系统的每一个BusinessObject中。
按照AOP的思想,我们应该把日志记录代码分离出来。要将这些代码分离就涉及到一个问题,我们必须知道商业逻辑代码何时被调用,这样我们好插入日志记录代码。一般来说要截获一个方法,我们可以采用回调方法或者动态代理。动态代理一般要更加灵活一些,目前多数的AOP Framework也大都采用了动态代理来实现。这里我们也采用动态代理作为例子。
JDK1.2以后提供了动态代理的支持,程序员通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行商业方法,在商业方法被调用的同时,执行处理器会被自动调用。
有了JDK的这种支持,我们所要做的仅仅是提供一个日志处理器。
public class LogHandler implements InvocationHandler { private Logger logger = Logger.getLogger(this.getClass().getName()); private Object delegate; public LogHandler(Object delegate){ this.delegate = delegate; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object o = null; try { logger.info("method stats..." + method); o = method.invoke(delegate,args); logger.info("method ends..." + method); } catch (Exception e){ logger.info("Exception happends..."); //excetpion handling. } return o; } }
现在我们可以把BusinessObject里面的所有日志处理代码全部去掉了。
public class BusinessObject implements BusinessInterface { private Logger logger = Logger.getLogger(this.getClass().getName()); public void processBusiness(){ //business processing System.out.println(“here is business logic”); } }
客户端调用商业方法的代码如下:
BusinessInterface businessImp = new BusinessObject(); InvocationHandler handler = new LogHandler(businessImp); BusinessInterface proxy = (BusinessInterface) Proxy.newProxyInstance( businessImp.getClass().getClassLoader(), businessImp.getClass().getInterfaces(), handler); proxy.processBusiness();
程序输出如下:
INFO: method stats...
here is business logic
INFO: method ends...
至此我们的第一次小尝试算是完成了。可以看到,采用AOP之后,日志记录和业务逻辑代码完全分开了,以后要改变日志记录的话只需要修改日志记录处理器就行了,而业务对象本身(BusinessObject)无需做任何修改。并且这个日志记录不会造成重复代码了,所有的商业处理对象都可以重用这个日志处理器。
发表评论
-
Springmvc 乱码问题
2012-08-24 22:54 12105后端的Tomcat server.xml里配置的<Con ... -
logback note
2012-04-01 16:35 01.logback核心 a.Logger(记录者), b.A ... -
java Cookie
2011-11-01 21:33 1377cookie的组成部分: key, value, maxage ... -
java 正则表达式
2011-10-30 14:53 2140正则表达式的关键是 创建用于"在源字符串中匹配出某些 ... -
java email
2011-10-27 17:04 0http://coolshell.cn/articles/42 ... -
java 定时器
2011-10-27 11:26 01.java.util.Timer 1.1 对应单个后台线程 ... -
Resin note1
2011-06-27 23:11 1656<cluster-default> ... -
Maven note2
2011-04-25 14:16 01.The Build Lifecycle A build ... -
Maven note1
2011-04-24 18:07 01.What is Maven Although there ... -
freemarker使用总结
2010-06-20 16:51 35041.freemarker在使用spring MVC时会出现乱 ... -
springmvc 笔记
2010-05-22 10:27 6830struct2很不好用,springmvc比较给力,跟spr ... -
ibatis3 的返回值
2010-05-11 16:43 1179当执行sqlSession.selectOne("& ... -
java static util, helper
2010-04-18 19:50 1573我们经常会写一些util,helper类, 而一般这些类的方 ... -
Quartz 使用笔记
2010-04-16 21:35 14181.Quartz的主要构件: SchedulerFactory ... -
pinyin4j 笔记
2010-04-05 21:00 1804最近需要将城市名称转换为拼音去访问google weather ... -
ibatis3 的变量
2010-04-05 10:12 1754ibatis的变量其实没什么特别,就是使用#{}定义, 比如 ... -
VPS中的resin3.1和tomcat6
2010-03-28 11:00 1762兴冲冲地在VPS安装了jdk1.6, resin-pro-3. ... -
java URL encoding and decoding
2010-03-19 09:48 8673HTML编码规则是: 字符"a"-&quo ... -
Cookie小解
2010-03-18 19:27 1250Cookie是客户端与服务器 ... -
ibatis3的使用参考
2010-03-12 17:03 3947以前用过ibatis2,但是听说ibatis3有较大的性能提升 ...
相关推荐
在"JAVA反射与代理"这个主题中,我们将深入探讨这两个核心概念。 首先,让我们了解反射的基本用法。当一个类的名称在运行时才被知道,反射可以帮助我们动态地创建对象。例如,我们可以使用`Class.forName()`方法...
### Java反射与代理实现AOP #### 一、AOP概念及应用场景 AOP(Aspect-Oriented Programming,面向切面编程)是一种编程思想和技术,主要用于处理横切关注点问题,比如日志记录、性能统计、安全控制、事务处理、...
Java反射是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类包括`Class`、`Field`、`Method`和`Constructor`,它们分别代表类、...
Java反射和动态代理是Java编程中的重要特性,它们在实现高度灵活和动态的代码执行方面发挥着关键作用。本文将深入探讨这两个概念及其在实际开发中的应用。 **Java反射** Java反射API允许程序在运行时检查类、接口...
Java反射和动态代理是Java编程中的重要特性,它们在实现高度灵活和动态的代码执行上发挥着关键作用。本文将深入探讨这两个概念,以及如何在实际开发中利用它们。 首先,我们来理解Java反射(Reflection)。Java反射...
Java的反射机制与动态代理是Java编程中两个非常重要的高级特性,它们在许多实际场景中发挥着关键作用,如框架开发、插件系统、元数据处理等。下面将详细讲解这两个概念及其应用。 首先,Java的反射机制允许我们在...
Java反射是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并操作类的对象。在Java中,反射机制提供了强大的能力,包括在运行时检查类的结构、创建对象实例、调用方法以及访问和修改字段值。...
JAVA反射机制与动态代理.part04
详细讲解java的reflect包的,阐述反射机制及动态代理的细节问题。其中动态代理部分内容参考网上资料。读完此文,相信会对javaf反射机制有一个完整清楚的了解。尤其应该看看其他中代码举例部分。
Java反射和动态代理是Java编程中的重要特性,它们在实现高度灵活和动态的代码执行上发挥着关键作用。本文将深入探讨这两个概念及其在实际开发中的应用。 **Java反射** Java反射API允许程序在运行时检查类、接口、...
总的来说,Java反射机制和动态代理是Java平台强大而灵活的特性,它们使得Java程序能够在运行时具有更高的灵活性和可扩展性。然而,使用反射也可能带来性能开销和安全风险,因此在实际应用中需要权衡利弊,合理使用。
在这个主题中,我们将深入探讨Java反射和动态代理如何帮助我们实现IOC。 首先,让我们理解Java反射。反射允许程序在运行时检查类、接口、字段和方法的信息,并且能够动态地创建对象和调用方法。在IOC中,反射用于在...
java反射机制和动态代理的原理,熟悉反射机制和动态代理
Java反射和动态代理是Java编程中的重要特性,它们允许程序在运行时检查和操作类、接口、对象等的内部结构,以及动态地创建代理对象来处理特定任务。在这篇文章中,我们将深入探讨这两个主题,结合"reflections"这个...