SpringAOP在江西省财政综合业务系统的应用方案

一、SpringAOP应用简介

面向方面编程 (AOP) 提供从另一个角度来考虑程序结构以完善面向对象编程(OOP)。面向对象将应用程序分解成 各个层次的对象,而AOP将程序分解成各个方面 或者说 关注点 。这使得可以模块化诸如事务管理等这些横切多个对象的关注点。(这些关注点术语称作 横切关注点。)

在江西省财政综合业务系统中,利用SpringAOP面向横切点的实现方式解决事务管理、方法级权限认证、操作日志跟踪、数据缓存、性能监控等功能。在不干预业务的基础上,应用事务管理提高系统的事务安全性,应用操作日志跟踪、方法级权限认证提高系统的安全级别,应用数据缓存、性能监控提高系统运行效率。

二、SpringAOP应用案例

1. 方法级权限控制

权限控制指控制用户对业务的操作权限。在财政综合业务系统中,对操作权限的控制粒度一般是方法级的,比如控制某用户允许增加某业务数据但不允许删除该数据。

传统的实现

public someFunciton() { //权限判断

            User user = context.getUser();

            if (user.canExecuteThisFunction()) {

                              // do the business method

                              // ...

            } else {

                throw new PermissionDeniedException();

            }

}

这种做法能够将权限的粒度控制到具体的业务方法,因此它的控制能力应该是强大的。可以看到,权限判断部分对于每个方法几乎是独立的。

这种在具体功能前加入权限操作检验的实现方式有很多缺点:

每个功能类都需要相应的权限检验代码,将程序功能和权限检验混淆在一起,存在紧密的耦合性,扩展修改难度大。  

以代理模式为每个功能类实现一个相应的代理类,虽然解耦了程序功能和权限检验,但是,从某个角色的权限检验这个切面考虑,涉及具体Proxy类太多,扩展修改难度大。

AOP下的权限控制实现

有了AOP,新的业务方法可以这样写:

public someFunciton() {
 // do the business method
 // ...
}

没有了额外的权限操作,这个业务方法看起来那么清晰自然。

将对权限的操作作为一个Advice,并将Advisor关注到所有的业务方法(可能有某一个特定package),然后,剩下的事情就由RBAC以及AOP来完成了。通过这样的分离,纵向的一个业务方法被分割为一个更为自然的业务方法和一个关注点。实现如下:

类图:

时序图:

部分实现代码:

public Object invoke(MethodInvocation invocation) throws Throwable {

     //权限判断

  if(!authenticator.check(user,uri)){

             response.sendError(403);

    } else{

            Object returnObject = invocation.proceed();

            return returnObject;

         }

由此,我们可以了解到,应用AOP控制方法级的权限,对编程人员是透明的,编程人员可以毫不关心权限控制机制。相应地业务处理类和权限控制相互分离开来,降低了代码之间的耦合性。

2. 操作日志跟踪

操作日志是反映用户对系统功能操作的跟踪记录。通过查询操作日志可以反映哪个用户在什么时间用哪台电脑对什么业务数据执行了什么操作。这些完整的操作信息可以防止用户在维护或操作业务数据时发生操作错误以至于对自己的操作不承认的抵赖。

传统的实现

public someFunciton() {
 // do the business method
 // ...

TrackOperatorLoger.log(info);//记录操作信息

}

   对于这种实现方式有个很大的问题就是在每个操作的代码当中都要调用记录操作信息的方法,很大程度上增加了业务代码与记录操作信息的代码之间的耦合性,加大了以后对代码的维护量。试想,如果需要修改记录操作信息的接口,那应用到此接口的所有业务代码都需要变更,这种现象是谁也不愿意发生的。

应用AOP的实现

    将记录操作信息的工作交给一个AfterAdviceAOP对系统执行的每一个方法进行拦截,拦截后获取方法相关的参数和用户相关的信息,再调用TrackOperatorLoger记录这些信息。

类图:

 

 

时序图:

 

部分实现代码:

public class TrackOperatorLogAdvice implements AfterReturningAdvice {  

public void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable {

       //获取用户信息

       //获取方法参数信息(业务对象等)

       TackOperatorLoger.inserLog(loginfo);

}

}

3. 数据缓存

在财政综合业务系统当中,用户每天的业务量及所操作的数据量很大,因此如何提供系统的运行性能是提高软件质量的关键因素。提高软件性能主要是减少系统访问数据库的次数和优化出现瓶颈的算法等。采用缓存技术,把系统不经常发生变更的数据或在同一个线程中调用多次的数据缓存起来,较少系统查询数据库的次数,减轻查询数据库的负担,降低其在访问数据库所耗费的时间,提供系统运行性能。

如果数据满足以下条件,可以考虑将其纳入缓存管理。

1、数据不会被第三方应用修改;

2、数据大小在可接受的范围之内;

3、数据更新频率较低;

4、同一数据可能会被系统频繁引用;

5、非关键数据;

我们都知道Hibernate可以用ehcache来作为Second Level Cache。其对Query缓存策略的过程如下:

1) Hibernate首先根据查询条件组成一个Query KeyQuery Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。

2) Hibernate根据这个Query KeyQuery缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。

3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。

Hibernate的缓存主要是针对POJO的缓存,而且缓存的读取在Hibernate中是写死,实际运用中感觉很不灵活。现在我们利用AOP技术,在不改变任何业务代码的前提下,采用类似于HibernateQuery缓存机制对方法级结果进行缓存。

类图:

 

 

时序图:

部分实现代码:

public class MethodCacheInterceptor implements MethodInterceptor,

        InitializingBean {

/**

     * 主方法 如果某方法可被缓存就缓存其结果 方法结果必须是可序列化的(serializable)

     */

    public Object invoke(MethodInvocation invocation) throws Throwable {

        String targetName = invocation.getThis().getClass().getName();

        String methodName = invocation.getMethod().getName();

        Object[] arguments = invocation.getArguments();

        Object result;

        String cacheKey = getCacheKey(targetName, methodName, arguments);//组合缓存KEY

        Element element = cache.get(cacheKey);

        if (element == null) {

            result = invocation.proceed();

            element = new Element(cacheKey, new TempObject(result)); // cache method result

            cache.put(element);

        }

        return ((TempObject)element.getValue()).getObject();

    }

}

4. 性能监控

用于监控方法执行的时间,有效的检查系统的运行瓶颈。在方法调用之前记录开始时间,在方法调用之后记录结束时间,并计算总运行所花的时间。

类图:

 

时序图:

 

 

5. 事务管理

在财政综合业务系统中存在同时在一个或多个数据库中访问或存储信息。因为这些信息对业务操作是至关重要的,他们必须准确,实时,可靠。如果允许多个程序同时(simultaneously)更新相同的信息,数据的完整性(integrity)将会丧失;同时,当处理一个事务性的业务流程时只是部分的更新了受影响的数据时系统失败了,这也丧失。通过阻止这两种情况的发生,软件事务确保了数据的完整性。事务管理多种程序对数据的并发(concurrent)访问。当遇到系统失败事件时,事务确保在系统恢复后数据仍然是一致的。

财政综合业务系统利用Spring AOP进行对系统的事务管理,很大程度上减轻了开发人员对事务的管理,不要写代码来出来事务提交、事务异常、事务回顾等。因此,开发人员把主要经理花在如下编写业务逻辑代码就可以了,事务管理对他们是透明的。

类图:

时序图:

相关配置:

<!-- 事务代理模板Transaction template for Managers, from:     http://blog.exis.com/colin/archives/ 2004/07/31 /concise-transaction-definitions-spring-11/ -->

    <bean id="txProxyTemplate" abstract="true"

        class="org.springframework.aop.framework.ProxyFactoryBean">

        <property name="optimize">

        <value>true</value>

        </property>

        <property name="proxyTargetClass"><value>true</value></property>

        <property name="interceptorNames">

        <list>

             <value>daoMethodCacheInterceptor</value>

             <value>TransactionInterceptor</value>

        </list>

        </property>

    </bean>

    <!--事务拦截机 -->

    <bean id="TransactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">

     <property name="transactionManager"><ref bean="transactionManager"/></property>

        <property name="transactionAttributes">

            <props>

                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>

                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>

                <prop key="*">PROPAGATION_REQUIRED</prop>

            </props>

        </property>

    </bean>

 

 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值