代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用。

代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务。而客户也不会为了喝红酒到处去找厂商,他只要找到厂商当地的代理就行了,具体红酒厂商在哪里,客户不用关系,代理会帮忙处理好。

代理模式涉及到的角色:

1:抽象主题角色,声明了代理主题和真实主题的公共接口,使用任何需要真实主题的地方都可以使用代理主题。

2:代理主题角色,含有真实主题的引用,从而可以在任何时候操作真实主题,代理主题提供和真实主题相同的接口,使他可以随时替代真实主题,代理主题持有真实主题的引用,不但可以控制真实主题的创建、删除,还可以在真实主题被调用之前就行拦截,或调用之后进行某些处理操作。

3:真实代理对象,定义了代理角色所代表的具体对象。

下面是代理模式的实现类图

根据上图的关系,我们可以根据客户买红酒模拟代理模式的实现。

/**
 * 
 *抽象主题角色,定义真实角色和代理角色的公共接口
 *
 */
public interface SellInterface {

    public Object sell();
}

接着我们定义真实主题角色(这里就是红酒工厂),它必须实现SellInterface接口。

/**
 * 
 * 真实主题角色,这里指红酒工厂角色,它实现了抽象主题角色SellInterface接口
 *
 */
public class RedWineFactory implements SellInterface {

    public Object sell() {
        return null;
    }

}

下面是代理主题角色(这里指红酒代理商),同样它必须实现SellInterface接口。

/**
 * 
 * 代理主题角色,这里指红酒代理商,它必须实现SellInterface接口,还持有红酒厂商
 * RedWineFactory对象的引用,从而使它能在调用真实主题前后做一些必要的处理。
 *
 */
public class RedWineProxy implements SellInterface {

    //持有一个RedWineFactory的引用
    private RedWineFactory redWineFactory; 
    
    //销售总量
    private  static int sell_count=0;
    
    public Object sell() {
        if (checkUser()) {//在通过代理主题角色,我们可在真实主题角色被调用之前做一些诸如权限判断的事情
            
            Object obj=redWineFactory.sell();
            
            sell_count++;//同样在调用之后可以执行一些额外的操作。
            
            return obj;
        }else {
            throw new RuntimeException();
        }
        
    }

    protected boolean checkUser() {
        //do something
        
        return true;
    }
}

接下来我们看看调用代理对象的代码

public static void main(String[] args) {
        SellInterface sell=new RedWineProxy();
        
        sell.sell();
    }

从上面例子可以看出代理模式的工作方式,因为代理主题和真实主题都实现了共同的接口,这可以使不改变原来接口的情况下,只要用真实主题对象的地方,都可以用代理主题来替代,其次代理主题在客户和真实主题之间起一个中间介作用,利用这个中介平台,我们可以在客户把请求传给真实主题前,做一些必要的预处理。

Java对代理模式的支持,动态代理

上面的代理,我们强迫代理类实现抽象接口,这导致我们的代理无法通用雨其它接口,而Java通过Proxy类和InvocationHandler接口可以解决这问题。

/**
 * 代理一定要实现InvocationHandler接口
 *
 */
public class ProxyObject implements InvocationHandler {
    
    private Object  proxy_obj;
    
    public ProxyObject(Object obj) {
        
        this.proxy_obj=obj;
    }

    public static Object factory(Object obj){
        Class cls =obj.getClass();
        
        //通过Proxy类的newProxyInstance方法返回代理对象。
        return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new ProxyObject(obj));
    }
    
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("函数调用之前被拦截了:"+method);
        
        if (args!=null) {
            //打印参数列表
            System.out.println("方法有:"+args.length+"个参数。。。。。");
            
            for (int i = 0; i < args.length; i++) {
                System.out.println(args[i]);
            }
        }
        //利用反射机制动态调用原对象的方法。
        Object mo=method.invoke(proxy_obj, args);
        
        System.out.println("函数调用之后进行处理:"+method);
        
        return mo;
    }

    //测试代码
    public static void main(String[] args) {
        SellInterface sell=(SellInterface) factory(new RedWineFactory());
        sell.sell();
    }
    
}

通过上面的代码可以看出,代理主题ProxyObjce类并没有实现我们定义的SellInterface接口,而是实现了Java的InvocationHandler接口,这样就把代理主题角色和我们的业务代码分离来,使代理对象能通用于其他接口,其实InvocationHandler接口就是一种拦截机制,当系统中有了代理对象以后,对原对象方法的调用,都会由InvocationHandler接口来处理,并把方法信息以参数的形式传递给invoke方法,这样,我们就可以在invoke方法中拦截原对象的调用,并用过反射机制来动态调用原对象的方法,这好像也是spring aop编程的基础吧。

Java动态代理,cglib动态代理的应用

JDK的动态代理用起来非常简单,但是它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类可以使用CGLIB包。

CGLIB是一个强大的高性能的代码生成包。它被许多AOP的框架(例如Spring AOP)使用,为他们提供方法的interception(拦截)。Hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联。EasyMock通过使用模仿(moke)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理

/**
 * 
 * 这是没有实现接口的实现类。
 *
 */
public class RedWineFactoryCglib {

    public Object sell(String str) {
        return null;
    }
}
/**
 * 使用cglib动态代理 
 */
public class ProxyObjectCglib implements MethodInterceptor {
    
    private Object target;

    /**
     * 创建代理对象
     * @return
     */
    public Object getInstance(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("函数调用之前被拦截了:"+method);
        
        if (args!=null) {
            //打印参数列表
            System.out.println("方法有:"+args.length+"个参数。。。。。");
            
            for (int i = 0; i < args.length; i++) {
                System.out.println(args[i]);
            }
        }
        
        proxy.invokeSuper(obj, args);
        
        System.out.println("函数调用之后进行处理:"+method);
        
        return null;
    }
    
    public static void main(String[] args) {
        ProxyObjectCglib cglib =new ProxyObjectCglib();
        RedWineFactoryCglib sell=(RedWineFactoryCglib) cglib.getInstance(new RedWineFactoryCglib());
        sell.sell("123");
    }
}

 

posted on 2015-05-11 13:45  一天做一件小事  阅读(178)  评论(0编辑  收藏  举报