设计模式------代理模式

(一)静态代理

(二)动态代理

代码 
抽象主题角色

//抽象角色:声明真实对象和代理对象的共同接口;
public interface  TicketManager { 
    /**
     * 售票
     */
    public  void  soldTicket();
    /**
     * 改签
     */
    public void changeTicket();
    /**
     * 退票
     */
    public void returnTicket();
}   

真实主题角色

public class TicketManagerImpl implements TicketManager {

    @Override
    public void soldTicket() {
        //checkIdentity();
        System.out.println("售票");
    }

    @Override
    public void changeTicket(){
        //checkIdentity();
        System.out.println("改签");
    }

    @Override
    public void returnTicket() {
        //checkIdentity();
        System.out.println("退票");
    }

    /**
     * 身份验证
     */
    public void checkIdentity(){
        System.out.println("身份验证");
    }
}

代理主题角色(添加了身份验证功能)

public class StaticProxyTicketManager implements TicketManager {
    TicketManager ticketManager;//目标对象的引用

    public StaticProxyTicketManager(TicketManager ticketManager) {
        this.ticketManager = ticketManager;
    }

    @Override
    public void soldTicket() {
        checkIdentity();
        ticketManager.soldTicket();
    }

    @Override
    public void changeTicket() {
        checkIdentity();
        ticketManager.changeTicket();
    }

    @Override
    public void returnTicket() {
        checkIdentity();
        ticketManager.changeTicket();
    }
    /**
     * 身份验证
     */
    public void checkIdentity(){
        System.out.println("身份验证--------------");
    }

}

第二个代理主题角色(添加了日志功能)

//代理类  实现同一个接口
public class LogProxy implements TicketManager {
    TicketManager ticketManager;//目标类的引用
    public LogProxy(TicketManager ticketManager){
        this.ticketManager=ticketManager;
    }
    @Override
    public void soldTicket() {
        ticketManager.soldTicket();
        log();//后置增强
    }

    @Override
    public void changeTicket() {
        ticketManager.changeTicket();
        log();
    }

    @Override
    public void returnTicket() {
        ticketManager.returnTicket();
        log();

    }
    //增强
    private void log() {
        System.out.println("日志...");

    }

}

客户端

public class Test {
    public static void main(String[] args) {

        //装饰模式   new TicketManagerImpl()  真实的目标对象
        //TicketManager tm=new StaticProxyTicketManager(new TicketManagerImpl());
        TicketManager tm=new LogProxy(new StaticProxyTicketManager(new TicketManagerImpl()));

        tm.soldTicket();
        tm.changeTicket();
        tm.returnTicket();
    }
}

结果: 
身份验证————– 
售票 
日志… 
身份验证————– 
改签 
日志… 
身份验证————– 
改签 
日志… 

我们可以看出,和装饰器非常相像,查阅资料勉强理解!!!其实不确定对不对

装饰器模式应当为所装饰的对象提供增强功能,而代理模式对所代理对象的使用施加控制,并不提供对象本身的增强功能。

意思就是,仅就目的来说,代理模式对所代理对象的使用施加控制(即加上一些日志,或者事务,这样子~)


动态代理

(一)jdk动态代理

(二)Cglib动态代理

描述(这个描述从网上看到的,相对比较容易理解) 
动态代理(Dynamic Proxy):相比静态代理,动态代理具有更强的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。 
所谓代理,就是需要代理类和被代理类有相同的对外接口或者说成服务,所以代理类一般都必须实现了所有被代理类已实现的接口,因为接口就是制定了一系列对外服务的标准。 
1.JDK实现动态代理

正因为动态代理有这样灵活的特性,所以我们在设计动态代理类(DynamicProxy)时不用显式地让它实现与真实主题类(RealSubject)相同的接口(interface),而是把这种实现推迟到运行时。 
为了能让DynamicProxy类能够在运行时才去实现RealSubject类已实现的一系列接口并执行接口中相关的方法操作,需要让 DynamicProxy类实现JDK自带的java.lang.reflect.InvocationHandler接口,该接口中的invoke() 方法能够让DynamicProxy实例在运行时调用被代理类的“对外服务”,即调用被代理类需要对外实现的所有接口中的方法,也就是完成对真实方法的调 用,Java帮助文档中称这些真实方法为处理程序。 
按照上面所述,我们肯定必须先把被代理类RealSubject已实现的所有interface都加载到JVM中,不然JVM怎么能够找到这些方法呢?明白了这个道理,那么我们就可以创建一个被代理类的实例,获得该实例的类加载器ClassLoader。 
所谓的类加载器ClassLoader,就是具有某个类的类定义,即类的内部相关结构(包括继承树、方法区等等)。 
更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到控制被代理对 象的行为的目的。请详看下面代码中的DynamicProxy类,其中必须实现的invoke()方法在调用被代理类的真实方法的前后都可进行一定的特殊 操作。这是动态代理最明显的优点

类图

这里写图片描述

代码

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

public class DynamicProxyTicketManager implements InvocationHandler {
    private Object targetObject;

    /**
     * 目标的初始化方法,根据目标生成代理类
     * 
     * @param targetObject
     * @return
     */
    public Object newProxyInstance(Object targetObject) {
        this.targetObject = targetObject;
        // 第一个参数,目标对象 的装载器
        // 第二个参数,目标接口已实现的所有接口,而这些是动态代理类要实现的接口列表
        // 第三个参数, 调用实现了InvocationHandler的对象生成动态代理实例,当你一调用代理,代理就会调用InvocationHandler的invoke方法
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(),
                this);
    }

    /**
     * 反射,这样你可以在不知道具体的类的情况下,根据配置的参数去调用一个类的方法。在灵活编程的时候非常有用。
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 检查
        checkIdentity();
        Object ret = null;
        try {
            // 调用目标方法
            ret = method.invoke(targetObject, args);
            // 执行成功,打印成功信息
            log();
        } catch (Exception e) {
            e.printStackTrace();
            // 失败时,打印失败信息
            System.out.println("error-->>" + method.getName());
            throw e;
        }
        return ret;
    }

    /**
     * 身份验证
     */
    public void checkIdentity(){
        System.out.println("身份验证--------------");
    }
    public void log(){
        System.out.println("日志..." );
    }

}

客户端

public class Test {
    public static void main(String[] args) {
        DynamicProxyTicketManager dynamicProxyTicketManager=new DynamicProxyTicketManager();
        TicketManager tm=(TicketManager) dynamicProxyTicketManager.newProxyInstance(new TicketManagerImpl());

        tm.soldTicket();
        tm.changeTicket();
        tm.returnTicket();
    }
}

结果同上 
优缺点 
优点: 
1、一个动态代理类更加简单了,可以解决创建多个静态代理的麻烦,避免不断的重复多余的代码 
2、调用目标代码时,会在方法“运行时”动态的加入,决定你是什么类型,才调谁,灵活 
缺点: 
1、系统灵活了,但是相比而言,效率降低了,比静态代理慢一点 
2、动态代理比静态代理在代码的可读性上差了一点,不太容易理解 
3、JDK动态代理只能对实现了接口的类进行代理 
总结 
各有各的好,具体情况具体讨论

2.Cglib实现动态代理

描述(网上整理) 
AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。 
两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的 ,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通 过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有 上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛, 且在效率上更有优势。 
JDK的动态代理机制只能代理实现了接口的类,否则不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

介绍: 
CGLIB的核心类: 
net.sf.cglib.proxy.Enhancer – 主要的增强类 
net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现 
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用: 
Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。 
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法 
public Object intercept(Object object, java.lang.reflect.Method method, 
Object[] args, MethodProxy proxy) throws Throwable; 
第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。原来的方法可能通过使用java.lang.reflect.Method 对象的一般反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy通常被首选使 用,因为它更快

代码

public class CglibDynamicProxyTicketManager implements MethodInterceptor  {
    private Object targetObject;//目标对象
    /** 
     * 创建代理对象 
     *  
     * @param targetObject 
     * @return 
     */  
    public Object getInstance(Object targetObject) {  
        this.targetObject = targetObject;  
        Enhancer enhancer = new Enhancer();  // 用这个类来创建代理对象(被代理类的子类): 并设置父类;设置回调;
        enhancer.setSuperclass(this.targetObject.getClass()); // 设置被代理类作为其父类的代理目标
        // 回调方法  
        enhancer.setCallback(this);  // 设置回调--当这个代理对象的方法被调用时 回调方法intercept()会被执行
        // 创建代理对象  
        return enhancer.create();  
    }  

    @Override
    //回调方法
    // methodProxy 代理的类的方法
    /**
     * methodProxy 会调用父类(目标对象)的被代理的方法,比如soldTicket方法等
     */
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy methodProxy) throws Throwable {
        Object result = null;
        checkIdentity();//前置增强
        result=methodProxy.invokeSuper(obj, args); //调用新生成的cglib的代理对象 所属的父类的被代理的方法
         log();//后置增强
        return result;
    }

    /**
     * 身份验证
     */
    public void checkIdentity(){
        System.out.println("身份验证--------------");
    }
    public void log(){
        System.out.println("日志..." );
    }


}

客户端

public class Test {
    public static void main(String[] args) {
        CglibDynamicProxyTicketManager cglibdynamicProxyTicketManager=new CglibDynamicProxyTicketManager();
        //生成代理对象
        TicketManager tm=(TicketManager) cglibdynamicProxyTicketManager.getInstance(new TicketManagerImpl());

        tm.soldTicket();//当调用代理对象的被代理对象的方法时  会自动回调 代理类中的Intercept()方法
        tm.changeTicket();
        tm.returnTicket();
    }
}


拓展请点这里

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值