本文共 1417 字,大约阅读时间需要 4 分钟。
动态代理是java语言中非常经典的一种设计模式,也是所有设计模式中最难理解的一种
我们看一个例子:
现在我们需要增加一个功能:记录模拟小鸟飞了多久,那么有什么方法可以解决呢?
- 方法一: 我们在类bird的fly的开始和结束部分加上计时功能: 通过在类中增加开始和结束标志,我们就可以得出飞行得时间。但是这种方法存在一个问题:如果该类是在jar包或者其他环境,我们不能修改他得源码(事实也是尽量避免去修改源代码),那么这种方法就不可取了
- 方法二:在调用该fly的方法的类中增加开始和结束标志 但是这种方法也存在一个问题:在执行一个方法,需要开辟内存,压栈,出栈等操作,这些时间是不能忽略的,也就是说,得出的时间并不是飞行时间,而是飞行时间加上执行方法的时间
- 方法三:使用继承
- 方法四:聚合
- 让我们先来了解一下聚合的概念:**整体与部分的关系,并且部分是可以离开整体而单独存在的,父类包含子类,子类可以独立于父类存在。**与之有关的则是组合:组合是整体与部分的关系,并且部分不可以离开整体而单独存在,父类拥有子类,子类不能独立于父类存在
静态代理
静态代理通常用于对原有业务逻辑的扩充,比如持有二方的某个类,并调用了其中的某些方法。然后出于某种原因,比如记录日志,打印方法执行时间,但是又不好将这些逻辑写入二方包的方法里。所以可以创建一个代理类实现和二方方法相同的方法,通过让代理类持有真实对象,然后在源代码中调用代理类方法
动态代理
- 特点:字节码随用随创建
- 作用:不修改源码的基础上对方法增强
- 分类:基于接口的动态代理和基于子类的动态代理
基于接口的动态代理:
- 涉及的类:Proxy
- 提供者:JDK官方
- 如何创建代理对象:使用Proxy类中的newProxyInstance方法
- newProxyInstance方法的参数:
- ClassLoader:类加载器,它是用于加载被代理对象字节码的,和被代理对象使用相同的类加载器,是固定写法
- Class[]:字节码数组,用于让代理对象和被代理对象具有相同的方法,也是固定写法
- InvocatianHandler:用于增强的代码,它是让我们写如何代理,我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的,此接口的实现类都是谁用谁写
newinvocationHandler具有一个匿名方法invoke(),该方法具有三个参数:
- proxy:代理对象的引用
- method:当前执行的方法
- args:当前执行方法所需的参数 基于子类的动态代理:
- 涉及的类:Enhancer
- 提供者:第三方cglib库(所以需要导入相应的jar包)
- 如何创建代理对象:使用Enhancer类中的create方法
- 创建代理对象的要求:被代理对象不能是最终类(final)
- create方法的参数:
- Class:字节码,它是用于指定被代理对象的字节码
- Callback:用于增强的代码,它是让我们如何写代理的,我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的,此接口的实现类都是谁用谁写,我们一般写的都是该接口的子接口实现类MethodInterceptor
关于MethodInterceptor类中的intercept方法的参数问题:
- proxy:代理对象的引用
- method:当前执行的方法
- args:当前执行方法的参数
- methodProxy:当前执行方法的代理对象
转载地址:http://iljmb.baihongyu.com/