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

本文来自云栖社区合作伙伴“汪子熙”,了解相关信息可以关注微信公众号"汪子熙"。

相关文章
|
1月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——DeptDaoImpl.java
ssh(Spring+Spring mvc+hibernate)——DeptDaoImpl.java
12 0
|
1月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——BaseDaoImpl.java
ssh(Spring+Spring mvc+hibernate)——BaseDaoImpl.java
12 0
|
1月前
|
Shell
sh(Spring+Spring mvc+hibernate)——IEmpDao.java
sh(Spring+Spring mvc+hibernate)——IEmpDao.java
11 0
|
1月前
|
Shell
sh(Spring+Spring mvc+hibernate)——IDeptDao.java
sh(Spring+Spring mvc+hibernate)——IDeptDao.java
13 0
|
1月前
|
网络安全
ssh(Spring+Spring mvc+hibernate)——Dept.java
ssh(Spring+Spring mvc+hibernate)——Dept.java
12 0
|
6天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
7天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【4月更文挑战第17天】Spring Cloud是Java微服务治理的首选框架,整合了Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心)。通过Eureka实现服务注册与发现,Ribbon提供负载均衡,Hystrix实现熔断保护,Zuul作为API网关,Config Server集中管理配置。理解并运用Spring Cloud进行微服务治理是现代Java开发者的关键技能。
|
8天前
|
安全 Java 数据安全/隐私保护
使用Spring Security进行Java身份验证与授权
【4月更文挑战第16天】Spring Security是Java应用的安全框架,提供认证和授权解决方案。通过添加相关依赖到`pom.xml`,然后配置`SecurityConfig`,如设置用户认证信息和URL访问规则,可以实现应用的安全保护。认证流程包括请求拦截、身份验证、响应生成和访问控制。授权则涉及访问决策管理器,如基于角色的投票。Spring Security为开发者构建安全应用提供了全面且灵活的工具,涵盖OAuth2、CSRF保护等功能。
|
9天前
|
Java 大数据 云计算
Spring框架:Java后台开发的核心
【4月更文挑战第15天】Spring框架在Java后台开发中占据核心位置,因其控制反转(IoC)、面向切面编程(AOP)、事务管理等特性提升效率和质量。Spring提供数据访问集成、RESTful Web服务和WebSocket支持。优势包括高效开发、灵活扩展、强大生态圈和广泛应用。应用于企业级应用、微服务架构及云计算大数据场景。掌握Spring对Java开发者至关重要。
|
12天前
|
Java 应用服务中间件 Maven
使用IDEA搭建SpringMVC环境,Maven导入了依赖,但是运行报错 java.lang.ClassNotFoundException
使用IDEA搭建SpringMVC环境,Maven导入了依赖,但是运行报错 java.lang.ClassNotFoundException
11 1