最近带应届新员工,教然后知不足,发现自己把很多基础知识已经还给了大学老师,因此开贴,温故而知新!

从最基础的Java知识开始由浅入深,在某个知识点中遇到有疑惑的点会额外多写几句或者单独开帖子展开。

什么是代理模式

简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

代理模式的主要作用是扩展目标对象的功能,比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。

先来看一下最基本的静态代理

1.先创建一个接口,定义方法,并创建一个被代理类实现这个接口和方法

2.再创建一个代理类同样实现这个接口和方法,并且将被代理类注入到代理类中

3.在代理类中调用被代理类的同名方法,这样就可以在调用前后做更多的业务操作

静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(需要对每个目标类都单独写一个代理类)。 实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

下面说一下动态代理,动态代理在日常开发的业务代码中其实也很少见,但是在框架型项目中几乎是必不可少的,因此理解动态代理的原理有利于理解框架。

JDK动态代理

JDK动态代理基于接口、JDK提供的Proxy类和InvocationHandler类

调用Proxy类的newProxyInstance方法来创建一个代理对象

这个方法一共有 3 个参数:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
{......
}

loader : 目标类的类加载器。
interfaces : 目标类实现的一些接口;
h : 实现了 InvocationHandler 接口的对象;

其中h需要自己定义一个对象来实现InvocationHandler 接口,并重写里面的invoke方法,invoke方法内部就是具体的业务逻辑

public interface InvocationHandler {/*** 当你使用代理对象调用方法的时候实际会调用到这个方法*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

invoke() 方法有下面三个参数:

proxy :动态生成的代理类,由jdk在动态代理的编译过程中产生
method : 与代理类对象调用的方法相对应
args : 当前 method 方法的参数
也就是说:你通过Proxy 类的 newProxyInstance() 创建的代理对象在调用方法的时候,实际会调用到实现InvocationHandler 接口的类的 invoke()方法。 你可以在 invoke() 方法中自定义处理逻辑,比如在方法执行前后做什么事情。

JDK 动态代理类使用步骤

定义一个接口及其实现类;
自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;

那么为什么JDK动态代理为什么必须针对接口

查看jdk的动态代理源码发现:
动态代理实际上是程序在运行中,根据被代理的接口来动态生成代理类的class文件,并加载class文件运行的过程,通过反编译被生成的$Proxy0.class文件发现:
class类定义为:
public final class $Proxy0 extends Proxy implements Interface {
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}

该方法为被代理接口的业务方法,代理类都会自动生成相应的方法,里面去执行invocationHandler 的invoke方法。

由于java的单继承,动态生成的代理类已经继承了Proxy类的,就不能再继承其他的类,所以只能靠实现被代理类的接口的形式,故JDK的动态代理必须有接口。

JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类
为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。

CGLIB 动态代理机制

很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。
不同于 JDK 动态代理不需要额外的依赖。CGLIB(Code Generation Library) 实际是属于一个开源项目,如果你要使用它的话,需要手动添加相关依赖。

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

在 CGLIB 动态代理机制中 MethodInterceptor 接口和 Enhancer 类是核心。

你需要自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法。

public interface MethodInterceptor
extends Callback{// 拦截被代理类中的方法public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}

obj : 动态生成的代理对象
method : 被拦截的方法(需要增强的方法)
args : 方法入参
proxy : 用于调用原始方法

你可以通过 Enhancer类来动态获取代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的 intercept 方法。

CGLIB 动态代理类使用步骤
1.定义一个类;
2.自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;

public class DebugMethodInterceptor implements MethodInterceptor {/*** @param o           代理对象(增强的对象)* @param method      被拦截的方法(需要增强的方法)* @param args        方法入参* @param methodProxy 用于调用原始方法*/@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//调用方法之前,我们可以添加自己的操作System.out.println("before method " + method.getName());Object object = methodProxy.invokeSuper(o, args);//调用方法之后,我们同样可以添加自己的操作System.out.println("after method " + method.getName());return object;}}

3.通过 Enhancer 类的 create()创建代理类;

import net.sf.cglib.proxy.Enhancer;public class CglibProxyFactory {public static Object getProxy(Class<?> clazz) {// 创建动态代理增强类Enhancer enhancer = new Enhancer();// 设置类加载器enhancer.setClassLoader(clazz.getClassLoader());// 设置被代理类enhancer.setSuperclass(clazz);// 设置方法拦截器enhancer.setCallback(new DebugMethodInterceptor());// 创建代理类return enhancer.create();}
}

4.调用

myService aliSmsService = (myService ) CglibProxyFactory.getProxy(myService .class);
aliSmsService.doSomeThing("java");

【重铸Java根基】理解Java代理模式机制相关推荐

  1. Java的三种代理模式完整源码分析

    Java的三种代理模式&完整源码分析 Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCach ...

  2. Java的三种代理模式【附源码分析】

    Java的三种代理模式&完整源码分析 代理模式分为两种,静态代理和动态代理,动态代理包括JDK动态代理和Cglib动态代理. 静态代理 静态代理在使用时,需要定义接口或者父类,被代理对象与代理 ...

  3. Java的三种代理模式简述

    本文着重讲述三种代理模式在java代码中如何写出,为保证文章的针对性,暂且不讨论底层实现原理,具体的原理将在下一篇博文中讲述. 代理模式是什么 代理模式是一种设计模式,简单说即是在不改变源码的情况下, ...

  4. 北风设计模式课程---深入理解[代理模式]原理与技术

    北风设计模式课程---深入理解[代理模式]原理与技术 一.总结 一句话总结: 不仅要通过视频学,还要看别的博客里面的介绍,搜讲解,搜作用,搜实例 设计模式都是对生活的抽象,比如用户获得装备,我可以先装 ...

  5. Java——深入理解Java异常体系

    Java--深入理解Java异常体系 参考文章: (1)Java--深入理解Java异常体系 (2)https://www.cnblogs.com/wugongzi/p/11858228.html 备 ...

  6. 【java项目实战】代理模式(Proxy Pattern),静态代理 VS 动态代理

    这篇博文,我们主要以类图和代码的形式来对照学习一下静态代理和动态代理.重点解析各自的优缺点. 定义 代理模式(Proxy Pattern)是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并 ...

  7. java的三种代理模式

    2019独角兽企业重金招聘Python工程师标准>>> 1.代理模式很好地将两个直接关联的类进行了解耦,并且还可以在代理类中添加额外的代码,以进行特殊的处理,如果不采用代理模式,当两 ...

  8. Java拾遗:007 - 代理模式与动态代理

    2019独角兽企业重金招聘Python工程师标准>>> 代理模式 在日常开发中我们可以会接手一些老的项目,有时连源码都没有,或者有时候我会需要对业务逻辑做一定增强(功能扩展,如:日志 ...

  9. 23种java设计模式详解-代理模式

    什么是代理模式: Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问.所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类, ...

最新文章

  1. 工作中不要为了用系统而用系统
  2. 看博客不回是小狗『博客运营随笔11.20』
  3. 数学之美 系列八-- 贾里尼克的故事和现代语言处理
  4. 卷积神经网络之 - VGGNet
  5. 重庆电子工程学院计算机专业,重庆计算机电子工程职业学院2020年招生录取分数线...
  6. cello 有关状态
  7. mac版本 sadptool_EZParkTools下载-智慧停车维护工具 v1.0 官方版 - 安下载
  8. 经典商业模式案例第1例:校园O2O
  9. Linux下查看网卡光衰值
  10. RabbitMQ队列,直连队列,主题队列,扇形队列,死信队列,延迟
  11. 关于家庭小型无线网络信号不稳定的说明
  12. 为什么别人在微信卖东西不会被人拉黑
  13. 解决Pycharm出现的Debug无法正常运行(Frames are not available)的问题
  14. R语言用Rshiny探索lme4广义线性混合模型(GLMM)和线性混合模型(LMM)
  15. python编程midi键盘按键错乱_键盘按键错乱有以下几种相应的解决办法
  16. 云阶月地,关锁千重(一.公平和非公平)
  17. java获取当前年份(java获取当前年份后两位)
  18. CAD 批量提取点坐标,实现坐标的快速提取
  19. linux安装7zip 64位下载,7-Zip首页、教程和下载-压缩软件-软件交流社区–完美下载...
  20. 需求理论:Web3集成分析

热门文章

  1. 【千律】C++基础:求出M以内的全部素数-方案1
  2. boosting 算法总结
  3. 用计算机发现计算规律,用计算器探索规律导学案.doc
  4. music generation with DL and sings datasets music datasets
  5. 前端面试题及答案!!!!!!!
  6. Android.mk基础知识
  7. kali提升root权限
  8. 【Android】ImageView的maxWidth,maxHeight的使用
  9. 万向肖风:从人人都能发资产到人人都能发应用 | Sodium线上发布会
  10. 【毕业设计】Java局域网聊天室系统的设计与实现