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

java 代理模式详解

2014-07-13 16:11 369 查看

java 动态代理(JDK和cglib)

设计模式这东东每次看到就明白可过段时间又不能很流利的说出来,今天就用详细的比喻和实例来加深自己的理解(小弟水平不高有不对的地方希望大家能指出来)。

(1)代理这个词生活中有很多比如在街边卖手机卡、充公交地铁卡的小商店他们都起了代理的作用,java中的代理跟这些小店商的作用是一样的。再比如我想在淘宝上开个服装店但又没有货源怎么办,这时候我就要跟淘宝上某一卖家联系做他的代理。我跟我的商家都要卖衣服(就好比我们都继承了卖衣服的接口sellClothesInterface),我的商家可以卖他网店上的衣服跟我没的关系(就好比实现了sellClothesInterface接口),我的网店也可以卖代理的衣服(同都也实现了sellClothesInterface接口),这个时候买家从我的网店上买了一件衣服而衣服的发货地址确是我的商家的,买家跟我的商家没有任何关系,我就起了代理的作用。

(2)用官方的话:代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

(3)代理分为两种:静态代理动态代理

1、静态代理用代码实现如下:

public interface SellClothesInterface {
// 都能卖衣服的接口
public void sell();
}


public class BossSellClothes implements SellClothesInterface {
// 我的商家有卖衣服的方法
public void sell() {
System.out.println("确定信息并发货...");
}

}


public class MySellClothes implements SellClothesInterface {
private BossSellClothes bossSellClothes;

// 构造方法
public MySellClothes(BossSellClothes bossSellClothes) {
this.bossSellClothes = bossSellClothes;
}

public void sell() {
// 卖衣服之前先与买家做沟通确定下单
System.out.println("确认信息,确定下单...");
bossSellClothes.sell();
// 买家收货并打款
System.out.println("买家收到货交易结束...");
}

}
@org.junit.Test
public void run1() {
BossSellClothes bossSellClothes = new BossSellClothes();// 我的商家实例类
SellClothesInterface scif = new MySellClothes(bossSellClothes);// 我卖衣服类
scif.sell();// 卖衣服
}


运行结果:

确认信息,确定下单...

确定信息并发货...

买家收到货交易结束...

从上面代码可以发现每一个代理类只能为一个接口服务,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

2、动态代理



JDK动态代理中包含一个类和一个接口:

InvocationHandler接口:

public interface InvocationHandler {

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

}

参数说明:

Object proxy:指被代理的对象。

Method method:要调用的方法

Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,也就是上面静态代理类MySellClothes。

Proxy类:

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

参数说明:

ClassLoader loader:类加载器,用于找到被代理类。

Class<?>[] interfaces:得到全部的接口 ,被代理类实现的所有接口。

InvocationHandler h:得到InvocationHandler接口的子类实。

代码改动发下:

/**
* JDK动态代理
*
* @author Administrator
*
*/
public class SellClothesProxy implements InvocationHandler {
private Object target;

/**
* 传入被代理类生成代理类
*
* @param target
* @return
*/
public Object buildProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}

/**
* 调用方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("确认信息,确定下单...");
Object result = method.invoke(target, args);
System.out.println("买家收到货交易结束...");
return result;
}
}


@org.junit.Test
public void run2() {
// 创建代理类并调用方法
SellClothesProxy proxy = new SellClothesProxy();
SellClothesInterface scif = (SellClothesInterface) proxy.buildProxy(new BossSellClothes());
scif.sell();
}


运行结果:
确认信息,确定下单...

确定信息并发货...

买家收到货交易结束...

结果出来了,但有一个问题继承InvocationHandler 覆盖invoke方法,那这个方法什么时候被调用的呢?,打个断点发现scif.sell();执行时才调用invoke方法。这个invoke 方法返回一个 Object的实例,然会会强转成你需要的接口。这时候调用你这个接口的方法的时候, 实质上 就是运行了 这个invoke的方法。

(4)cglib动态代理

有了JDK的动态代理再说说cglib,为什么要用cglib呢,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,cglib就弥补了这点。cglib是对指定的目标类生成一个子类,并覆盖其中方法实现增强。但既然是类的继承就不能对final修饰的类进行代理了。

public class SellClothesProxy2 implements MethodInterceptor {
private Object target;

/**
* 传入被代理类生成代理类
*
* @param target
* @return
*/
public Object buildProxy(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("确认信息,确定下单...");
proxy.invokeSuper(obj, args);
System.out.println("买家收到货交易结束...");
return null;
}
}


@org.junit.Test
public void run3() {
SellClothesProxy2 proxy = new SellClothesProxy2();
SellClothesInterface scif = (SellClothesInterface) proxy.buildProxy(new BossSellClothes());
scif.sell();
}


运行结果:

确认信息,确定下单...

确定信息并发货...

买家收到货交易结束...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: