2020-01-07动态代理

个人日记:不建议购买

一、代理模式的第一个版本:静态代理

如图所示:


图片.png

图中反应的本质:

  • 代理对象和被代理对象实现相同的接口。
  • 代理对象中包含被代理对象。
    (不禁感叹:静态代理和装饰器模式好像啊!!)

代码表现:

Class ProxyObject implements A,B,C{
  private A a;
  private B b;
  private C c;
//在方法中调用具体对象a,b,c的方法并且对方法进行增强

}
静态代理的测试方法.png

静态代理存在的问题:

  • 代码的冗余
  • 不符合开闭原则,所谓开闭原则是指对扩展开放,对修改关闭(当我们的需求发生变化的时候,我们通过添加新的模块来满足新的需求,而不是通过修改原来的代码来满足)。这个原则是六个设计原则中最重要的。

如果不满足单一原则会发生

  • 可读性变差
  • 可维护性变差(代码耦合性比较高),只要有一个功能模块发生了变化,代理类就会出错,牵一发动全身,代理类也没法为其他的模块提供服务了。

静态代理作为代理模式的第一个实现版本,存在以上比较严重的问题。违反了开闭原则。

二、代理模式的第二个版本:动态代理

代理:代理模式
动态:???

静态代理和动态代理的类图是一毛一样的!!对于动态代理来说,它的代理对象不再是一个固定的对象,而是一个动态的对象。可以在使用的时候进行动态的生成。

图片.png

Proxy:调度各种员工进行服务
查看源码看proxy的功能:

InvocationHandler:本质就是对服务进行增强

这里体现了单一职责的原则:

  • Proxy仅仅负责创建对象;
  • InvocationHandler负责实例做的事情;

方法增强的类中含有被代理对象:
下面的例子中使用接口是面向接口编程,解耦


图片.png
图片.png

这里使用反射去调用运行的方法,因为不知道究竟是哪个被代理对象在运行。


图片.png

关于类加载器,不同的类加载器可以随便使用吗?还有,继承关系的两个类,类加载器一样吗??


图片.png

这样的话使用一套代码就能够满足所有的需求。

二、深入内核剖析

解密事务注解

我们可以发现代理对象的名称是$Proxy+数字。
这种名字是内部类

接下来探索这两个类究竟是什么,发现它们不曾出现在文件中,那么是怎样产生的呢??
首先来看一下类的生命周期:


图片.png

编译使用的命令:javac XXX.java
java的跨平台性质也是因为字节码技术。
Class对象存在于JVM的方法区或者叫元空间,在jdk1.8之前是方法区,后来叫做元空间。
实例对象在堆上。
可达性分析可以帮助判断这个类需不需要进行回收。

面试的问题形式:
不会问你有什么垃圾回收算法或者垃圾回收器,而是问你在你的项目中使用了什么垃圾回收算法,为什么使用这种垃圾回收算法和回收器。它有什么优点。

动态代理忽略了java文件,直接生成的就是java字节码,java字节码有两种来源,一种是硬盘,一种是内存

tomcat的类热加载机制???从网络中传输字节码
mapper的实际实现原理??

1、怎样在内存中生成字节码?
内存中生成的字节码究竟是什么样子??
Proxy.newInstance()进行分析。

分析代码Class cl = getProxyClass0(loader,intfs),这句代码完成两件事情:

  1. 在JVM中生成了字节码
  2. 将字节码文件加载成了Class对象。

native方法,直接调用操作系统的类库生成的方法。用c或者是c++写的。

那么生成代码的结构是什么样呢??
使用反编译工具看一看这个类究竟是什么样子的。


图片.png
图片.png
图片.png

产生的所有Proxy对象都是Proxy的子类对象


图片.png

使用动态代理解析spring相关的注解源码:

面试题:
1、spring事务注解的实现原理?
为什么加了@Transactional注解之后,方法就有了事务的能力?
首先是JdkDynamicAopProxy,其中有一个方法,这个方法会经过一系列的拦截器链,然后是TransactionaIntercepter这个拦截器,在这个拦截器中实现了方法前的事务开启,方法后的事务结束,出现异常的回滚操作。

2、为什么Mybatis可以直接使用mapper接口访问数据库?

你可能感兴趣的:(2020-01-07动态代理)