java动态代理实现

  • 为什么要用动态代理
  • 动态代理的实现

为什么要用动态代理

我们开发软件的过程中,通常会有各种各样的相同代码重复出现。遇到这种情况,一般会有三种做法,最不可取的是一路“复制”,“粘贴”到底,写起来挺爽,要是去维护,简直是噩梦;稍有经验的都会将这些重复的代码独立出来,在别的地方直接引用即可。但这样也有一个问题,程序中必须要硬编码去直接调用独立出来的方法,有没有一种即可以执行独立方法,又不用硬编码调用的优雅方法,这个时候就可以考虑动态代理了。

动态代理的实现

要实现动态代理,必须先要了解两个类Proxy和InvocationHandler。

Proxy是所有动态代理类的父类,包含了用于创建动态代理类和代理对象的静态方法。用的较多的的getProxyClass()和newProxyInstance()这两个方法,从名字上估计你已经看出来了,前者是用来创建一个动态代理类;后者则是创建一个动态代理对象。

不管用哪一种方法,有一点是肯定的,每一个代理对象都必须有一个InvocationHandler类与之关联。这个InvocationHandler是个很奇妙的类,有了它之后,就可以接管动态代理对象里的方法。也就是说当执行动态代理对象里的方法时,实际上执行的是InvocationHandler对象的invoke方法。

说到这里,应该明白动态代理所需要的几样东西了吧:
(1)接口。jdk动态代理只能为接口创建;
(2)有接口当然得有接口的各种实现类,记做A。(有同学可能要问,为什么需要各种实现类呢?那是因为如果直接为接口创建动态代理对象,那代理对象所有的执行方法是不是都一样?可不就失去了它的意义);
(3)通用代码块,就是前面提到的独立代码块,记做B。用各种A来调用B,是不是就模拟了前面提到的问题?;
(4)重要的InvocationHandler类。执行代理对象的所有方法都会转换为InvocationHandler的invoke方法。所以B方法通常也放在invoke里面实现。

下面我们用个简单的例子来实现一下:
首先定义一个Person接口。

public interface Person {
    void eat();
    void sleep();
}

接着实现这个接口。

public class ImplementPerson implements Person {

@Override
public void eat() {
    // TODO Auto-generated method stub
    System.out.println("=-=-=吃了吃了=-=-=");
}

@Override
public void sleep() {
    // TODO Auto-generated method stub
    System.out.println("=-=-=睡了睡了=-=-=");
}
}

定义公共代码块。

public class PersonUtils {
public void commonMethodOne() {
    System.out.println("=-=-=公共方法1");
}

public void commonMethodTwo() {
    System.out.println("=-=-=公共方法2");
}
}

定义自己的InvocationHandler,动态代理的关键实现。

public class MyInvokationHandler implements InvocationHandler {

private Object target;

public void setTarget(Object target) {
    this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
    // TODO Auto-generated method stub
    PersonUtils personUtils = new PersonUtils();
    // 执行PersonUtils的commonMethodOne方法
    personUtils.commonMethodOne();
    // 以target为主调,执行method方法;
    Object result = method.invoke(target, args);
    // 执行PersonUtils的commonMethodTwo方法
    personUtils.commonMethodTwo();
    return result;
}  
}

创建一个代理工厂,为指定的target生成动态代理实例。

public class MyProxyFactory {
public static Object getProxy(Object target) {
    MyInvokationHandler myInvokationHandler = new MyInvokationHandler();
    // 为myInvokationHandler设置target对象
    myInvokationHandler.setTarget(target);
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInvokationHandler);
}
}

最后就是个测试类了。

public class Test {
/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    // 创建一个ImplementPerson对象,作为主调target
    Person target = new ImplementPerson();
    // 创建一个动态代理对象person
    Person person = (Person) MyProxyFactory.getProxy(target);
    person.sleep();
    person.eat();
}

}

运行的效果,贴出来:

=-=-=公共方法1
=-=-=睡了睡了=-=-=
=-=-=公共方法2
=-=-=公共方法1
=-=-=吃了吃了=-=-=
=-=-=公共方法2

有了这些实现,不难看出动态代理可以很灵活地实现解耦。普通的编程中,用的比较少,但在编写框架或者底层代码时,动态代理就可大显身手了。

AOP编程中把这类动态代理叫做AOP代理,即可在执行目标方法之前,之后加入一些通用处理。至于更深层次的AOP编程,水平有限,请自行探讨。

附上代码链接,可免去粘贴之苦。
http://download.csdn.net/detail/luochoudan/9462093

欢迎留言拍砖。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值