麻涌建设网站,运城学院教务网络管理系统,wordpress相册模板,仿08影院wordpress作者简介#xff1a;大家好#xff0c;我是smart哥#xff0c;前中兴通讯、美团架构师#xff0c;现某互联网公司CTO 联系qq#xff1a;184480602#xff0c;加我进群#xff0c;大家一起学习#xff0c;一起进步#xff0c;一起对抗互联网寒冬 到目前为止#xff0c…作者简介大家好我是smart哥前中兴通讯、美团架构师现某互联网公司CTO 联系qq184480602加我进群大家一起学习一起进步一起对抗互联网寒冬 到目前为止在Java基础进阶这个章节我们已经帮大家梳理了很多晦涩但极其重要的知识点包括反射、注解和泛型。这些都是我们迈向中高级程序员的小碎步我们已经离“成熟的码农”越来越近了但还不够。今天我们仍需一起再往前走一小步JDK动态代理。个人认为Java基础有“四大神兽”除了刚才说的反射、注解和泛型JDK动态代理就是最后一道坎。 “动态代理”四个字一出来估计很多初学者已经开始冒冷汗。它之所以给人感觉很难有三点原因
代码形式很诡异让人搞不清调用逻辑用到了反射而很多初学者不了解反射现在你应该感觉好些了包含代理模式的思想本身比较抽象 尽管动态代理看起来似乎有一定难度但却必须拿下。因为Spring的事务控制依赖于AOPAOP底层实现便是动态代理 责任链环环相扣。所以说搞编程的拼到到最后还是看基本功要么是语言基础、要么是计算机基础。 一个小需求给原有方法添加日志打印
假设你刚进入一个项目组项目中存在一个Calculator类代表一个计算器它可以进行加减乘除操作
public class Calculator {// 加public int add(int a, int b) {int result a b;return result;}// 减public int subtract(int a, int b) {int result a - b;return result;}// 乘法、除法...
}
现在老大给你提了一个需求在每个方法执行前后打印日志。 你有什么好的方案 方案一直接修改
很多人最直观的想法是直接修改Calculator类
public class Calculator {// 加public int add(int a, int b) {System.out.println(add方法开始...);int result a b;System.out.println(add方法结束...);return result;}// 减public int subtract(int a, int b) {System.out.println(subtract方法开始...);int result a - b;System.out.println(subtract方法结束...);return result;}// 乘法、除法...
}
上面的方案是有问题的
直接修改源程序不符合开闭原则即好的程序设计应该对扩展开放对修改关闭如果Calculator类内部有几十个、上百个方法修改量太大存在重复代码都是在核心代码前后打印日志日志打印硬编码在代理类中不利于后期维护比如你花了一上午终于写完了组长告诉你这个功能不做了于是你又要打开Calculator花十分钟删除日志打印的代码或回滚分支 所以此种方案PASS 方案二静态代理实现日志打印
“静态代理”四个字包含了两个概念静态、代理。我们先来了解什么叫“代理”至于何为“静态”需要和“动态”对比着讲。
代理是一种模式提供了对目标对象的间接访问方式即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作前拦截后拦截等以满足自身的业务需求。 常用的代理方式可以粗分为静态代理和动态代理。 静态代理的实现比较简单编写一个代理类实现与目标对象相同的接口并在内部维护一个目标对象的引用。通过构造器塞入目标对象在代理对象中调用目标对象的同名方法并添加前拦截后拦截等所需的业务功能。 是不是有点晕是的我最讨厌这种干巴巴的描述。简而言之就是这样 按上面的描述代理类和目标类需要实现同一个接口所以我打算这样做
将Calculator抽取为接口创建目标类CalculatorImpl实现Calculator创建代理类CalculatorProxy实现Calculator 抽取接口
/*** Calculator接口*/
public interface Calculator {int add(int a, int b);int subtract(int a, int b);
}
原目标类实现接口
/*** 目标类实现Calculator接口如果一开始就面向接口编程其实是不存在这一步的CalculatorImpl原本就实现Calculator接口*/
public class CalculatorImpl implements Calculator {// 加public int add(int a, int b) {int result a b;return result;}// 减public int subtract(int a, int b) {int result a - b;return result;}// 乘法、除法...
}
新增代理类并实现接口
/*** 静态代理类实现Calculator接口*/
public class CalculatorProxy implements Calculator {// 代理对象内部维护一个目标对象引用private Calculator target;// 通过构造方法传入目标对象public CalculatorProxy(Calculator target) {this.target target;}// 调用目标对象的add并在前后打印日志Overridepublic int add(int a, int b) {System.out.println(add方法开始...);int result target.add(a, b);System.out.println(add方法结束...);return result;}// 调用目标对象的subtract并在前后打印日志Overridepublic int subtract(int a, int b) {System.out.println(subtract方法开始...);int result target.subtract(a, b);System.out.println(subtract方法结束...);return result;}// 乘法、除法...
}测试案例
使用代理对象完成加减乘除并且打印日志
public class Test {public static void main(String[] args) {// 把目标对象通过构造器塞入代理对象Calculator calculator new CalculatorProxy(new CalculatorImpl());// 代理对象调用目标对象方法完成计算并在前后打印日志calculator.add(1, 2);calculator.subtract(2, 1);}
} 静态代理的优点可以在不修改目标对象的前提下对目标对象进行功能的扩展和拦截。但是它也仅仅解决了上一种方案4大缺点中的第1、4两点
直接修改源程序不符合开闭原则即好的程序设计应该对扩展开放对修改关闭✅如果一开始就面向接口编程这一步其实是不需要的如果Calculator类内部有几十个、上百个方法修改量太大❎目标类有多少个方法代理类就要重写多少个方法存在重复代码都是在核心代码前后打印日志❎代理类中的日志代码是重复的日志打印硬编码在代理类中不利于后期维护比如你花了一上午终于写完了组长告诉你这个功能不做了✅别用代理类就好了 静态代理的问题
上面的代码中为了给目标类做日志增强我们编写了代理类而且准备了一个构造器接收目标对象。代理代理对象构造器的参数类型是Calculator这意味着它只能接受Calculator的实现类对象亦即我们写的代理类CalculatorProxy只能给Calculator做代理它们绑定死了 如果现在我们系统需要全面改造要给其他类也添加日志打印功能就得为其他几百个接口都各自写一份代理类... 自己手动写一个类并实现接口实在太麻烦了。仔细一想我们其实想要的并不是代理类而是代理对象
你细品上面加粗的这句话是不是好像一句废话没有类哪来的对象 其实我的意思是能否让JVM根据接口自动生成代理对象呢
比如有没有一个方法我传入接口增强的代码比如打印日志它就给我自动返回代理对象呢这样就能省去编写代理类这个无用的“中介”了没有中间商赚差价岂不爽哉 JDK能做到吗 预知后事如何请听下回分解~
作者简介大家好我是smart哥前中兴通讯、美团架构师现某互联网公司CTO 进群大家一起学习一起进步一起对抗互联网寒冬