一、如何基于Spring写优雅易扩展的代码
1.1 案例一
1.1.1 如何实现订单金额的计算
-
策略模式 实现面向接口编程,由于计算金额的方法是会增加的,比如促销方案是会变的,可以利用策略模式,将订单金额计算的方法抽象为接口,有不同的促销模式时候实现该接口(接口隔离原则),避免频繁的修改代码(开闭原则)
-
工厂模式 利用工厂方法实现方案计算方法实例的生成,(根据传入的String)利用反射获取各种金额计算方案的实现,如果是自己利用反射技术实现简单工厂的话,每次有新促销方案的话我们需要修改自定义的工厂,因为工厂需要初始化各个促销接口的实现类,为此引入下列几种方式,通过将变化的部分以配置文件的方式隔离(SPI)、Spring注入、Spring提供的工厂真正实现开闭原则。
-
Java SPI:
接口服务发现机制
,对接口的实现类自动完成加载。SPI机制可以避免硬编码的问题,厂商通过规定的配置规则,即使用方提供规则,提供方根据规则把自己加载到提供方的思想
。在Java中通过ServiceLoader
加载约定配置下的实现类,ServiceLoader<Driver> s = ServiceLoader.load(Driver.class);
如:-
- MySQL的驱动加载时,在
META/services
中以调用者给定的完整接口名
命名文件,文件内容为该接口的具体实现完整类名
;
- MySQL的驱动加载时,在
-
- Spring中的
component-scan
注解标签,会将@Controller、@Service等的标签注入到容器中,也就是Spring制定了规则,开发者根据规则去实现。
- Spring中的
- 参考: https://zhuanlan.zhihu.com/p/28909673
-
-
Dubbo SPI
-
Spring实现
@Autowired Map<String,Order> map
,利用Map可以自动将所有Order接口的实现类注入
- 利用
ApplicationContext
获取bean并实现方法的调用,即利用Spring提供的工厂模式
-
二、如何提高工作效率
为什么我们的工作效率不高
- 我们掌握的方法、技能、工具不多,不知道还有更好的开发模式,一直采用传统的堆代码开发,
要提高工作效率,需要多掌握更多更好的开发方法、工具和技能
。
高薪人的优势是什么
- 能够解决更大的问题,更难的问题
- 相同时间解决的问题更多,绝对不是因为加班多才会薪资高
三、如何基于Spring写解耦易扩展的代码
3.1 案例分析
3.1.1 业务场景演示
常规代码流程:
问题
- 同步调用
- 如何邮件发送异常,则短信服务也无法进行,订票失败
- 违反单一原则(在订单方法中加入了邮件和短信通知)
与不是强相关的类耦合
(航班预定与邮箱、短信类) - 复用性极低- 如果有新功能加入,如需要发微信、QQ,则会违反开闭原则,不易扩展
基于事件驱动
的流程(观察者模式):
事件驱动
- 发布者:OrderService类中的预定订单方法
- 事件:航班预定事件,即Order(订单)对象为事件
- 事件通道:spring(
ApplicationContext
提供事件的发布通道,如publishEvent(Object o)
和publishEvent(ApplicationEvent event)
方法,一个用于对象事件如订单生成Order对象、一个用于应用事件如应用启动关闭事件,可以用于Spring启动的时候进行相关的初始化任务) - 监听者:邮件发送类、短信发送类
Spring注解
-
@Async
:异步执行注解 -
@Transactional
:添加事务 -
观察者模式
- 监听者:
@EventListener
@EventListener @Async //异步执行 public void handleOrderEvent(Order order){ //上面的传入对象参数即为监听的事件,该监听方法只对Order事件感兴趣 Email mail = ...; this.sendMail(email); }
- 发布者:在发生订单事件的方法中调到Spring提供的`ApplicationContext`的发布方法
@Autowired ApplicationContext context; public void bookOrder(Order o){ ... context.publishEvent(order); }
- 监听者:
四、如何基于Spring写异步、定时任务
异步方式
- 方式一:配置ApplicationEventMuticaster的Bean(基于事件的异步)
- Spring提供,配置configuration的Bean,并在其中配置线程池(没有线程池配置则为同步)
- 缺点:一刀切(所有的事件执行都变为异步的)
- 方式二:@EnableAsync @Async(基于Bean的异步)
- 控制Bean的方法调用为异步执行(灵活),需要特定线程池则进行配置
@EnableAsync
:开启SpringBoot异步模式@Async
:被标识的方法在调用的时候为异步调用,未被标识的方法为同步执行
定时任务
@EnableScheduling
:开启SpringBoot定时任务@Schedule
:在执行逻辑的Bean(@Component
)的方法上注释即可实现定时任务
五、如何扩展我们的技术广度
针对事情快速应对,即想到相应的方法。需要有好的技术,想想如何达到高薪的位置,而不是单单想着拿高薪。 单机的技术使用跟分布式的使用是不同的,单机的可以充分利用Spring的高级用法,而分布式则更多的依赖于中间件,比如上面说的事件驱动编程,如果在Spring中可以利用其注解快速实现,而分布式环境中则需要利用
MQ
实现发布订阅模式,要能快速的想出解决方案,需要我们有足够的知识广度。
扩展技术广度的方法
- 参加课程
- 技术大牛带
- 项目的洗礼
- 去大的互联网公司
- 多看书、多交流探讨