• 动态代理 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则是对实现类进行代理。

  • 相关阅读:
    转载 | CSS文本溢出显示省略号
    转载 | CSS书写顺序
    转载 | CSS布局大全
    threejs sprite 制作标签
    typeScript 中的类
    Es5中的类
    typeScript中的函数
    websocket在vue项目中的使用
    typeScript中的变量数据类型
    echarts 中的1/4圆环行图的使用
  • 原文地址:https://www.cnblogs.com/mxz1994/p/7249255.html
Copyright © 2020-2023  润新知