设计模式01—代理模式Proxy

代理模式 Proxy

代理模式是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。

请添加图片描述
这有什么好处呢?

如果需要在类的主要业务逻辑前后执行一些工作, 你无需修改类就能完成这项工作。 由于代理实现的接口与原类相同, 因此你可将其传递给任何一个使用实际服务对象的客户端。

总结:在目标对象实现的基础上,增强额外的 功能操作,扩展目标对象的功能

三种:

静态代理

动态代理(JDK代理,接口代理)

Cglib代理(可以在内存中动态的创建对象,而不需要实现接口)

真实世界类比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-95RiI2Wb-1658573921930)(代理模式.assets/live-example-zh.png)]

信用卡和现金在支付过程中的用处相同。

信用卡是银行账户的代理, 银行账户则是一大捆现金的代理。 它们都实现了同样的接口, 均可用于进行支付。 消费者会非常满意, 因为不必随身携带大量现金; 商店老板同样会十分高兴, 因为交易收入能以电子化的方式进入商店的银行账户中, 无需担心存款时出现现金丢失或被抢劫的情

况。

代理模式结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eyezQOfU-1658573921930)(代理模式.assets/structure.png)]

  1. 服务接口 (Ser­vice Inter­face) 声明了服务接口。 代理必须遵循该接口才能伪装成服务对象。

  2. 服务 (Ser­vice) 类提供了一些实用的业务逻辑。

  3. 代理 (Proxy) 类包含一个指向服务对象的引用成员变量。 代理完成其任务 (例如延迟初始化、 记录日志、 访问控制和缓存等) 后会将请求传递给服务对象。

    通常情况下, 代理会对其服务对象的整个生命周期进行管理。

  4. 客户端 (Client) 能通过同一接口与服务或代理进行交互, 所以你可在一切需要服务对象的代码中使用代理。

静态代理

静态代理在使用的时候,需要定义接口或者父类,被代理对象,与代理对象一起实现相同的接口或者是继承相同的父类

服务接口

public interface ITeacherDao {

    /**
     * teach方法
     */
     void teach();
}

服务类

public class TeacherDao implements ITeacherDao {
    @Override
    public void teach() {
        System.out.println("老师正在授课~~~");
    }
}

代理类

public class TeacherDaoProxy implements ITeacherDao {

    private ITeacherDao target;

    public TeacherDaoProxy(ITeacherDao target) {
        super();
        this.target = target;
    }
    /**
     * 这里在重写接口方法的同时,还可以对方法进行增强
     */
    @Override
    public void teach() {
        System.out.println("代理开始before....");
        target.teach();
        System.out.println("代理结束after....");
    }
}

客户端

public class Client {
    public static void main(String[] args) {
//        创建目标对象
        TeacherDao teacherDao = new TeacherDao();
//        创建代理对象,同时将目标对象传递给代理对象
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
//        通过代理对象,调用被代理对象TeacherDao的方法
        teacherDaoProxy.teach();
    }
}

代码运行结果

在这里插入图片描述

动态代理

代理对象,不需要实现接口,但是目标对象要实现接口,否则不能使用动态代理

代理对象的生成,是利用JDK的API,动态地在内存中构建代理对象

动态代理也叫做:JDK代理,接口代理

java.lang.reflect.Proxy;

服务接口

public interface ITeacherDao {

    /**
     * teach方法
     */
     void teach();

    /**
     *
     * @param name
     */
     void sayHello(String name);
}

代理类

public class TeacherDao implements ITeacherDao {
    @Override
    public void teach() {
        System.out.println("老师正在授课~~~");
    }

    @Override
    public void sayHello(String name) {
        System.out.println("你好啊~"+name);
    }

}

代理工厂

public class ProxyFactory {

    /**
     * 维护一个目标对象
     */
    private Object target;

    /**
     * 构造器,对target进行初始化
     * @param target
     */
    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     *
     * @return
     */
   public Object getProxyInstance(){
       /**
        *     public static Object newProxyInstance(ClassLoader loader,
        *                                           Class<?>[] interfaces,
        *                                           InvocationHandler h)
        *      ClassLoader loader,指定当前对象的类加载器
        *      Class<?>[] interfaces, 目标对象的实现类接口,使用泛型来确认类型
        *      InvocationHandler h,处理事件,执行目标对象的方法时,会触发事件处理器的方法,在这里写:如何去增强原来的方法,如何调用
        */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("利用JDK动态代理来对原来的方法进行增强~~~");
//                        利用反射机制来调用目标对象的方法
                        Object invoke = method.invoke(target, args);
                        System.out.println("增强完毕~动态代理结束~~~~");
//                        返回调用的结果
                        return invoke;
                    }
                });
    }
}

代理类——由代理工厂动态生成

动态生成————class com.sun.proxy.$Proxy0

public class Client {
    public static void main(String[] args) {
//        创建目标对象(被代理的对象)
        ITeacherDao target = new TeacherDao();
//        给目标对象创建代理对象,强转为ITeacherDao
        ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
        System.out.println("proxyInstance--------->" + proxyInstance.getClass());
//        proxyInstance--------->class com.sun.proxy.$Proxy0

    }
}

客户端

public class Client {
    public static void main(String[] args) {
//        创建目标对象(被代理的对象)
        ITeacherDao target = new TeacherDao();
//        给目标对象创建代理对象,强转为ITeacherDao
        ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
//        通过代理对象,调用被代理对象TeacherDao的方法
        proxyInstance.teach();
        proxyInstance.sayHello("ZQH");

    }
}

代码结果:

Cglib代理

  • 静态代理和JDK代理模式都要求目标对象实现一个接口,有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可以使用目标对象子类来实现代理——这就是Cglib代理

  • Cglib页叫做子类代理,归属于动态代理

  • Cglib是一个强大的高性能代码生成包,可以再运行时期动态扩展Java类和实现Java接口,广泛用于AOP框架,实现方法拦截

  • 如何选择代理模式:

    • 目标对象需要实现接口,使用JDK代理
    • 目标对象不需要实现接口,使用Cglib代理
  • Cglib包的底层是通过使用字节码处理器ASM来转换字节码,并生成新的类

服务类

public class TeacherDao {
    public void teach() {
        System.out.println("老师正在授课.....我是Cglib代理,不需要实现接口");
    }
}

代理工厂

public class ProxyFactory implements MethodInterceptor {   //实现 MethodInterceptor接口

    /**
     * 目标对象
     */
    private Object target;

    /**
     * 构造器,传入目标对象
     * @param target
     */
    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxyInstance(){
//        创建一个工具类型
        Enhancer enhancer = new Enhancer();
//        设置父类
        enhancer.setSuperclass(target.getClass());
//        设置回调函数
        enhancer.setCallback(this);
//        创建子类对象,即代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理模式开始......");
        Object invoke = method.invoke(target, objects);
        System.out.println("Cglib代理模式提交......");
        return invoke;
    }
}

客户端

public class Client {
    public static void main(String[] args) {
//        创建目标对象(被代理的对象)
        TeacherDao target = new TeacherDao();
//        给目标对象创建代理对象,把目标对象传递给代理对象
        TeacherDao  proxyInstance = (TeacherDao) new ProxyFactory(target).getProxyInstance();
//        通过代理对象,调用被代理对象TeacherDao的方法
        proxyInstance.teach();
    }
}

运行结果:

Spring的动态代理

参考:https://blog.csdn.net/shijinjins/article/details/124423859

Spring如何选择是用JDK还是cglib?

1、当bean实现接口时,会用JDK代理模式

2、当bean没有实现接口,用cglib实现

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值