设计模式之浅谈代理模式

代理模式,首先笔者会介绍代理模式的概念,之后再分类介绍java中的静态和动态代理。

  • 什么叫代理模式?
    1. 举个例子,在娱乐圈中有这样一群人,明星/经纪人/客户。客户要想找明星打广告、拍戏等,则需要通过经纪人进行磋商,这种场景下明星称为被代理对象,经纪人就是代理对象。即,经纪人对外界提供一种对明星的访问,以减少明星的负担。

    2. 画张图,可以直接看出被代理对象和代理对象的关系。代理对象经纪人可以对明星,进行功能增强,提高明星工作效率。

      在这里插入图片描述

    3. 或者,这张网上找的,画的很可以:

      在这里插入图片描述

  • 使用代理模式的优缺点:

    缺点分析:

    1. 复杂度变高与处理速度变慢
      • 其实,实现代理对象(经纪人)需要进行代码的编写,这时候会增加系统实现的复杂度。
      • 由于客户与被代理对象之间,增加一个中介,因此会造成请求速度变慢问题,即请求都会先通过中介。

    优点分析:

    1. 安全性提高:
      • 讲道理明星也有生活,若没有经纪人的话,每天都会被脑残粉骚扰,对于明星而言安全性提高。
      • 那么,在这种场景下,代理对象作为客户端与被代理对象之间的中介,起到保护被代理对象的作用。
    2. 耦合性降低
      • 讲道理,明星也需要进行个人提升的。
      • 那么,使用代理对象(经纪人)协调客户与被代理对象(明星),被代理对象只需要实现本身关心的业务,非本职业务通过代理对象区处理并隔离,降低与客户耦合度。
  • 关于静态代理和动态代理
    1. 静态代理和动态代理的区别

      • 静态代理类,在运行前就已经存在,即为静态代理。

      • 就一点,看是否手写代理对象。静态代理需要程序员手写代理对象,而动态代理不必。

    2. 动态代理实现方式:

      • JDK动态代理:利用反射技术实现
      • cglib动态代理:利用字节码实现
    3. 在面试中,会遇到手撕代理模式,静态代理的实现方式是你的首选。

      • 编写共同接口代码:

        // 接口
        interface Common {
        	// 接电影
        	void getMovie();
        }
        
      • 编写经纪人(代理对象)代码:

        // 经纪人
        class Agent implements Common {
        	// 经纪人需要明星对象的引用
        	private Start mm;
        	public Agent(Start mm) {
        		this.mm = mm;
        	}
        	@Override
        	public void getMovie() {
        		System.out.println("我是经纪人,代表明星接单!");
        	}
        	public Start getStart() {
        		return mm;
        	}
        }
        
      • 编写明星(被代理对象)代码:

        // 明星
        class Start implements Common {
        	@Override
        	public void getMovie() {
                System.out.println("我只要美美哒地拍戏就好!不需要管其他的。");
        	}
        }
        
      • 客户端调用代码

        		// 客户通过代理洽谈
        		Agent agent = new Agent(new Start());
        		agent.getMovie();
        
  • 关于动态代理分类, 笔者需要再叨叨几句。
      1. 什么叫,JDK动态代理
        • 代理类的class文件由JDK运行时,动态生成。

        • 主要需要记住的API有:Proxy.newProxyInstance及其传入的参数。

        • JDK有一个很大的弊端,代理过程必须依靠接口实现,注意观察target.getClass().getInterfaces(),说明类如果没有实现接口,则不能使用JDK动态代理。

          // 代理接口
          interface Common {
          	// 接电影
          	void getMovie();
          }
          // 代理实现类-经纪人
          class Agent implements Common{
          	public void getMovie() {
          		System.out.println("我是经纪人,代表明星接单!");
          	}
          }
          // 使用JDK动态代理,生成代理类
          public class Poxy {
          	public static void main(String[] args) {
          		try {
          			// 正常生产代理类
          			Common target = new Agent();
          			
          			// 通过动态代理,生产代理类
          			Common proxyObj = (Common) 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("进行前置处理");
          					// 调用
          					method.invoke(target, args);
          					System.out.println("进行后置处理");
          					return null;
          				}
          			});
          			proxyObj.getMovie();
          		}catch (Exception e) {
          			e.printStackTrace();
          		}
          	}
          }
          
    1. 关于CGLIB动态代理:
      • 就是为了解决JDK动态代理的弊端,如果一个目标类(被代理对象)没有实现接口,但又想使用代理模式,那么CGLIB是一个很好的选择。
      • 其实,对于无接口的目标类,CGLIB的原理就是生成目标类的子类,利用子类来充当代理对象。意思就是,当一个明星忽然爆红,一时间找不到经纪人(没实现接口),那么明星的儿子或者女儿也可以充当其经纪人的职责。当然,明星这个类不能用final修饰,原因不言而喻。
      • 那么,什么是CGLIB(code generation library)呢?简单点说,是一个代码生成的类库,它可以在运行期间扩展和增强java类。在Spring中可以用来实现AOP编程。
      • 关键点:对于没有实现接口的目标类,生成目标类的子类作为代理对象。
      • 话不多说,直接贴上代码:
      //代理实现类-经纪人
      class Agent {
      	public void getMovie() {
      		System.out.println("我是经纪人,代表明星接单!");
      	}
      }
      public class CglibProxy implements MethodInterceptor{
      
      	private Agent agent;
      	
      	public CglibProxy(Agent agent) {
      		super();
      		this.agent = agent;
      	}
      	/**
      	 * 返回代理对象
      	 */
      	public  Agent getProxyObj() {
      		// 创建增强类
      		Enhancer en = new Enhancer();
      		// 设置父类
      		en.setSuperclass(Agent.class);
      		// 回调
      		en.setCallback(this);
      		return (Agent) en.create();
      	}
      	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
      		System.out.println("前置处理");
      		method.invoke(agent, args);
      		System.out.println("后置处理");
      		return null;
      	} 
      	/**
      	 * 调用逻辑
      	 * @param args
      	 */
      	public static void main(String[] args) {
      		CglibProxy proxy = new CglibProxy(new Agent());
      		Agent agent = proxy.getProxyObj();
      		agent.getMovie();
      	}
      }
      

    参考链接:

    https://juejin.im/post/5a546ad051882573443c8eec

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值