1.java反射机制
理解代理模式的前提是先理解java中的反射机制,先看一个例子:

JDBC加载驱动时,Class.forName(“com.mysql.jdbc.Driver”);
此时通过反射加载连接mysql数据库的jar包,该句等价于import com.mysql.jdbc.Driver;
可是为什么不直接导入呢?这就是反射设计的合理之处了。
<1>,用反射可以在运行时动态导入,直接导入是在编译时就确定com.mysql.jdbc.Driver包必须存在,否则编译不过,这样看来,加上反射,可执行的范围增大了。
<2>,提高复用率,加上反射,Class.forName(“从配置文件读取具体的包内容”),这样,当你更换数据库时,只需更改配置文件,而不用像导入的方式那样挨个更换你的import。
java反射就是在运行时动态获取类的信息,方法,构造方法等信息。可以加载一个在运行时才确定其名称信息的类,并确定该类的基本信息。

2.由反射引出的设计模式-代理模式
代理模式概念理解:我自己能做的事情,让别人代替我来做,例如,我点了份菜,可以自己下楼去拿,但我现在比较忙,就让外卖小哥帮忙送上来,这块,外卖小哥就充当一个中间人的角色,帮我把事情做了。

3.静态代理模式
代理类由程序员自己实现的。就是再定义一个实现被代理类所实现的接口的代理类。
具体:

public interface People {public void execute();}
public class My implements People {@Overridepublic void execute() {System.out.println("拿外卖");}}
public class WaiMaiXiaoGe implements People {public My my;public WaiMaiXiaoGe(My my){this.my=my;}@Overridepublic void execute() {System.out.println("打包外卖");my.execute();System.out.println("送外卖结束");}}

4.动态代理模式
概念:在运行的过程中运用反射动态创建代理类。
<1>JDK动态代理
01具体过程:
1.定义一个事件管理器类实现invocationHandle接口,并重写invoke(代理类,被代理的方法,方法的参数列表)方法。
2.实现被代理类及其实现的接口,
3.调用Proxy.newProxyInstance(类加载器,类实现的接口,事务处理器对象);生成一个代理实例。
4.通过该代理实例调用方法。
02代码实现:

public interface People {public void execute();}
package com.Dream.Design;/*** @author wangpei* @version 创建时间:2017年4月22日 下午4:20:23 类说明*/
public class My implements People {@Overridepublic void execute() {System.out.println("拿外卖");}}
package com.Dream.Design;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** @author wangpei* @version 创建时间:2017年4月22日 下午5:31:23 类说明*/
public class Handler implements InvocationHandler {private Object o = null;public Handler(Object o) {this.o = o;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("外卖小哥取外卖");method.invoke(o, args);System.out.println("送外卖完成");return null;}}
package com.Dream.Design;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** @author wangpei* @version 创建时间:2017年4月22日 下午5:31:23 类说明*/
public class Handler implements InvocationHandler {private Object o = null;public Handler(Object o) {this.o = o;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("外卖小哥取外卖");method.invoke(o, args);System.out.println("送外卖完成");return null;}}

结果:

外卖小哥取外卖
拿外卖
送外卖完成

03具体分析
怎么通过Proxy.newProxyInstance(,,,,)就能生成一个代理实例呢。
我们分析方法内部:

 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{Objects.requireNonNull(h);//事务处理器为空抛出异常。final Class<?>[] intfs = interfaces.clone();//被代理类实现的接口数组Class<?> cl = getProxyClass0(loader, intfs);//获得代理类final Constructor<?> cons = cl.getConstructor(constructorParams);//获得代理类的构造方法//返回构造方法的实例return cons.newInstance(new Object[]{h});}

ps:上面是我把验证部分的处理删了的源码,千万别以为源码长这样。。

当然,我们要看一看getProxyClass0()方法的具体实现

private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}// If the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces);//###############}

如上图#处,那再看proxyClassCache.get(loader, interfaces);的实现

public V get(K key, P parameter) {Objects.requireNonNull(parameter);expungeStaleEntries();Object cacheKey = CacheKey.valueOf(key, refQueue);ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);if (valuesMap == null) {ConcurrentMap<Object, Supplier<V>> oldValuesMap= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());if (oldValuesMap != null) {valuesMap = oldValuesMap;}}Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));//#######Supplier<V> supplier = valuesMap.get(subKey);Factory factory = null;while (true) {if (supplier != null) {V value = supplier.get();if (value != null) {return value;}}if (factory == null) {factory = new Factory(key, parameter, subKey, valuesMap);}if (supplier == null) {supplier = valuesMap.putIfAbsent(subKey, factory);if (supplier == null) {// successfully installed Factorysupplier = factory;}} else {if (valuesMap.replace(subKey, supplier,factory)){supplier = factory;} else {supplier = valuesMap.get(subKey);}}}}

再继续往下,我们找到根源:ProxyClassFactory

private static final class ProxyClassFactoryimplements BiFunction[], Class>>{// prefix for all proxy class namesprivate static final String proxyClassNamePrefix = "$Proxy";// next number to use for generation of unique proxy class namesprivate static final AtomicLong nextUniqueNumber = new AtomicLong();@Overridepublic Class> apply(ClassLoader loader, Class>[] interfaces) {Map, Boolean> interfaceSet = new IdentityHashMap(interfaces.length);for (Class> intf : interfaces) {/** Verify that the class loader resolves the name of this* interface to the same Class object.*/Class> interfaceClass = null;try {interfaceClass = Class.forName(intf.getName(), false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != intf) {throw new IllegalArgumentException(intf + " is not visible from class loader");}/** Verify that the Class object actually represents an* interface.*/if (!interfaceClass.isInterface()) {throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}/** Verify that this interface is not a duplicate.*/if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());}}String proxyPkg = null;     // package to define proxy class inint accessFlags = Modifier.PUBLIC | Modifier.FINAL;/** Record the package of a non-public proxy interface so that the* proxy class will be defined in the same package.  Verify that* all non-public proxy interfaces are in the same package.*/for (Class> intf : interfaces) {int flags = intf.getModifiers();if (!Modifier.isPublic(flags)) {accessFlags = Modifier.FINAL;String name = intf.getName();int n = name.lastIndexOf('.');String pkg = ((n == -1) ? "" : name.substring(0, n + 1));if (proxyPkg == null) {proxyPkg = pkg;} else if (!pkg.equals(proxyPkg)) {throw new IllegalArgumentException("non-public interfaces from different packages");}}}if (proxyPkg == null) {// if no non-public proxy interfaces, use com.sun.proxy packageproxyPkg = ReflectUtil.PROXY_PACKAGE + ".";}/** Choose a name for the proxy class to generate.*/long num = nextUniqueNumber.getAndIncrement();String proxyName = proxyPkg + proxyClassNamePrefix + num;/** Generate the specified proxy class.*///######################byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);try {return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/** A ClassFormatError here means that (barring bugs in the* proxy class generation code) there was some other* invalid aspect of the arguments supplied to the proxy* class creation (such as virtual machine limitations* exceeded).*/throw new IllegalArgumentException(e.toString());}}}

上面代码很容易看出,
调用ProxyGenerator.generateProxyClass生成代理类。
byte[] proxyClassFile字节码反编译后发现:
生成代理类 class ProxySubject extends Proxy implements Subject

现在我们总结一下,当我们调用代理类的方法时(即上面的步骤4),会通过反射处理为调用,实现管理器的实现类中的invote()方法,调用
handler.invoke(this, m3, null);

还有许多不太透彻的地方,望批评指正,下节介绍代理模式在spring aop中的具体应用。

理解java代理模式相关推荐

  1. 【重铸Java根基】理解Java代理模式机制

    最近带应届新员工,教然后知不足,发现自己把很多基础知识已经还给了大学老师,因此开贴,温故而知新! 从最基础的Java知识开始由浅入深,在某个知识点中遇到有疑惑的点会额外多写几句或者单独开帖子展开. ​ ...

  2. 如何理解java代理模式?

    需求 假设现在有一个需求:在项目现有所有类的方法前后打印日志. 你如何在不修改已有代码的前提下,如何完成这个需求? 直切主题 那这个时候我们可以使用动态代理 要理解动态代理首先要理解代理模式 什么是代 ...

  3. 浅谈自己对Java代理模式的理解--即为什么要用怎么用

    首先,国际惯例,上Java代理模式的定义:  Java代理模式:对其他对象提供一种代理以控制对这个对象的访问.              定义很简单,就一句话,怎么去理解,不急,先听一个小故事: 故事 ...

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

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

  5. java代理模式(java代理模式和适配器模式)

    Java设计模式的中介者模式是怎样的? 如果对象之间的关系原本一目了然,中介对象的加入便是"画蛇添足". 来看下中介者模式的组成部分吧. 1) 抽象中介者(Mediator)角色: ...

  6. Java代理模式汇编

    文章目录 Java 代理模式实现方式,主流如下五种方法 Notes 静态代理实现 实现步骤 Cat接口 委托类 Lion 代理类角色(FeederProxy) 静态代理类测试 动态代理类(基于接口实现 ...

  7. java代理模式_Java代理

    java代理模式 本文是我们名为" 高级Java "的学院课程的一部分. 本课程旨在帮助您最有效地使用Java. 它讨论了高级主题,包括对象创建,并发,序列化,反射等. 它将指导您 ...

  8. java代理模式总结

    Java代理模式根据代理类生成时间的不同,可以分为静态代理和动态代理,它如同中介机构,可以为目标类提供代理服务,以控制对对象的访问,目标类的任何方法在执行前都必须经过代理类,这样代理类就可以用来负责请 ...

  9. java代理模式实现

    java代理模式实现 @(代理模式)[静态代理,动态代理,InvocationHandler] java的代理模式 分为两种,静态代理和动态代理,学习下什么是代理和静态动态代理的作用. java代理模 ...

最新文章

  1. pythonexe32位-如何使用pyinstaller打包32位的exe
  2. Python3 内置http.client,urllib.request及三方库requests发送请求对比
  3. hadoop入门-在windows上编译x64位hadoop
  4. 微软2021校园招聘正式启动
  5. 循环队列(0965)
  6. mysql常用的约束_MySQL常用的约束条件
  7. 微型计算机中被处理信息称为,2011海南省计算机等级考试试题 二级C试题考资料...
  8. JavaScript——面向对象(封装)
  9. 浅入深出Vue:注册
  10. 关于excel密码 工作表密码 工作簿密码 工程密码
  11. 为什么Java中只有值传递
  12. How to install innotop and percona tookit on centos
  13. 鸿蒙本质是安卓吗,华为鸿蒙系统遭实锤,本质还是安卓系统
  14. 2021-08-08 WPF控件专题 StackPanel 控件详解
  15. 构建自己企业的邮箱验证服务
  16. 初中计算机课师徒结对活动记录,2013师徒结对活动记录
  17. 小程序如何写一个优美的tab选项卡
  18. 【实用工具01】免费的比较工具Meld
  19. 解决HTML中文乱码
  20. ChatGPT4吊打国内一众所谓山寨科技公司

热门文章

  1. python 帮助台_想知道拉夫堡大学和Queen mary 的商业分析硕士好吗,学得东西有没有用,实不实用?...
  2. 第六章 DirectX 2D游戏和帧动画(上)
  3. mipsel_24kc的linux内核,mips与mipsel相关编译问题
  4. Python--总结第一阶段
  5. Python第一阶段学习 day10
  6. 形态学梯度运算、礼帽运算
  7. java计算机毕业设计供电公司安全生产考试系统源码+mysql数据库+系统+lw文档+部署
  8. 汕头东厦中学2021年高考成绩查询,2021年汕头高中录取分数线是多少及高中排名榜...
  9. wrapper-windows-x86 window 10安装
  10. 2010年全国专业技术人员计算机应用能力考试(职称计算机考试)专用教程下载汇总...