11.0 代理模式

简介

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

类图


1.静态代理

/**  
 * 抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口
 * @author: 张彬
 * @date: 2018年6月4日 下午3:27:30
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午3:27:30
 */
public interface Subject {
    void visit();
}
/**  
 * 真实主题角色,是实现抽象主题接口的委托类。
 * @author: 张彬
 * @date: 2018年6月4日 下午3:28:47
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午3:28:47
 */
public class RealSubject implements Subject {

    @Override
    public void visit() {
        System.out.println("in RealSubject");
    }
}

/**  
 * 代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。
 * 同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
 * @author: 张彬
 * @date: 2018年6月4日 下午3:29:47
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午3:29:47
 */
public class ProxySubject implements Subject{

    private RealSubject subject;

    @Override
    public void visit() {
        System.out.println("静态代理开始");
        if(subject==null)  subject = new RealSubject();
         subject.visit();
        System.out.println("静态代理结束");
    }
}
/**  
 * 静态代理测试
 * 代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
 * @author: 张彬
 * @date: 2018年6月4日 下午3:30:53
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午3:30:53
 */
public class Client {
    public static void main(String[] args) {
        ProxySubject subject = new ProxySubject();
        subject.visit();
    }
}

输出结果:

静态代理开始
in RealSubject
静态代理结束

2.动态代理-JDK

/**  
 * 动态代理类,实现InvocationHandler接口,并重写该invoke方法
 * @author: 张彬
 * @date: 2018年6月4日 下午3:34:55
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午3:34:55
 */
public class DynamicProxy implements InvocationHandler {
    private Object object;
    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理开始");
        Object result = method.invoke(object, args);
        System.out.println("动态代理结束");
        return result;
    }
}
/**  
 * 动态代理测试
 * Subject接口与RealSubject实现类不再重敲与 1.静态代理 相同
 * 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象,代理接口InvocationHandler所在包:java.lang.reflect.Proxy
 * @author: 张彬
 * @date: 2018年6月4日 下午3:36:35
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午3:36:35
 */
public class ClientJDK {
    public static void main(String[] args) {
        // 创建一个实例对象,这个对象是被代理的真实对象
        Subject realSubject = new RealSubject();
        // ,创建一个与代理对象相关联的InvocationHandler动态代理对象
        InvocationHandler proxy = new DynamicProxy(realSubject);
        ClassLoader classLoader = realSubject.getClass().getClassLoader();
        
        // 创建一个代理对象subject来代理realSubject,代理对象的每个执行方法都会替换执行proxy中的invoke方法
        //classLoader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
        //Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
        //proxy:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
        Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new  Class[]{Subject.class}, proxy);
        
        //代理执行真实对象的方法
        subject.visit();
    }
}

输出结果:

动态代理开始
in RealSubject
动态代理结束

3.动态代理-cglib

/**  
 * 使用cglib动态代理  
 * 有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
 * 需要引入cglib的jar文件,Spring的核心包中已经包括了Cglib功能:Spring-core-3.2.5.jar
 * @author: 张彬
 * @date: 2018年6月4日 下午4:23:58
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午4:23:58
 */
public class CGLibProxy implements MethodInterceptor {    
    
    private Object targetObject;// CGLib需要代理的目标对象    
    /**
     * 创建代理对象
     * @param obj
     * @return
     */
    public Object getInstance(Object obj) {    
        this.targetObject = obj;    
        Enhancer enhancer = new Enhancer();    
        enhancer.setSuperclass(this.targetObject.getClass());    
        enhancer.setCallback(this);    
        return enhancer.create();// 返回代理对象    
    }    
    
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {    
        System.out.println("cglib开始...");
        Object result = method.invoke(targetObject, args);    
        System.out.println("cglib结束...");
        return result;
    }    
    
}
/**  
 * cglib测试
 * @author: 张彬
 * @date: 2018年6月4日 下午4:35:08
 * @version: V1.0
 * @review: 张彬/2018年6月4日 下午4:35:08
 */
public class ClientCglib {
    public static void main(String[] args) {    
        CGLibProxy cglib=new CGLibProxy();    
        RealSubject bookCglib=(RealSubject)cglib.getInstance(new RealSubject());    
        bookCglib.visit(); 
    }   
}

输出结果:

cglib开始...
in RealSubject
cglib结束...

总结

优点:1、职责清晰。2、高扩展性。3、智能化。

缺点:1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

静态代理:

优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.

缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

动态代理:

JDK:代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理;对于没有实现接口的类,不便使用该方方式实现动态代理

cglib:代理的类不能为final,否则报错,目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.



















dong

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值