您的位置:首页 > 编程语言 > Java开发

Java中的动态代理及反射机制

2015-07-10 11:38 676 查看
面向对象的基本原则封装、继承、多态,在java中多态机制,表现为变量多态,方法多态,这都是指的是因对象所属的类不同,而调用不同的类方法;对于对象的方法,还有函数重载,java中的函数的签名是由函数名+参数方法来定的,不能仅由返回值不同来定。

反射Reflect

运行时获取类的类型,域,方法等各种属性。

Class是一个类,其实例对应其他不同的类。程序运行期间jvm为所有对象维护这运行时类型标识。

(CalculatorImpl)Class.forName("CalculatorImpl").newInstance();


newInstance()得到结果是Object型,后要做类型转换。

相关的类,主要有

java.lang.Class

java.lang.reflect.Field

java.lang.reflect.Method

java.lang.reflect.Constructor

java.lang.reflect.Modifier

java.lang.reflect.AccessibleObject

Method method = clazz.getDeclaredMethod("testMethod", int.class,int.class);
int res = (Integer) method.invoke(null, 10,10);


参照书上的ArrayCopy的例子。

public static Object goodArrayCopy(Object a, int newLength){
Class<?> clazz = a.getClass();
if(!clazz.isArray()){
return null;
}
Class<?> componentType = clazz.getComponentType();
int origLength = Array.getLength(a);
Object o = Array.newInstance(componentType, newLength);
System.arraycopy(a, 0, o, 0, Math.min(newLength, origLength));
return o;
}


注意这里的Array是java.lang.reflect.Array

Method m1 = XXXX.class.getMethod("testMethod",double.class, double.class);

函数指针的对应物,调用任意方法,通过Method来实现,Method类的invoke方法(Object invoke(Object obj, Object... args)),调用包装在当前Method对象的方法。

动态代理

代理,有静态代理,

动态代理通过java.lang.reflect包中的Proxy类和InvocationHandler接口来实现的(在 Proxy类中,

/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;



public Object invoke(Object proxy, Method method, Object[] args)


To create a proxy for some interface Foo:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
or more simply:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);


下面这个InvocationHandler摘自《大型网站系统与Java中间件实践》

class LogHandler implements InvocationHandler{

Object obj;
LogHandler(Object obj){
this.obj = obj;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
this.doBefore();
Object o = method.invoke(obj, args);
this.doAfter();
return o;
}

public void doBefore(){
System.out.println("do this before");
}

public void doAfter(){
System.out.println("do this after");
}
}


public static void testDynamicProxy(){
Calculator calculator = new CalculatorImpl();
LogHandler logHandler = new LogHandler(calculator);
Calculator proxy = (Calculator) Proxy.newProxyInstance(calculator.getClass().getClassLoader(),
calculator.getClass().getInterfaces(), logHandler);
int res = proxy.add(2, 3);
System.out.println(res);
}


自己运行时,加一个JVM参数:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true ,运行时产生的中间代理类$Proxy0.class被保存下来,而后用jd反编译查看,

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy
implements DynamicProxyTest.Calculator
{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;

public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}

public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final int add(int paramInt1, int paramInt2)
throws
{
try
{
return ((Integer)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt1), Integer.valueOf(paramInt2) })).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("DynamicProxyTest$Calculator").getMethod("add", new Class[] { Integer.TYPE, Integer.TYPE });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}


其中的h是继承自父类Proxy中的InvocationHandler实例,在本例中也即自己实现的LogHandler,通过这个Handler来进行invoke调用从而实现动态代理,也可以看到动态代理能够实现的依赖还是反射机制,需要传入method和args参数,invoke方法具体细节再单独抽出如下,这也是执行proxy.toString()方法会打印doBefore和doAfter,而要是执行proxy.getClass()并不会。

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
this.doBefore();
Object o = method.invoke(obj, args);
this.doAfter();
return o;
}


可以看到这个$Proxy0.class类实现了Calculator接口,就是这个类作为实际代理去执行add方法的,相当于我们写静态代理(代理模式)时候写的,因为在编译时候无法确定是要实现哪个接口,所以才需要使用动态代理的。

static class CalculatorProxy implements Calculator{

private Calculator cal;

CalculatorProxy(Calculator cal){
this.cal = cal;
}

@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
int result = cal.add(a, b);
return result;
}

}


cglib字节码增强

,"在运行期扩展java类及实现java接口",补充的是java动态代理机制要求必须实现了接口,而cglib针对没实现接口的那些类,原理是通过继承这些类,成为子类,覆盖一些方法,所以cglib对final的类也没效。

Byte Code Generation Library is high level API to generate and transform JAVA byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access

"Hibernate Uses cglib to generate proxies for persistent classes.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: