【设计模式】与其说学习代理模式,不如说学习如何使用动态代理

599 阅读8分钟

这是我参与更文挑战的第25天,活动详情查看:更文挑战


👉设计模式目录

一、什么是代理模式

先来看看百度的解释

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 ——百度百科

个人感觉这个将的太抽象了,不过这里有个概念-“中介”,这个词就很能体现代理模式的精髓,一切代理模式其实都是一个中介,能够让使用者去使用不方便直接使用的对象,而不需要考虑其中复杂的过程。

二、使用代理模式的优缺点

1.优点

  • 让代码的职责更加清晰,经过代理之后,在使用方法时就不需要考虑业务逻辑之外的东西
  • 具有高扩展性,能够很好的与其他方法进行组合
  • 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用

2.缺点

  • 增加了系统复杂度,这也是不可避免的,代理模式在不影响使用的情况下,增加了额外的功能,必然会增加复杂度
  • 由于在客户端和真实对象之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢(个人觉得,实例之间的相互调用应该是一个很迅速的过程,有没有代理的效率应该是差不多的)

3.原则

“+”代表遵守,“-”代表不遵守或者不相关

原则开放封闭单一职责迪米特里氏替换依赖倒置接口隔离合成复用
-+--++-

三、代理模式的分类

我这里不是按照实现方法来进行分类的,而是按照代理模式的本质来分类的。

1.增强型代理

  1. 特点

核心功能不变(不能修改原来的功能) 业务无关性(不修改核心的业务逻辑,降低系统的复杂性) 使用习惯不变 附加新功能(只是让需要代理的功能附加不影响原来的功能的功能,相当于加个buff) 普适性(增强的功能能够加到其他方法中)

总的来说,增强型代理只是对一个方法进行一些无关业务的操作,安全校验,上锁,记录等一些无关业务的操作。

  1. 常见的例子

增强代理的实现可以有静态代理,也可以有动态代理 常见的例子有:

  • spring的aop,声明型事物
  • 监控操作(当用户操作后,做一个记录)

2.链接型代理

  1. 特点

跟增强型代理一些相似的特点 核心功能不变 业务无关性 使用更加方便

总的来说,链接型代理就是简化我们对方法的调用,也是不改变业务,一般来说,不会做一些增强型的操作。

  1. 常见的例子

链接型代理的实现同样也是可以静态,也可以动态。 常见的例子有:

  • MyBtis的mapper代理
  • springCloud中的ribbon,zuul等

四、代理模式的实现

1.静态代理

静态代理就是采用手动写代码的方式来实现,可以在不修改目标对象功能的前提下,实现功能扩展扩展多样化,但是需要编写很多方法的扩展,管理成本增大 首先需要创建一个接口,接口中定义被代理类和代理类都要实现的方法,然后创建被代理类和代理类

/**
 * @author xxj
 * 静态代理测试
 */
public class StaticProxy {
    public static void main(String[] args) {
        Company company=new Company("房地产公司","靠海别墅");
        CompanyProxy companyProxy=new CompanyProxy(company,"小张");

        companyProxy.sale();
    }

    /**
     * 接口
     * 卖东西的接口
     */
    public interface Salor{
        public void sale();
    }

    /**
     * 被代理类
     * 需要代理的公司
     */
    public static class   Company implements Salor{
        String name;
        String product;
        public Company(String name,String product){
            this.name=name;
            this.product=product;
        }
        @Override
        public void sale() {
            System.out.println(name+"卖出"+product);
        }
    }
    /**
     * 代理类
     * 中介
     */
    public static class CompanyProxy implements Salor{
        private Company company;
        private String worker;
        /**
         * @param company 需要代理的公司
         */
        public CompanyProxy(Company company,String worker){
            this.company=company;
            this.worker=worker;
        }
        @Override
        public void sale() {
            System.out.println(worker+"推销--联系客户---");
            System.out.println("联系"+company.name+"进行交易--");
            company.sale();
            System.out.println(worker+"拿提成--");
        }
    }
}

个人感觉这更像链接型代理,因为CompanyProxy的sale方法中是有做相关操作的(如果把打印到控制台理解为一个操作),而增强型代理则是打印一下状态信息或者是监控,而不会去执行company.sale()

2.动态代理

动态代理生成的代理类都是通过动态拼接字节码产生的,实际上代理类并不存在,而静态代理中代理类则是真是存在的

JDK动态代理

JDK动态代理就不需要手动地去扩展方法的功能了,而是由一个实现了InvocationHandler接口的类来统一管理,不用写每个方法的扩展,使代理类的管理成本降低,但是会是代理类的创建变得麻烦,这就可以套上一个工厂模式来创建代理类了

首先依然是要创建一个接口被代理类需要实现这个接口,然后在创建一个中介类实现InvocationHandler接口,然后调用Proxy提供的静态方法newProxyInstance来创建代理类(注意需要用接口接收)

/**
 * @author xxj
 * JDK动态代理
 */
public class DynamicProxy {
    public static void main(String[] args) {
        Company company=new Company("房产公司","傍山别墅");
        //中介公司
        CompanyHandler companyHandler=new CompanyHandler(company,"啥都能卖公司");
        //类加载器,可以强行理解为销售组长,要由他来叫人干活
        ClassLoader classLoader=company.getClass().getClassLoader();
        //叫张三来替啥都能卖公司干活
        Salor zhangsan= (Salor) Proxy.newProxyInstance(classLoader,
                company.getClass().getInterfaces(),companyHandler);
        zhangsan.sale();
    }

    /**
     * handle类
     * 相当于中介公司
     */
    public static class CompanyHandler implements InvocationHandler{
        private Company company;
        private String agentCompany;
        public CompanyHandler(Company company,String agentCompany){
            this.company=company;
            this.agentCompany=agentCompany;
        }
        /**
         * @param proxy 貌似不能使用
         * @param method 调用invoke的method信息
         * @param args method的参数信息
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println(agentCompany+"推销--联系客户---");
            System.out.println("联系"+company.name+"进行交易--");
            //执行company的方法
            method.invoke(company,args);
            System.out.println(agentCompany+"拿提成--");
            return null;
        }
    }

    /**
     * 被代理类
     * 需要代理的公司
     */
    public static class  Company implements Salor {
        String name;
        String product;
        public Company(String name,String product){
            this.name=name;
            this.product=product;
        }
        @Override
        public void sale() {
            System.out.println(name+"卖出"+product);
        }
    }
    /**
     * 接口
     * 卖东西的接口
     */
    public interface Salor{
        public void sale();
    }
}

Cglib动态代理

Cglib动态代理使用起来就比JDK动态代理方便多了,只需要写一个ProxyFactory类就可以给其他类做代理了,而且不需要再写接口了,但是它生成代理类的过程比较复杂,还需要依赖第三方jar包 首先,需要导入依赖,然后只需要写一个代理工厂类,需要实现MethodInterceptor接口,还要在内部提供构建代理类的方法,直接把被代理类放入代理工厂类就可以生成代理类

maven

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>
/**
 * @author xxj
 * Cglib动态代理
 */
public class CglibDynamicProxy {

    public static void main(String[] args) {
        Company company=new Company("房产公司","私人庄园");
        Company proxy= (Company) new ProxyFactory(company,"一定能卖出公司").getProxyInstance();
        proxy.sale();
    }
    public static class ProxyFactory implements MethodInterceptor {
        private Company company;
        private String agentCompany;
        public ProxyFactory(){}
        public ProxyFactory(Company company, String agentCompany){
            this.company=company;
            this.agentCompany=agentCompany;
        }

        //给目标对象创建一个代理对象
        public Object getProxyInstance(){
            //1.工具类
            Enhancer en = new Enhancer();
            //2.设置父类
            en.setSuperclass(company.getClass());
            //3.设置回调函数
            en.setCallback(this);
            //4.创建子类(代理对象)
            return en.create();
        }
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println(agentCompany+"推销--联系客户---");
            System.out.println("联系"+company.name+"进行交易--");
            //执行company的方法
            method.invoke(company,objects);
            System.out.println(agentCompany+"拿提成--");
            return null;
        }
    }

    /**
     * 被代理类
     * 需要代理的公司
     */
    public static class   Company  {
        String name;
        String product;
        public Company(){}
        public Company(String name,String product){
            this.name=name;
            this.product=product;
        }
        public void sale() {
            System.out.println(name+"卖出"+product);
        }
    }
}

五、总结

无论那种代理模式都需要满足不改变核心功能不改变业务逻辑这两个特点,一旦违背了,就会极大的增加系统的复杂度。

这里分别举两个生活中的例子来作为本章节的结束吧。 增强型代理,就像是微波炉(代理对象),当我们需要加热食物(被代理对象)时,就将食物放入微波炉中,然后我们就会得到一个加热了的食物(附加新功能)。这个过程没有改变食物的本质(不改变核心功能),我们依然能吃(说加热太烫吃不了的,你就杠吧)(使用习惯不变)一切食物都可以加热(普适性)你想加热别的东西也可以。 链接型代理,这个可以举的例子太多了,像宅急送,我们只需要手机下单就可以购买汉堡(使用更加方便)我们手机下单最终做的事情就是买汉堡(不改变核心功能

——————————————————————————————

这里是程序员徐小白,不知道这样的文章风格您是否喜欢,不要吝啬您免费的赞,您的点赞、收藏以及评论都是我下班后坚持更文的动力。

未经允许,不得转载!