ABAP模拟Java Spring依赖注入(Dependency injection)的一个尝试

Recently I will deliver a session regarding dependency inversion principle to my team.

As Java Spring is already widely used in all other Java development teams in my site, some ABAPers are not well aware of its idea and implementation under the hood. In order for ABAPers to easily understand the mechanism of Java Spring dependency inversion, I wrote a prototype in ABAP after going through related Java source code of Spring.

Before I start, I perform the search in SCN. There are already several excellent blogs written regarding dependency injection in ABAP:

(1) ABAP Dependency Injection – An implementation approach
(2) Shoot Me Up ABAP
(3) Dependency Injection for ABAP
(4) MockA in github

Thanks a lot for efforts spent by authors of them!
Compared with those blogs, the advantage of my prototype is: it follows exactly the design of Java Spring, it is not needed for users to do any other manual dependency registration except a single annotation @Inject. So it is useful for ABAPers to understand Spring dependency internal implementation.

Let me begin with a simple example. In real world I have a switch. By pressing it, the lamp connected by that switch is turned on. With switch pressed for second time, the lamp is turned off. That’s all.

Implementation without using Dependency injection

I have an interface ZIF_SWITCHABLE with two simple methods:

And a ZCL_LAMP which simply implements this interface:


CLASS ZCL_LAMP IMPLEMENTATION.
method ZIF_SWITCHABLE~OFF.
    WRITE: / 'lamp off'.
  endmethod.

 method ZIF_SWITCHABLE~ON.
    WRITE: / 'lamp on'.
  endmethod.
ENDCLASS.

And a switch which internally maintains the current switch status and a reference to ZIF_SWITCHABLE:

The switch has a push method to toggle:


METHOD push.
    IF isswitchon = abap_true.
      mo_switchable->off( ).
      isswitchon = abap_false.
    ELSE.
      mo_switchable->on( ).
      isswitchon = abap_true.
    ENDIF.
 ENDMETHOD.

And a setter method is needed to inject the switchable instance:


method SET_SWITCHABLE.
    mo_switchable = io_switchable.
endmethod.

These two classes and one interface are put to the following package:

Consumer code – version one without using dependency injection

Here the ZCL_SWITCH has tight dependency on ZCL_LAMP: it has to manually inject this dependency via setter method in line 11.

Let’s summarize how many manual / unnecessary operations are done by consumer:

(1) line 8: create lamp instance
(2) line 9: create switch instance
(3) line 11: connect switch with lamp

Implementation using ABAP Summer

I call my prototype as ABAP Summer just to show my admire on Java Spring

When the same requirement is implemented in Java Spring, the logic in line 11 could completely be avoided, with help of various powerful annotation like @Autowired, @Named, @Inject etc. Thanks to Java Spring container, lots of labor work has been done by it under the hood, saving lots of routine effort from application developers so that they can only concentrate on the core business logic. For example, in Java using Spring, all developers need to do is to add annotation @Inject on top of attribute switchable – in the runtime Spring will guarantee that the annotated implementation for this interface is instantiated automatically.

How can we simulate the similar logic of Spring now in ABAP Summer?

(1) Add the annotation @Inject to attribute mo_switchable, which tells ABAP summer “hey, I would like this attribute to be automatically injected with proper implementation in the runtime”.
Since I have no other way to add metadata in class attribute in ABAP – there is no first class annotation supported in ABAP – I have to use description field for simulation.

(2) And below is my consumer code, no more manual instance initialization and manual setter call. Very clean, isn’t it?

data(summer) = zcl_summer=>get_instance( ).
data(lo_switch) = cast zcl_switch( summer->get_bean( EXPORTING iv_bean_name = 'ZCL_SWITCH' ) ).

lo_switch->push( ).
lo_switch->push( ).

Let’s make comparison. By using ABAP summer, consumer can simply get switch instance from container by passing bean technical name ( here again, I use Spring terminology “bean” to name those ABAP classes which owns an injected member attribute with @Inject ). This is exactly the way a Java developer doing daily work using Java Spring:

How does ABAP summer work?

There are lots of books written to illustrate the design of Java Spring, I read one of them listed below, and wrote this ABAP summer based on my understanding.

I draw a diagram below to explain the core method init of ABAP summer:

Last by not least, when you try this demo, after you copy the source code of ZCL_SWITCH to your system and activate it, NEVER forget to add this annotation in description field manually, as in ABAP, the attribute description is not stored in source code but in DB table.

More thought on ABAP annotation

The annotation in Java is a form of metadata which could be defined by application developer and are available in the runtime by Java reflection. It is a built-in language feature supported by JVM.

In ABAP there is no such first-class annotation supported. In CDS view, there are some grammar which have annotation-like style. You can append lots of annotation defined in SAP help to a CDS view.

However those annotation are not first-class annotation supported by ABAP language itself as well. It is just CDS view framework which parses the source code of these annotation and react accordingly. For details please see these two blogs of mine:

(1) My CDS view self study tutorial – Part 3 how is view source in Eclipse converted to ABAP view in the backend
(2) My CDS view self study tutorial – Part 4 how does annotation @OData.publish work

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

展开阅读全文

Git 实用技巧

11-24
这几年越来越多的开发团队使用了Git,掌握Git的使用已经越来越重要,已经是一个开发者必备的一项技能;但很多人在刚开始学习Git的时候会遇到很多疑问,比如之前使用过SVN的开发者想不通Git提交代码为什么需要先commit然后再去push,而不是一条命令一次性搞定; 更多的开发者对Git已经入门,不过在遇到一些代码冲突、需要恢复Git代码时候就不知所措,这个时候哪些对 Git掌握得比较好的少数人,就像团队中的神一样,在队友遇到 Git 相关的问题的时候用各种流利的操作来帮助队友于水火。 我去年刚加入新团队,发现一些同事对Git的常规操作没太大问题,但对Git的理解还是比较生疏,比如说分支和分支之间的关联关系、合并代码时候的冲突解决、提交代码前未拉取新代码导致冲突问题的处理等,我在协助处理这些问题的时候也记录各种问题的解决办法,希望整理后通过教程帮助到更多对Git操作进阶的开发者。 本期教程学习方法分为“掌握基础——稳步进阶——熟悉协作”三个层次。从掌握基础的 Git的推送和拉取开始,以案例进行演示,分析每一个步骤的操作方式和原理,从理解Git 工具的操作到学会代码存储结构、演示不同场景下Git遇到问题的不同处理方案。循序渐进让同学们掌握Git工具在团队协作中的整体协作流程。 在教程中会通过大量案例进行分析,案例会模拟在工作中遇到的问题,从最基础的代码提交和拉取、代码冲突解决、代码仓库的数据维护、Git服务端搭建等。为了让同学们容易理解,对Git简单易懂,文章中详细记录了详细的操作步骤,提供大量演示截图和解析。在教程的最后部分,会从提升团队整体效率的角度对Git工具进行讲解,包括规范操作、Gitlab的搭建、钩子事件的应用等。 为了让同学们可以利用碎片化时间来灵活学习,在教程文章中大程度降低了上下文的依赖,让大家可以在工作之余进行学习与实战,并同时掌握里面涉及的Git不常见操作的相关知识,理解Git工具在工作遇到的问题解决思路和方法,相信一定会对大家的前端技能进阶大有帮助。
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值