动态代理 aop切面实现事务管理

 

 

1、定义接口和实现

  
public interface UserService {  
    public String getName(int id);  
  
    public Integer getAge(int id);  
}  

 

public class UserServiceImpl implements UserService {  
    @Override  
    public String getName(int id) {  
        System.out.println("------getName------");  
        return "Tom";  
    }  
  
    @Override  
    public Integer getAge(int id) {  
        System.out.println("------getAge------");  
        return 10;  
    }  
}  

  

 

2、jdk动态代理实现

 

BeanFactiory 创建注入方法时使用

               if (object.getClass().getPackage().getName().equals("")) {
                    ConnectionDynamicProxy connectionDynamicProxy = new ConnectionDynamicProxy();
                    connectionDynamicProxy.setTarget(object);

                    //daili object
                    Object proxyObject = Proxy.newProxyInstance(object.getClass().getClassLoader(),
                            object.getClass().getInterfaces(), connectionDynamicProxy);
                    return proxyObject;
                }

  

public class ConnectionDynamicProxy implements InvocationHandler{

    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        boolean needMyClose = false;
        Connection   conn = (Connection) AppContext.getAppContext().getObject("APP_REQUEST_THREAD_CONNECTION");
        if (conn == null) {
            conn = DBUtil.getConnection();
            needMyClose = true;
            AppContext.getAppContext().addObject("APP_REQUEST_THREAD_CONNECTION",conn);
        }
        try {
            result = method.invoke(target, args);
        } finally {
            if (needMyClose) {
                conn = (Connection) AppContext.getAppContext().getObject("APP_REQUEST_THREAD_CONNECTION");
                DBUtil.close(conn, null, null);
                AppContext.getAppContext().removeObject("APP_REQUEST_THREAD_CONNECTION");
                conn = null;
            }
        }
        return result;
    }

}
代理对象

 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;

import com.augmentum.oes.util.DBUtil;

public class ConnectionDynamicProxy implements InvocationHandler{

    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        boolean needMyClose = false;
        boolean isCommitOrRollbackTran =  false;
        ConnectionHolder   connectionHolder = (ConnectionHolder) AppContext.getAppContext().getObject("APP_REQUEST_THREAD_CONNECTION");

        if (connectionHolder == null) {
            connectionHolder = new ConnectionHolder();
            Connection conn = DBUtil.getConnection();
            connectionHolder.setConn(conn);
            if (method.getName().equals("add")) {
                DBUtil.setAutoCommit(conn, false);
                connectionHolder.setStartTran(true);
                isCommitOrRollbackTran = true;
            }
            AppContext.getAppContext().addObject("APP_REQUEST_THREAD_CONNECTION",connectionHolder);
            needMyClose = true;
        } else {
            if (method.getName().equals("add")) {
                if(!connectionHolder.isStartTran()) {
                    connectionHolder.setStartTran(true);
                    DBUtil.setAutoCommit(connectionHolder.getConn() , false);
                    isCommitOrRollbackTran = true;
                }
            }
        }
        try {
            result = method.invoke(target, args);
            if (method.getName().equals("add")) {
                if (isCommitOrRollbackTran) {
                DBUtil.commit(connectionHolder.getConn());
                }

            }
        } catch (Throwable throwable) {
            if (method.getName().equals("add")) {
                if (isCommitOrRollbackTran) {
                    DBUtil.rollback(connectionHolder.getConn());
                }

            }
            throw throwable;
        } finally {
            if (needMyClose) {
                connectionHolder = (ConnectionHolder) AppContext.getAppContext().getObject("APP_REQUEST_THREAD_CONNECTION");
                DBUtil.close(connectionHolder.getConn(), null, null);
                AppContext.getAppContext().removeObject("APP_REQUEST_THREAD_CONNECTION");
                connectionHolder.setConn(null);
                connectionHolder = null;
            }
        }
        return result;
    }

}

 放置connection与是否开启事务

package com.augmentum.oes.common;

import java.sql.Connection;

public class ConnectionHolder {
    private Connection conn;
    private boolean isStartTran = false;

    public Connection getConn() {
        return conn;
    }

    public void setConn(Connection conn) {
        this.conn = conn;
    }

    public boolean isStartTran() {
        return isStartTran;
    }

    public void setStartTran(boolean isStartTran) {
        this.isStartTran = isStartTran;
    }

}
ConnectionHolder

 也就是说main函数里面的proxy实际就是$Proxy0的一个实例对象。
可知JDK动态代理是使用接口生成新的实现类,实现类里面则委托给InvocationHandler,InvocationHandler里面则调用被代理的类方法

 

3、cglib动态代理实现

 Cglib是通过直接继承被代理类,并委托为回调函数来做具体的事情:

从代理类里面可知道对于原来的add函数,代理类里面对应了两个函数分布是add 和CGLIB$add$0
其中后者是在方法拦截器里面调用的的,前者则是我们使用代理类时候调用的函数。当我们代码调用add时候,会具体调用到方法拦截器的intercept方法,该方法内则通过proxy.invokeSuper调用CGLIB$add$0

这是一个需要被代理的类,也就是父类,通过字节码技术创建这个类的子类,实现动态代理。

public class SayHello {  
 public void say(){  
  System.out.println("hello everyone");  
 }  
}  

  

该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类实例。proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。

 

public class CglibProxy implements MethodInterceptor{  
 private Enhancer enhancer = new Enhancer();  
 public Object getProxy(Class clazz){  
  //设置需要创建子类的类  
  enhancer.setSuperclass(clazz);  
  enhancer.setCallback(this);  
  //通过字节码技术动态创建子类实例  
  return enhancer.create();  
 }  
 //实现MethodInterceptor接口方法  
 public Object intercept(Object obj, Method method, Object[] args,  
   MethodProxy proxy) throws Throwable {  
  System.out.println("前置代理");  
  //通过代理类调用父类中的方法  
  Object result = proxy.invokeSuper(obj, args);  
  System.out.println("后置代理");  
  return result;  
 }  
}  

  实现类

public class DoCGLib {  
 public static void main(String[] args) {  
  CglibProxy proxy = new CglibProxy();  
  //通过生成子类的方式创建代理类  
  SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);  
  proxyImp.say();  
 }  
}  

 结果

前置代理
hello everyone
后置代理

  

 

关闭事务自动提交   
public static void setAutoCommit(Connection conn, boolean autoCommit) { try { conn.setAutoCommit(autoCommit); } catch (SQLException e) { e.printStackTrace(); throw new DBException(); } }

同一事务代码块


提交事务 commit catch 调用 public void rollback(Connection conn) { try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); throw new DBException(); } }

  

 

 四 spring 进行 事务 管理

    <!-- add Transation Manger -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
        <!-- start  Transation annoation -->  加入这个时可以直接使用注解@Transctional
        <tx:annotation-driven transaction-manager="transactionManager"/>
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="update" propagation="REQUIRED" read-only="false"/>
            <tx:method name="deleteById" propagation="REQUIRED" read-only="false"/>
            <tx:method name="getNextId" propagation="REQUIRED" read-only="false"/>
            <tx:method name="addUpdate" propagation="REQUIRED" read-only="false"/>
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut expression="execution(* com.augmentum.oes.service..*.*(..))" id="pc"/>
        <aop:advisor pointcut-ref="pc" advice-ref="txAdvice" order="1"/>
    </aop:config>

注解属性xml配置属性

 

rollbackFor  设置为此异常回滚。 大部分异常继承runtimeException

 

对应JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托为hanlder去调用原始实现类方法。

比如接口类为Abo,实现类为AboImpl,AboImpl的代理类为$ProxyAoImpl ,那么$ProxyAoImpl 能赋值给Abo?能够赋值给AboImpl?

$ProxyAoImpl 是能够赋值给Abo的,因为前者间接实现了后者,但是$ProxyAoImpl 不能赋值给AboImpl因为他们没有继承或者实现关系。所以回顾下自己项目中Rpc里面autowired时候都是对bo类进行的,而不是对boimpl,并且我们的boimpl类一般都是配置了事务切面被代理过的。

对应Cglib则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。

另外JDK代理只能对接口进行代理,Cglib则是对实现类进行代理。

posted @ 2017-07-28 11:22  jojoworld  阅读(805)  评论(0编辑  收藏  举报