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; } }
也就是说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>
rollbackFor 设置为此异常回滚。 大部分异常继承runtimeException
对应JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托为hanlder去调用原始实现类方法。
比如接口类为Abo,实现类为AboImpl,AboImpl的代理类为$ProxyAoImpl
,那么$ProxyAoImpl
能赋值给Abo?能够赋值给AboImpl?
$ProxyAoImpl
是能够赋值给Abo的,因为前者间接实现了后者,但是$ProxyAoImpl
不能赋值给AboImpl因为他们没有继承或者实现关系。所以回顾下自己项目中Rpc里面autowired时候都是对bo类进行的,而不是对boimpl,并且我们的boimpl类一般都是配置了事务切面被代理过的。
对应Cglib则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
另外JDK代理只能对接口进行代理,Cglib则是对实现类进行代理。