【13】SAP ABAP性能优化 - 共享对象 (Shared Objects)

1. 背景

“共享对象”是NetWeaver 6.40以上版本ABAP编程中的一个技术,在"共享对象"概念出来之前,在ABAP中可以通过EXPORT和IMPORT这样的关键字去访问服务器上的共享内存,实现不同进程中的数据交互。有关这方面的概念,我在之前的博客《SAP ABAP性能优化 - 内存管理 (ABAP Memory vs. SAP Memory》中已有介绍。

今天,让我们一起看下“共享对象”的概念和实现。

2. 基础概念

2.1 共享内存(Shared Memory)

共享内存是应用服务器上的一个内存区域,该服务器的所有ABAP程序都可以访问该内存区域。在引入共享对象之前,ABAP程序可以使用EXPORT和IMPORT语句访问该内存区域,但这种方式是不支持类的实例或匿名数据对象的实例这种“面向对象”的概念的,大白话说就是,你不可能从一个进程EXPORT一个类的实例,然后IMPORT到另个一个进程。

随着6.40版本中共享对象的引入,共享内存得到了扩展,包括可以存储共享对象的共享对象内存。共享对象内存的大小由abap/shared_objects_size_MB配置文件参数决定。这也就意味着,我们可以实现类的实例在不同进程中的共享。

2.2 共享对象(Shared Object)

共享对象也即是共享内存中的对象,用于存储类的实例和匿名数据对象。

2.3 启动共享内存的类(Shared Memory-Enabled Classes)

如果想让一个类可以被存放在共享内存中,那么在定义这类时,要声明其属性是“Shared Memory-Enabled”。

 关键字是SHARED MEMORY ENABLED。 

CLASS zcl_gg_shma_root DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC
  SHARED MEMORY ENABLED.

  PUBLIC SECTION.

ENDCLASS.

2.4 共享域和域的实例(Area and Area Instance)

除了共享类,这里还有一个“共享域”的概念,可以把它理解成一个“控制层”,可以控制共享对象的一些特定的属性,例如“创建方式”,“生命周期”等等。

可以使用事务代码SHMA来创建和管理区域及其属性, 可以使用SHMM来监测共享域和共享实例的状态。

域和共享对象的root类链接,共享对象的root类可以包含单独的数据和开启用共享内存的类的其他实例,或对匿名数据对象的引用。

2.5 域类和域的句柄(Area and Area Handles)

当在事务SHMA中定义一个域时,将生成一个具有相同名称的全局最终区域类,作为CL_SHM_AREA的子类。类CL_SHM_AREA本身是CL_ABAP_MEMORY_AREA的直接子类。

在ABAP程序中,使用生成的域类的方法访问域。

这个同名的全局类中的静态方法可以将ABAP程序(或其内部会话)绑定到共享内存中的域实例(附加方法)。

绑定将创建一个域类的实例作为区域句柄,并同时创建一个锁。

ABAP程序可以使用域句柄访问绑定区域实例版本,从而访问存储在那里的共享对象。区域句柄还包含用于删除连接或锁的方法(分离方法)。

3. 示例

下面,让我们用一个最简单的例子来看一下,共享对象的实现。

目标,通过共享对象的方式,将一个内表的数据,有一个session传递到另一个session。

3.1 定义共享对象类

定义全局类ZCL_GG_SHMA_ROOT并声明其开启了共享内存。

定义要传递的数据mt_sflight为此类的属性,并为此属性添加set和get方法。与此同时,实现接口if_shm_build_instance,目的是可以实现此共享类可以作为域的构建函数类。也就是说,可以实现共享域的自动构建。当启动自动构建共享域时,会隐式开启一个内部的ABAP session来调用root类中的这个if_shm_build_instance~build方法。

这个例子中,为了简化共享域的构建步骤,我们使用自动构建的方式。

CLASS zcl_gg_shma_root DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC
  SHARED MEMORY ENABLED.

  PUBLIC SECTION.
    INTERFACES if_shm_build_instance.

    METHODS get_data
      EXPORTING et_sflight TYPE flighttab.

    METHODS set_data
      IMPORTING it_sflight TYPE flighttab.

  PRIVATE SECTION.
    DATA mt_sflight TYPE flighttab.
ENDCLASS.



CLASS zcl_gg_shma_root IMPLEMENTATION.
  METHOD get_data.
    et_sflight = mt_sflight.
  ENDMETHOD.


  METHOD set_data.
    mt_sflight = it_sflight.
  ENDMETHOD.


  METHOD if_shm_build_instance~build.
    DATA lo_root TYPE REF TO zcl_gg_shma_root.

    TRY.
        " Request a Write Lock
        DATA(lo_area_handle) = zcl_gg_shma_area=>attach_for_write( ).
      CATCH cx_shm_exclusive_lock_active
            cx_shm_version_limit_exceeded
            cx_shm_change_lock_active
            cx_shm_parameter_error
            cx_shm_pending_lock_removed.
        " handle exception
    ENDTRY.

    CREATE OBJECT lo_root AREA HANDLE lo_area_handle.

    " Initialize data in root class
    lo_root->set_data( VALUE #( ) ).

    lo_area_handle->set_root( lo_root ).

    " Release Change Lock and Flag for COMMIT
    lo_area_handle->detach_commit( ).
  ENDMETHOD.
ENDCLASS.

3.2 定义共享对象域

使用事务代码SHMA创建共享域ZCL_GG_SHMA_AREA,共享域创建时,会自动创建一个同名的全局类,用于控制共享域和共享对象。

指定相关共享域的属性,此处声明共享类ZCL_GG_SHMA_ROOT为共享域ZCL_GG_SHMA_AREA的root class完成共享类与共享域的链接。

同时声明,这个共享域可以通过ZCL_GG_SHMA_ROOT的Build方法自动构建,自动构建的场景是“Autostart if read request and invalidated”,就是只要有读此共享域的请求时,或是共享域失效时,都会自动重新构建此共享域。

 我们可以看一下,自动生成共享域全局类ZCL_GG_SHMA_AREA中的一些方法,有三大类:

  • 构建共享域,设定获取共享对象
  • 请求释放共享锁
  • 释放共享域

我们在程序中,可以通过这些方法,来控制使用的共享域。

3.3 数据写入

编写程序A,用于向共享对象中写入数据。

*&---------------------------------------------------------------------*
*& Report ZGG_SHMA_SESSION_A
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zgg_shma_session_a.

TRY.
    " Direct Call of Area Constructor
    zcl_gg_shma_area=>build( ).
  CATCH cx_root.
    EXIT.
ENDTRY.

TRY.
    " Request a Change Lock
    DATA(lo_area_handle) = zcl_gg_shma_area=>attach_for_update( ).
  CATCH cx_root.
    EXIT.
ENDTRY.

DATA(lo_root) = CAST zcl_gg_shma_root( lo_area_handle->get_root( ) ).


" set data into shared memory object
SELECT * FROM sflight INTO TABLE @DATA(lt_sflight).
lo_root->set_data( CORRESPONDING #( lt_sflight ) ).

lo_area_handle->set_root( lo_root ).
lo_area_handle->detach_commit( ).

WRITE 'SFLGHT data has been added to shared memory object'.

3.4 数据读取

编写程序B,用于从共享对象中获取数据。

*&---------------------------------------------------------------------*
*& Report ZGG_SHMA_SESSION_B
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zgg_shma_session_b.

TRY.
    " request a read lock
    DATA(lo_area_handle) = zcl_gg_shma_area=>attach_for_read( ).
  CATCH cx_root INTO DATA(lx_exc).
    EXIT.
ENDTRY.

" get data from shared memory object
DATA(lo_root) = CAST zcl_gg_shma_root( lo_area_handle->get_root( ) ).
lo_root->get_data( IMPORTING et_sflight = DATA(lt_sflight) ).

" remove shared lock
lo_area_handle->detach( ).

cl_demo_output=>display_data( lt_sflight ).

3.5 测试

运行程序A,然后运行程序B,可以发现,在程序B执行的dialog session仍然可以读到程序A中写入共享域中共享对象的数据。

程序A运行结果:

程序B运行结果:

4. 扩展

上面的例子中,对于理解共享内存的概念很有帮助,但其实也是存在一定的问题的,例如例子中,对于写入共享对象的数据其实是一直存在的,如果再次启动session B,仍然是可以读取到的。

如果完成数据传递后,我们的目的就达到了,那么应当在session B访问到数据后,销毁共享内存中的数据,否则是对shared memory的一种浪费。

针对上面的例子,我们可以在SHMM中看到,及时运行完程序B后,仍然可以监控到这个共享域以及其中的数据。

因而,在实际开发中,我们要考虑放入共享内存中数据的生命周期,对共享对象的使用有着更加规范的方式。

4.1 手动启动域

因为,我们也可以选择不自动启动域的创建,仅仅手动启动域,配置参数如下:

不配置自动创建域,就不需要在root class中实现这个if_shm_build_instance~build方法了。

CLASS zcl_gg_shma_root_manual DEFINITION PUBLIC FINAL CREATE PUBLIC
  SHARED MEMORY ENABLED.

  PUBLIC SECTION.
    METHODS get_data
      EXPORTING et_sflight TYPE flighttab.

    METHODS set_data
      IMPORTING it_sflight TYPE flighttab.

  PRIVATE SECTION.
    DATA mt_sflight TYPE flighttab.
ENDCLASS.



CLASS zcl_gg_shma_root_manual IMPLEMENTATION.
  METHOD get_data.
    et_sflight = mt_sflight.
  ENDMETHOD.


  METHOD set_data.
    mt_sflight = it_sflight.
  ENDMETHOD.
ENDCLASS.

在进程C中,手动启动共享域,并向共享对象中写入数据。

REPORT zgg_shma_session_c.

DATA lo_root_manual TYPE REF TO zcl_gg_shma_root_manual.

TRY.
    " create a new area instance (it could be specified with a unique name) and get handles
    DATA(lo_area_handle) = zcl_gg_shma_area_manual=>attach_for_write( ).

    " Request a Change Lock for this area using an existing instance
    " lo_area_handle = zcl_gg_shma_area_manual=>attach_for_update( ).

    CREATE OBJECT lo_root_manual AREA HANDLE lo_area_handle.

    " set data into shared memory object
    SELECT * FROM sflight INTO TABLE @DATA(lt_sflight).
    lo_root_manual->set_data( CORRESPONDING #( lt_sflight ) ).

    " link shared object to area handle
    lo_area_handle->set_root( lo_root_manual ).

    " release change lock
    lo_area_handle->detach_commit( ).

    WRITE 'SFLGHT data has been added to shared memory object'.
  CATCH cx_root INTO DATA(lx_exc).
    cl_fins_cfin_msg=>output_exception_msg( lx_exc ).
    EXIT.
ENDTRY.

要区分attach_for_write和attach_for_update的不同,这两个方法都可以返回一个共享域实例的句柄。通常而言,使用attach_for_write去创建一个新的共享域的实例(通过SHMM可观测到新实例的创建),而用attach_for_update去获取一个已经创建域的实例的句柄,在此基础上更新其所存储的共享对象的内容。

因而,当需要有多个共享实例时,要指定其instance_name用于区分。当然,如果仅需要一个共享实例,则可以默认使用default的name。

4.2 手动销毁域

在进程D中,读取共享域,并在读取结束后,销毁域的实例。

REPORT zgg_shma_session_d.

TRY.
    " request a read lock
    DATA(lo_area_handle) = zcl_gg_shma_area_manual=>attach_for_read( ).

    " get data from shared memory object
    DATA(lo_root_manual) = CAST zcl_gg_shma_root_manual( lo_area_handle->get_root( ) ).
    lo_root_manual->get_data( IMPORTING et_sflight = DATA(lt_sflight) ).

    " remove shared lock
    lo_area_handle->detach( ).

    " Deactivate the instance, else we create waste instances in shared memory
    zcl_gg_shma_area_manual=>invalidate_instance( ).

  CATCH cx_root INTO DATA(lx_exc).
    cl_fins_cfin_msg=>output_exception_msg( lx_exc ).
    EXIT.
ENDTRY.

cl_demo_output=>display_data( lt_sflight ).

4.3 共享类的扩展

在上面的例子中,我们仅仅展示了一个共享对象root,在实际使用中,如果需要多个共享对象,那么则可以将这些共享对象申明为root的属性,形成层级关系。

通过root来链接共享域,来统一管理,在此不再赘述,大家可以参考系统中已有的共享域。

5. 小结

本文介绍了ABAP编程中“共享对象”的概念,我们除了传统的EXPORT和IMPORT,还可以通过“共享对象”实现在不同ABAP进程间数据的传递。通过事物代码SHMA创建共享域,通过事物代码SHMM监控共享域。

6. 参考资料

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《从实例学SAP ABAP编程1-10章》是一本SAP ABAP编程的经典入门教材。本书从简单的SAP ABAP编程入手,通过多个实例向读者展示了SAP ABAP编程的核心概念和语法。 在第一章中,本书通过一个简单的例子介绍了SAP ABAP编程的基础知识,讲解了ABAP编辑器、ABAP数据字典和ABAP Workbench等重要工具的用法。 在第二章中,本书通过一个简单的例子向读者介绍了ABAP表格的创建和维护,并讲解了一些与表格相关的SAP ABAP编程的语法和概念。 在第三章中,本书介绍了SAP ABAP编程中的面向对象编程,通过几个例子向读者展示了如何使用类、对象和继承等概念进行SAP ABAP编程。 在第四章中,本书介绍了SAP ABAP编程中的函数模块,向读者讲解了如何创建和调用函数模块,以及如何在SAP系统中使用函数模块。 在第五章中,本书介绍了SAP ABAP编程中的异常处理,向读者讲解了如何使用TRY/CATCH语句处理SAP系统中的异常情况。 在第六章中,本书介绍了SAP ABAP编程中的Web服务,向读者讲解了如何创建和使用SAP系统中的Web服务,以及如何使用HTTP和SOAP协议进行数据通信。 在第七章中,本书介绍了SAP ABAP编程中的ALV报表,向读者讲解了如何创建和维护SAP系统中的ALV报表,以及如何对报表进行数据操作和定制。 在第八章中,本书介绍了SAP ABAP编程中的BADI和Enhancement点,向读者讲解了如何使用BADI和Enhancement点扩展和修改SAP系统中的业务逻辑。 在第九章中,本书介绍了SAP ABAP编程中的Smart Form,向读者讲解了如何使用Smart Form创建和维护SAP系统中的表单。 在第十章中,本书介绍了SAP ABAP编程中的SAP HANA数据库,向读者讲解了如何使用SAP HANA数据库进行高效的数据处理和分析。 通过阅读本书,读者可以快速掌握SAP ABAP编程的核心知识和技能,从而能够独立进行SAP系统的开发和维护工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十年铸器

给作者赏杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值