【Java基础】动态代理实现AOP之控制事务

前言

在学习设计模式的时候,对静态代理和动态代理做过研究,静态代理倒是很好理解,代码也简单。但是动态代理代码相对复杂,基于当时的水平,没看太懂。这次就来解析一下java中的动态代理。

静态代理缺点

静态代理是简单,但是他不灵活,使用的话需要为每个类都创建一个代理类。使用起来很不方便,并且也造成了大量的代码重复,在实际应用中并不广泛。而动态代理的出现正好解决了这些问题。

动态代理解析

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

我们在invoke方法中,就可以做一些其他的操作,比如事务的控制,日志输出等等,从而实现AOP的效果。在这里需要提一下Servlet的Filter,因为它也可以实现AOP的效果,和动态代理不同的是,Filter基于拦截器的原理,在访问某个目标资源之前,会对访问的请求和响应进行拦截,然后在偷偷执行一些操作。这两种方式相比较而言,使用场景不一样,Filter适用于前台JSP,Servlet;动态代理适用于后台的一些service方法。

Proxy 这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法,它的作用就是得到一个动态的代理对象。


应用实例

下面是一个具体的示例,通过动态代理实现AOP,统一控制事务。大家可以对比一下使用动态代理前后代码的变化,感受AOP的作用。

一、 原来的manager方法,每个都需要添加相关的事务代码,事务代码大量重复。

    public void delFlowCard(String[] flowCardVouNos)
            throws ApplicationException
    {
        Connection conn = null;
        try
        {
            // 取得Connection
            conn = ConnectionManager.getConnection();

            // 开始事务
            ConnectionManager.beginTransaction(conn);

            // 删除流向单明细
            flowCardDao.delFlowCardDetail(flowCardVouNos);

            // 删除流向单主表
            flowCardDao.delFlowCardMaster(flowCardVouNos);

            // 提交事务
            ConnectionManager.commitTransaction(conn);
        }
        catch (DaoException e)
        {
            // 回滚事务
            ConnectionManager.rollbackTransaction(conn);
            throw new ApplicationException("删除流向单失败!");
        }
        finally
        {
            // 关闭Connection并从ThreadLocal中清除
            ConnectionManager.closeConnection();
        }
    }


二、 使用动态代理实现AOP效果:

① 创建代理类:

/**
 * @ClassName: TransactionHandler
 * @Description: 动态代理封装事务
 * @author: 十期-牛迁迁
 * @date: 2015-10-11 下午2:59:15
 */
public class TransactionHandler implements InvocationHandler
{
    private Object targetObject;

    public Object newProxyInstance(Object targetObject)
    {
        this.targetObject = targetObject;
        //使用Proxy类,通过反射得到一个动态的代理对象
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(), this);
    }

     //在invoke方法中做一些其他操作
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
        Connection conn = null;
        Object ret = null;
        try
        {
            // 从ThreadLocal中取得Connection
            conn = ConnectionManager.getConnection();
            if (method.getName().startsWith("add")
                    || method.getName().startsWith("del")
                    || method.getName().startsWith("modify"))
            {
                // 手动控制事务提交
                ConnectionManager.beginTransaction(conn);
            }
            // 调用目标对象的业务逻辑方法
            ret = method.invoke(targetObject, args);
            if (!conn.getAutoCommit())
            {
                // 提交事务
                ConnectionManager.commitTransaction(conn);
            }
        }
        catch (ApplicationException e)
        {
            // 回滚事务
            ConnectionManager.rollbackTransaction(conn);
            throw e;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            if (e instanceof InvocationTargetException)
            {
                InvocationTargetException ete = (InvocationTargetException) e;
                throw ete.getTargetException();
            }
            // 回滚事务
            ConnectionManager.rollbackTransaction(conn);
            throw new ApplicationException("操作失败!");
        }
        finally
        {
            ConnectionManager.closeConnection();
        }
        return ret;
    }

}

② 在servlet中创建调用代理类

    public void init() throws ServletException
    {
        flowCardManager = (FlowCardManager) getBeanFactory().getServiceObject(
                FlowCardManager.class);
        // 调用代理
        TransactionHandler transactionHandler = new TransactionHandler();
        // 对目标生成代理对象
            flowCardManager = (FlowCardManager) transactionHandler
                .newProxyInstance(flowCardManager);
    }


以后在调用manager的方法时会先跳到代理类中执行相应的事务操作,然后在继续调用目标方法。这样我们的事务代码只需要写一次,就可以满足所有的需要,完成了代码的复用,同时维护的话也只需要维护这一个事务代理类即可。这就是面向切面编程带来的好处。

发布了189 篇原创文章 · 获赞 470 · 访问量 74万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览