`
ldd600
  • 浏览: 103597 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
47bb354f-8b5f-3ea6-a206-c7ead38c741c
Hyperic插件开发不完...
浏览量:11257
社区版块
存档分类
最新评论

侦听和处理用户对业务对象改动的简易框架(下)

阅读更多

上篇地址:http://ldd600.iteye.com/blog/534039

从“侦听和处理用户对业务对象改动的简易框架(上)”中知道整个Framework的原理还是相当简单的,稍微值得注意的可能是下面几个方面。

Listener如何获取被改动的对象

TopLink会把所有改动过的对象都会被放在UnitOfWorkChangeSet中,因为在UnitOfWork提交的时候它需要将UnitOfWorkChangeSet中记下的改动提交到数据库。然后mergesession cache。所以所有改动从UnitOfWork中都是可以拿到的。

public class ActionLogPassiveAsyncListener extends AbstractActionLogAsyncListener {

    private ValueDistiller distiller;

 

    public void preCommitUnitOfWork(SessionEvent sessionevent) {

        log.debug("preCommitUnitOfWork begin.");

        UnitOfWork unitOfWork = (UnitOfWork) sessionevent.getSession();

 

        if (null == unitOfWork.getUnitOfWorkChangeSet()) {

         unitOfWork.setUnitOfWorkChangeSet((oracle.toplink.internal.sessions.UnitOfWorkChangeSet) unitOfWork

                    .getCurrentChanges());

        }

        UnitOfWorkChangeSet ucs = unitOfWork.getUnitOfWorkChangeSet();

        if (ucs != null && ucs.getAllChangeSets() != null) {

            Set finishedObjects = new HashSet();

            Map<Class<?>, List<ChangedPair>> changedPairs = new HashMap<Class<?>, List<ChangedPair>>();

 

            for (Enumeration objectChangeSetEnum = ucs.getAllChangeSets().keys(); objectChangeSetEnum

                    .hasMoreElements();) {

                ObjectChangeSet objectChangeSet = (ObjectChangeSet) objectChangeSetEnum.nextElement();

                if (objectChangeSet == null) {

                    continue;

                }

                Object clone = objectChangeSet.getUnitOfWorkClone();

                if (!finishedObjects.contains(clone)) {

                    for (Class focusClass : this.focusClasses) {

                        if ((includeSubclass ? focusClass.isAssignableFrom(clone.getClass())

                                : clone.getClass() == focusClass)

                                && (filter == null || (filter != null && !filter.isFiltered(clone, unitOfWork)))) {

                            finishedObjects.add(clone);

                            if (objectChangeSet.hasChanges()) {

                                List<ChangedPair> changedPairList = changedPairs.get(focusClass);

                                if (null == changedPairList) {

                                    changedPairList = new ArrayList<ChangedPair>();

                                    changedPairs.put(focusClass, changedPairList);

                                }

                                Object originalObject = this.distiller.getOriginObject(clone);

 

                                changedPairList.add(new ChangedPair(originalObject, clone));

 

                            }

 

                        }

                    }

                }

            }

            if (!changedPairs.isEmpty()) {

                try {

                    ChangedPairMap changedPairMap = this.assembleChangedPairMap(unitOfWork, changedPairs);

                    this.changedPairCache.set(changedPairMap);

                } catch (ActionLogException e) {

                    if (shouldBreakIfException) {

                        throw new ActionLogRuntimeException(e);

                    }

                }

            }

            log.debug("preCommitUnitOfWork end.");

        }

    }

}

 

异步状态下,ActionRecord要在Application事务提交之后生成

同步状态下,ActionRecord的生成可以Join Applicationtransaction,这样他们会一起成功或者失败。但是异步情况下,就会是不同的事务,两个事务之间的关系可能是有先后顺序或者互不相干。互不相干是不可能的,从业务意义上讲只有Application的改动确实生效之后ActionRecord才能生成,但是将ActionRecord放在Application事务提交成功之后生成或者提交,也会面临一个问题,就是application成功提交了,但ActionRecord的生成可能会失败。但要知道ActionRecord失败的几率远比Application提交失败的几率要小得多,application常常会因为乐观锁的问题而提交失败,但ActionRecord只可能因为DB Shutdown而丢失数据。失败后会做详细的备份,以便做恢复。那如何感知application事务是提交成功还是失败了呢?TopLinkSessionEventListener有四个有用的回调方法:PreCommitPostCommitPostRollbackPostRelease,用户事务提交的时候在提交之前会调用PreCommit方法,这时我们还可以从UnitOfWork中获取新老对象,我们会把老对象深clone一份出来,将他们存放在ThreadLocal中,而在PostCommit回调的实现中,我们会从ThreadLocal中取出新老对象完成ActionRecord的生成,而PostRollback就可以什么都不干了。但不管是提交成功还是提交失败Rlease方法都会被调用,UnitOfWork需要release,这里我们就会去清空ThreadLocal,以便内存即时的垃圾回收。这样说来即使是主动调用ActionAsyncService也会注册一个Listener,不同的是这个Listener不需要从UnitOfWork检测变化。

public class AbstractActionAsyncListener extends AbstractActionListener {

    protected ThreadLocal<ChangedPairMap> changedPairCache = new ThreadLocal<ChangedPairMap>();

   

    public void postCommitUnitOfWork(SessionEvent arg0) {

        ChangedPairMap changedPairMap = this.changedPairCache.get();

        if (changedPairMap != null) {

            if (!changedPairMap.isEmpty()) {

//异步生成ActionRecord

            }

        }

    }

 

    public void postReleaseUnitOfWork(SessionEvent arg0) {

        if (this.changedPairCache.get() != null) {

            this.clearResource();

        }

    }

 

    private void clearResource() {

        this.changedPairCache.set(null);

}

}

 

 

public class ActionActiveAsyncListener extends AbstractActionAsyncListener {

    private Map<Class<?>, List<ChangedPair>> changedPairs;

 

    public void preCommitUnitOfWork(SessionEvent sessionEvent) {

        UnitOfWork unitOfWork = (UnitOfWork) sessionEvent.getSession();

        try {

            ChangedPairMap changedPairMap = this.assembleChangedPairMap(unitOfWork, this.changedPairs);

            this.changedPairCache.set(changedPairMap);

        } catch (ActionLogException e) {

            log.error("Assemble ChangePairMap fails! ChangedPairs: " + changedPairs.toString(), e);

            if (shouldBreakIfException) {

                throw new ActionRuntimeException(e);

            }

        }

    }

}

 

 

ObjectCloner

如果对象树的结构很庞大,深copy的性能代价不得不考虑。BeanUtils进行深copy的性能很差。5000个对象花了我20s。首先要说的是其实不需要所有对象引用都需要深copy,只有那些用户对关注的对象属性才需要深copyclone的步骤大概如下:

l           对根对象进行浅copy

l           对用户关心的对象属性迭代的进行深copy

l           如果关心的对象属性是Collection,浅copy Collection中的每个对象并深copy对象中用户关注的对象属性

l           其实那些domain class,早在做ORM的时就确定下来了,所以所有domain对象反射metadata都可以事先确定,存在内存中,这样会大大提高性能,其实toplink也会把这些反射结构解析出来后缓存在内存中,直接利用toplinkclone逻辑就可以了。1000个对象深clone一把大约是120ms

 

 

 

 

分享到:
评论

相关推荐

    时间类型侦听函数

    在编程和软件开发中,时间类型的侦听函数是一种重要的技术,它主要用于监控和处理与时间相关的事件或行为。这类函数通常被用在实时系统、游戏引擎、数据流处理或者任何需要定时触发某些操作的场景。在本文中,我们将...

    行业分类-设备装置-无现金呼叫业务预订的侦听.zip

    借助大数据处理技术和流计算框架(如Apache Flink或Spark Streaming),企业可以实时处理大量并发的交易数据,快速识别出异常交易、热门服务、用户需求变化等关键信息。这样的实时响应能力对于提升用户体验、预防...

    jsp中servlet过滤器和侦听器

    过滤器在JSP中起到中介的作用,它们可以拦截HTTP请求和响应,对数据进行处理或修改,然后再将其传递给下一个组件。过滤器的工作原理是基于过滤链的概念,当请求到达时,会按照配置的顺序依次调用过滤器。 1. **...

    matlab开发-单个事件侦听器和Matlabui的SimulinksignalView

    在MATLAB开发中,事件侦听器是一种强大的工具,它允许程序对特定事件做出响应,例如数据更改或用户交互。本教程重点介绍了如何利用单个事件侦听器以及MATLAB UI(用户界面)中的Simulink Signal Viewer来增强模型的...

    网络侦听以及反侦听的原理和实现

    首先简要介绍了网络侦听的原理及其潜在的安全隐患,讲述了侦听技术在Unix和Windows环 境下的几种实现技术;说明了如何检测侦听器的存在;最后提出了一种切实可行的、用来消除网络侦听 的方案。

    多线程 TCIIP 侦听器

    2. 创建TCP侦听器类,包含启动和停止侦听的方法以及处理连接的回调函数: ```vbnet Public Class TCPListener Private tcpListener As TcpListener Private serverPort As Integer Public Sub New(port As ...

    VS2008数据侦听

    这个示例可能涵盖了连接数据库、创建`SqlCommand`和`SqlDependency`对象、设置事件处理程序以及处理数据变更事件的完整流程。 需要注意的是,`SqlDependency`需要SQL Server Agent服务运行,并且需要在服务器端启用...

    Servlet上下文和侦听器

    Servlet上下文和侦听器

    AS2中的侦听器

    事件侦听器允许我们响应特定的事件,如用户点击、对象加载等,而无需不断检查这些事件是否已经发生,这与线性编程模式形成了鲜明对比。 线性编程,也称为顺序编程,是一种按照预定顺序执行指令的编程方式。在上述...

    多线程 TCP/IP 侦听器

    在IT领域,多线程TCP/IP侦听器是一种常见的网络通信工具,用于接收并处理来自多个客户端的并发连接。在VB.NET环境下,开发者可以利用System.Net.Sockets命名空间中的TcpListener类来实现这样的功能。本节将深入探讨...

    串口侦听器

    &lt;br&gt;SerialTrace的界面美观精致,侦听、显示、仿真功能简捷易用,符合用户的操作和心理习惯。软件针对不同专业用户的关注内容,对信息进行分类,提供了 具有信息染色功能的多视图窗口供显示、分析使用,并提供...

    8种加密狗侦听工具8种加密狗侦听工具

    8种加密狗侦听工具8种加密狗侦听工具8种加密狗侦听工具

    windowsAPI(waveform)实现侦听功能

    在Windows API中,"waveform"通常指的是Waveform Audio ...综上所述,利用Windows API实现话筒侦听涉及多个步骤,需要对音频处理和系统编程有深入的理解。通过学习和实践,开发者可以创建出高效、稳定的音频输入应用。

    arp 侦听工具,局域网工具

    描述中提到的“局域网侦听工具.C:\TDDOWNLOAD\Spynet.rar”,这可能是一个名为“Spynet”的特定 ARP 侦听工具,它是一个RAR压缩文件,位于C盘的TDDOWNLOAD文件夹下。RAR是一种常见的文件压缩格式,用于打包和存储多...

    PHP-PayPal-IPN, 用于侦听和处理即时付款通知( IPN )的PHP 5类.zip

    PHP-PayPal-IPN, 用于侦听和处理即时付款通知( IPN )的PHP 5类 PHP-PayPal-IPN一个用于 PHP 5的贝宝即时付款通知( IPN ) 类。在 PHP IPN脚本中使用 IpnListener 类处理发布数据。回发到贝宝,以及从PayPal解析响应。...

    服务器端侦听软件

    用于在服务器端侦听上传到服务器的数据。该工具是用C#编写的 ,使用的时候只要侦听端口号,以及要创建相应的数据库表。

    第六节 事件侦听.docx

    事件侦听是ActionScript(特别是Flash和Flex)中一个重要的交互处理机制。它允许我们对用户的行为或者对象的状态变化做出响应,例如,当用户点击一个按钮时触发特定的操作。 首先,`addEventListener`方法用于添加...

    Dojo基础2事件侦听器

    Dojo事件对象包含了丰富的属性,例如`bubbles`(事件是否冒泡)、`currentTarget`(当前处理事件的节点)和`keyCode`(键盘事件的键码)等,这些都极大地简化了跨浏览器的事件处理。 键码的标准化是Dojo的一大亮点...

    JMS侦听器pdf

    通过对JMS侦听器的概念、工作原理及配置步骤的详细介绍,我们可以看到,正确配置和使用JMS侦听器对于实现高效可靠的消息传递至关重要。通过遵循上述步骤,开发者可以轻松地在WebSphere环境下构建出具有良好可维护性...

    网络侦听以及反侦听原理

    ### 网络侦听及反侦听原理详解 #### 一、引言 随着互联网技术的飞速发展,网络安全成为了一个不容忽视的问题。网络侦听作为一种常见的安全威胁手段,通过对网络流量的非法监听,窃取敏感信息。本文旨在探讨网络侦听...

Global site tag (gtag.js) - Google Analytics