关于动态代理,先引用JDK上的一段话
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 |
看了上面的一段话,想必你已经明白什么叫动态代理了吧。没明白?没关系,老实说,我也不明白,上面的一段话看了一半就看不下去了,实在没这个耐心看。不过还好,旁边就有个例子 来说明:
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 });
可以看到,通过一系列方法,最终创建出了一个Foo的实例。
那么MyInvocationHandler是什么呢?正如jdk上所说,它实现了InvocationHandler
接口,拥有一个invoke(Object proxy, Method method, Object[]args)方法。也就是说,它是通过反射的方式,调用了Foo接口的实例的具体实现方法。具体的调用,肯定发生在invoke里面了。
看到这里我们明白了吧,其实动态代理就是为其他对对象提供一种动态的可以在运行中改变的代理以控制对这个对象的访问。也就是说,在运行过程中,Foo的实例,甚至Foo的这个接口,都可以作出改变,这也就是为什么叫动态代理了。真的和具体应用无关,很抽象的东东。
好了,现在我们都知道什么是动态代理了,但是它有什么作用呢?
通过查看JDK我们知道,Proxy这个类从JDK1.3开始就有了,为什么设计这个类,我还是没想明白,网上也没找到,不过也是,如果那帮人的思维我们可以理解,那么我们也可以去设计jdk了。
那么我们可以自己想下,我们可以要在什么情况下使用动态代理。很明显,在本地代码里面,我们不会很费力的把每个接口的实现和引用都改成动态代理的方式的,因为那样既难看,又难以理解,而且还不易于维护,但是如果我们在设计一个框架,一个可以在运行期间动态改变其表现的框架呢?
还有,如果我们有远程的调用(RMI),那么我们就还要集成remoteobj的类,并且实现自己的接口,像这样似的:
public class RemoteTest extends RemoteObject implements Foo
{
Foo f;
public RemoteTest(Foo f)
{
this.f = f;
}
void fooMethod1()
{
}
}
日志模块:比如需要在方法的开始和结束打印参数和执行时间,又不愿意修改应用代码,怎么半?
安全性检查:比如论坛注册用户访问和非注册用户的访问之类的。
事务管理:比如需要访问数据库,在每个方法调用之前打开连接,调用之后关闭连接,这样就可以大大简化我们的代码,多优雅的设计,不是么?
仔细看着上面的一系列应用,一个词渐渐的浮现在脑海,AOP(面向切面编程),这些不就是AOP要解决的问题么?
的确如此,Struts、Spring等框架的实现原理就是来源与动态代理,通过动态代理,我们来实现拦截器的功能,然后我们将多个拦截器连成一串,那就是过滤器链模式(ChannelPipeline)。好了不多扯了,再撤就多了 ,还有控制反转、依赖倒置、依赖注入等。
由于从动态代理中引申的东西比较多,一时半会儿也说不完,仅仅粘贴基本的动态代理调用,至于简单的AOP实现,代理模式实现等,我们就不管了。有时间再写写吧。
1、bird.java
package com.test.proxy;
public interface Bird
{
void fly(String arg);
void display();
}
2、Angel.java
package com.test.proxy;
/**
* 鸟人类
* @author Ransom
*
*/
public class Angel implements Bird
{
private String name;
public Angel(String name)
{
this.name = name;
}
@Override
public void fly(String arg)
{
System.out.println("Bird " + name + " called fly method,args:" + arg);
}
@Override
public void display()
{
System.out.println("Bird " + name + " called display method");
}
}
3、BirdInvocationHandler.java
package com.test.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 虽然起名为bird,但是确实是一个动态代理类,所以可以创建任何接口的实例
* @author Ransom
*
*/
public class BirdInvocationHandler implements InvocationHandler
{
private Object target;
public BirdInvocationHandler(Object target)
{
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
/*
* 可以在方法调用的前后加入时间或者日志的打印
* 也算是实现了一个基本的AOP了吧。
*/
System.out.println("excute medhod:" + method.getName());
Object obj = method.invoke(target, args);
return obj;
}
public void setTarget(Object target)
{
this.target = target;
}
}
4、Testmain.java
package com.test.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
public class TestMain
{
public static void main(String[] args) throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchMethodException, SecurityException
{
/*
* 创建代理方法1
*/
InvocationHandler handler = new BirdInvocationHandler(new Angel(
"birdman"));
// Class> proxyClass =
// Proxy.getProxyClass(Bird.class.getClassLoader(),
// Bird.class);
// Bird b = (Bird) proxyClass.getConstructor(new Class[]
// { InvocationHandler.class }).newInstance(new Object[]
// { handler });
// b.fly();
// b.display();
/**
* 创建代理方法2
*/
Bird b2 = (Bird) Proxy.newProxyInstance(
BirdInvocationHandler.class.getClassLoader(), new Class[]
{ Bird.class }, handler);
b2.fly("abc");
b2.display();
}
}