代理模式

Posted woniu4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理模式相关的知识,希望对你有一定的参考价值。

代理模式,为其他对象提供一种代理以控制对这个对象的访问。【大话设计模式】

一张图,说明代理模式的结构。代理在客户端和目标对象起到的是中介的作用,一种桥梁,也如大话设计模式中所言,为他人做嫁衣。

代理模式按照创建时期可以分为两类:静态代理、动态代理。

静态代理

首先介绍一下静态代理,静态代理的结构完全契合于上图,需要首先定义个接口,业务实现接口,然后定义代理类,且需要实现所有的相同的接口。

首先,定义一个业务接口:

public interface Account
{
    public void save();
}

然后,定义代理类,实现业务接口

public class AccountImpl implements Account
{
    
    @Override
    public void save()
    {
        System.out.println("保存中。。。。。");
    }
    
}

接下来,实现代理类

public class AccountProxy implements Account
{
    private AccountImpl accountImpl;
    
    public AccountProxy(AccountImpl accountImpl)
    {
        this.accountImpl = accountImpl;
    }
    
    @Override
    public void save()
    {
        System.out.println("开始保存啦。。。。。");
        accountImpl.save();
        System.out.println("保存结束啦。。。。。");
    }
    
}

客户端类:

public class TestAccount
{
    public static void main(String[] args)
    {
        AccountImpl accountImpl = new AccountImpl();
        AccountProxy proxy = new AccountProxy(accountImpl);
        proxy.save();
    }
}

 结果如下:

开始保存啦。。。。。
保存中。。。。。
保存结束啦。。。。。

这样静态的代理模式就可以完成了。但是,有个问题,就是代理类要实现所有的业务接口,这样就会造成很多代码重复,为了解决这些,需要用接下来的动态代理模式来实现。

动态代理模式

我们接着用上边的例子,通过动态代理模式实现代理。

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

public class DynamicProxy implements InvocationHandler
{
    private Object target;
    
    public Object newInstance(Object target)
    {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        Object result = null;
        System.out.println("begin");
        result = method.invoke(target, args);
        System.out.println("end");
        return result;
    }
}

客户端调用如下:

import com.huawei.model.proxy.Account;
import com.huawei.model.proxy.AccountImpl;

public class TestProxy {    
    
    public static void main(String[] args) {    
        DynamicProxy proxy = new DynamicProxy();    
        //在这里进行真正的对象传入  
        Account account= (Account )proxy.newInstance(new AccountImpl());    
        account.save();  
    } 
}

通过对比,我们可以发现,通过动态代理,我们省略了关于代理接口的实现方法,不用讲所有需要被代理的全部方法都要实现,即可实现代理功能。

 

通过以上方法实现,我们仍然是需要接口的,如果没有接口,该怎么办?

CGLib动态代理

CGLib是一个类库,它可以在运行期间动态生成字节码,动态生成代理类。

代码如下:

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor
{

    public <T> T getProxy(Class<T> cls)
    {
        return (T)Enhancer.create(cls, this);
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy proxy) throws Throwable
    {
        System.out.println("开始保存啦。。。。。");
        Object result = proxy.invokeSuper(obj, arg2);
        System.out.println("保存结束啦。。。。。");
        return result;
    }
    
}

客户端调用代码:

import com.huawei.model.proxy.Account;
import com.huawei.model.proxy.AccountImpl;

public class TestProxy
{
    public static void main(String[] args)
    {
        CglibProxy proxy = new CglibProxy();
        Account account = proxy.getProxy(AccountImpl.class);
        account.save();
    }
}

输出结果:

开始保存啦。。。。。
保存中。。。。。
保存结束啦。。。。。

虽然该方法比上述两种方式均更加灵活,但是其也有自己的缺点,就是会拦截被代理类的所有方法。

参考链接:

https://www.zhihu.com/question/20794107

http://blog.csdn.net/wangyongxia921/article/details/46240877

以上是关于代理模式的主要内容,如果未能解决你的问题,请参考以下文章

scrapy按顺序启动多个爬虫代码片段(python3)

用于从 cloudkit 检索单列的代码模式/片段

java代码实现设计模式之代理模式

代理模式(静态代理动态代理)代码实战(详细)

Java设计模式-代理模式之动态代理(附源代码分析)

代理模式(静态代理)