mysql:day5-详解多线程状态下的事务(连接池、动态代理技术)
来源:互联网 发布:万圣节软件 编辑:程序博客网 时间:2024/05/21 06:57
问题:
如下面代码:
cn.hncu.demo.TxMultiThreadDemo
package cn.hncu.demo;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;import cn.hncu.pool.ConnsFactory;import cn.hncu.util.ConnFactory;/* * 通过本例的演示说明: * 如果多个线程获取的是同一个con对象,那么一个线程的事务提交,会把其它线程正在执行的语句也提交了。 * 反之,如果一个线程进行事务回滚,那么会把其它线程的语句也回滚了。 * 还有,一个线程把con关闭,那么其它线程执行提交或回滚时就会出异常。 * -----总之,多线程共享同一个连接,会相互影响。 */public class TxMultiThreadDemo { public static void main(String[] args) { Connection con = null; try { con=ConnFactory.getCon(); con.setAutoCommit(false); new OneThread().start(); Statement st = con.createStatement(); String sql ="insert into student values('p00a','测试一',23)"; st.execute(sql); sql ="insert into student values('p0a0','测试二',29)"; st.execute(sql); System.out.println("主线程准备提交"); con.commit(); System.out.println("主线程已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("主线程回滚"); } catch (SQLException e1) { throw new RuntimeException("主线程事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); con.close(); } } catch (Exception e) { throw new RuntimeException("主线程事务关闭失败!", e); } } }}class OneThread extends Thread{ @Override public void run() { Connection con = null; try { con=ConnFactory.getCon(); con.setAutoCommit(false); Statement st = con.createStatement(); String sql ="insert into student values('p00b','测试一#',21)"; st.execute(sql); sql ="insert into student values('p0b0','测试二#',39)"; st.execute(sql); System.out.println("次线程准备提交"); con.commit(); System.out.println("次线程已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("次线程回滚"); } catch (SQLException e1) { throw new RuntimeException("次线程事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); con.close(); } } catch (Exception e) { throw new RuntimeException("次线程事务关闭失败!", e); } } }}
cn.hncu.util.ConnFactory
package cn.hncu.util;import java.io.IOException;import java.sql.Connection;import java.sql.DriverManager;import java.util.Properties;public class ConnFactory { private static Connection con ; static{ //采用配置文件的方式连接数据库 try { Properties p = new Properties(); p.load(ConnFactory.class.getClassLoader().getResourceAsStream("jdbc.properties")); String driver =p.getProperty("driver"); String url = p.getProperty("url"); String userName=p.getProperty("userName"); String password = p.getProperty("password"); //1加载连接器 Class.forName(driver); //2建立连接 con = DriverManager.getConnection(url, userName, password); } catch (Exception e) { e.printStackTrace(); } } public static Connection getCon(){ return con; }// public static void main(String[] args) {// getCon();// System.out.println(con);// }}
如果多个线程获取的是同一个con对象,那么一个线程的事务提交,会把其它线程正在执行的语句也提交了。
反之,如果一个线程进行事务回滚,那么会把其它线程的语句也回滚了。
还有,一个线程把con关闭,那么其它线程执行提交或回滚时就会出异常。
—–总之,多线程共享同一个连接,会相互影响。
由此引出了线程池
解决方法:
解决方法1:
限制个数的多例+锁拿connection对象+把关流改成还回去一个connection对象
cn.hncu.pool.ConnsFactory
package cn.hncu.pool;import java.sql.Connection;import java.sql.DriverManager;import java.util.ArrayList;import java.util.List;import java.util.Properties;import cn.hncu.util.ConnFactory;public class ConnsFactory { private static List<Connection> pool = new ArrayList<Connection>(); private static final int NUM=3; static{ //采用配置文件的方式连接数据库 try { Properties p = new Properties(); p.load(ConnFactory.class.getClassLoader().getResourceAsStream("jdbc.properties")); String driver =p.getProperty("driver"); String url = p.getProperty("url"); String userName=p.getProperty("userName"); String password = p.getProperty("password"); //1加载连接器 Class.forName(driver); for (int i = 0; i < NUM; i++) { //2建立连接 Connection con = DriverManager.getConnection(url, userName,password); pool.add(con); } } catch (Exception e) { e.printStackTrace(); } } public static synchronized Connection getCon() throws InterruptedException{ if(pool.size()<=0){ Thread.sleep(100); getCon(); } return pool.remove(0); } public static void backCon(Connection con){ System.out.println("还回来一个连接..."); pool.add(con); }}
cn.hncu.pool.TestPool
package cn.hncu.pool;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;public class TestPool { public static void main(String[] args) { Connection con = null; try { con= ConnsFactory.getCon(); con.setAutoCommit(false); new OneThread(1).start(); new OneThread(2).start(); new OneThread(3).start(); new OneThread(4).start(); new OneThread(5).start(); Statement st = con.createStatement(); String sql ="insert into student values('p00a','测试一',23)"; st.execute(sql); sql ="insert into student values('p0a0','测试二',29)"; st.execute(sql); System.out.println("主线程准备提交"); con.commit(); System.out.println("主线程已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("主线程回滚"); } catch (SQLException e1) { throw new RuntimeException("主线程事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); ConnsFactory.backCon(con);//将关流改成还连接对象,如果一定要用关闭连接, //那么我们将close()函数的功能修改成还连接对象,以后学动态代理、切面技术会学到 } } catch (Exception e) { throw new RuntimeException("主线程事务关闭失败!", e); } } }}class OneThread extends Thread{ private int num; public OneThread(int num) { this.num = num; } @Override public void run() { Connection con = null; try { con= ConnsFactory.getCon(); con.setAutoCommit(false); Statement st = con.createStatement(); String sql ="insert into student values('p0"+num+"1','测试一"+num+"',25)"; st.execute(sql); sql ="insert into student values('p"+num+"01','测试二"+num+"',26)"; st.execute(sql); System.out.println("线程"+num+"准备提交"); con.commit(); System.out.println("线程"+num+"已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("线程"+num+"回滚"); } catch (SQLException e1) { throw new RuntimeException("第"+num+"个事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); ConnsFactory.backCon(con); } } catch (Exception e) { throw new RuntimeException("第"+num+"个事务关闭失败!", e); } } }}
上面这种方法索然是能解决多线程下的事务处理,但是把我们习惯的con.close()
方法变成了ConnsFactory.backCon(con)
这样不符合我们开发的习惯。
由此我们要学习动态代理技术。
解决方法2
可以用继承Connection 然后覆盖也可以用实现Connection接口,然后实现它的接口,使用装饰模式封装一个Connection对象我们自己做connection的colse()方法自己想要做的方法自己写,不做的就用封装的Connection对象去做。Connection对象用构造方法传进来去封装。
缺点是:代码太长了,为了一个自己写的方法实现Connection接口的所有抽象方法,我的天。当然这里只是为了过度。
cn.hncu.pool.day2.v1.ConnsUtils2
package cn.hncu.pool.day2.v1;import java.sql.Array;import java.sql.Blob;import java.sql.CallableStatement;import java.sql.Clob;import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.DriverManager;import java.sql.NClob;import java.sql.PreparedStatement;import java.sql.SQLClientInfoException;import java.sql.SQLException;import java.sql.SQLWarning;import java.sql.SQLXML;import java.sql.Savepoint;import java.sql.Statement;import java.sql.Struct;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.concurrent.Executor;import cn.hncu.util.ConnFactory;public class ConnsUtils2 { private static List<Connection> pool = new ArrayList<Connection>(); private static final int NUM=3; static{ //采用配置文件的方式连接数据库 try { Properties p = new Properties(); p.load(ConnFactory.class.getClassLoader().getResourceAsStream("jdbc.properties")); String driver =p.getProperty("driver"); String url = p.getProperty("url"); String userName=p.getProperty("userName"); String password = p.getProperty("password"); //1加载连接器 Class.forName(driver); for (int i = 0; i < NUM; i++) { //2建立连接 Connection con = DriverManager.getConnection(url, userName,password); MyConnection conn = new MyConnection(con);//加强版的conn pool.add(conn);//将加强版的conn放入连接池 } } catch (Exception e) { e.printStackTrace(); } } public static synchronized Connection getCon() throws InterruptedException{ if(pool.size()<=0){ Thread.sleep(100); return getCon(); } return pool.remove(0); } static class MyConnection implements Connection{ private Connection con = null; public MyConnection(Connection con) { this.con=con; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { // TODO Auto-generated method stub return false; } @Override public Statement createStatement() throws SQLException { return con.createStatement(); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return con.prepareStatement(sql); } @Override public CallableStatement prepareCall(String sql) throws SQLException { // TODO Auto-generated method stub return null; } @Override public String nativeSQL(String sql) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { con.setAutoCommit(autoCommit); } @Override public boolean getAutoCommit() throws SQLException { return con.getAutoCommit(); } @Override public void commit() throws SQLException { con.commit(); } @Override public void rollback() throws SQLException { con.rollback(); } @Override public void close() throws SQLException { pool.add(con); } @Override public boolean isClosed() throws SQLException { // TODO Auto-generated method stub return false; } @Override public DatabaseMetaData getMetaData() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setReadOnly(boolean readOnly) throws SQLException { // TODO Auto-generated method stub } @Override public boolean isReadOnly() throws SQLException { // TODO Auto-generated method stub return false; } @Override public void setCatalog(String catalog) throws SQLException { // TODO Auto-generated method stub } @Override public String getCatalog() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setTransactionIsolation(int level) throws SQLException { // TODO Auto-generated method stub } @Override public int getTransactionIsolation() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public SQLWarning getWarnings() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void clearWarnings() throws SQLException { // TODO Auto-generated method stub } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { // TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Map<String, Class<?>> getTypeMap() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { // TODO Auto-generated method stub } @Override public void setHoldability(int holdability) throws SQLException { // TODO Auto-generated method stub } @Override public int getHoldability() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public Savepoint setSavepoint() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Savepoint setSavepoint(String name) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void rollback(Savepoint savepoint) throws SQLException { // TODO Auto-generated method stub } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { // TODO Auto-generated method stub } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { // TODO Auto-generated method stub return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { // TODO Auto-generated method stub return null; } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Clob createClob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Blob createBlob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public NClob createNClob() throws SQLException { // TODO Auto-generated method stub return null; } @Override public SQLXML createSQLXML() throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isValid(int timeout) throws SQLException { // TODO Auto-generated method stub return false; } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { // TODO Auto-generated method stub } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { // TODO Auto-generated method stub } @Override public String getClientInfo(String name) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Properties getClientInfo() throws SQLException { // TODO Auto-generated method stub return null; } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { // TODO Auto-generated method stub return null; } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setSchema(String schema) throws SQLException { // TODO Auto-generated method stub } @Override public String getSchema() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void abort(Executor executor) throws SQLException { // TODO Auto-generated method stub } @Override public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { // TODO Auto-generated method stub } @Override public int getNetworkTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } }}
cn.hncu.pool.day2.v1.TestPool
package cn.hncu.pool.day2.v1;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;public class TestPool { public static void main(String[] args) { Connection con = null; try { con= ConnsUtils2.getCon(); con.setAutoCommit(false); new OneThread(1).start(); new OneThread(2).start(); new OneThread(3).start(); new OneThread(4).start(); new OneThread(5).start(); Statement st = con.createStatement(); String sql ="insert into student values('p00a','测试一',23)"; st.execute(sql); sql ="insert into student values('p0a0','测试二',29)"; st.execute(sql); System.out.println("主线程准备提交"); con.commit(); System.out.println("主线程已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("主线程回滚"); } catch (SQLException e1) { throw new RuntimeException("主线程事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); con.close(); } } catch (Exception e) { throw new RuntimeException("主线程事务关闭失败!", e); } } }}class OneThread extends Thread{ private int num; public OneThread(int num) { this.num = num; } @Override public void run() { Connection con = null; try { con= ConnsUtils2.getCon(); con.setAutoCommit(false); Statement st = con.createStatement(); String sql ="insert into student values('p0"+num+"1','测试一"+num+"',25)"; st.execute(sql); sql ="insert into student values('p"+num+"01','测试二"+num+"',26)"; st.execute(sql); System.out.println("线程"+num+"准备提交"); con.commit(); System.out.println("线程"+num+"已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("线程"+num+"回滚"); } catch (SQLException e1) { throw new RuntimeException("第"+num+"个事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); con.close(); } } catch (Exception e) { throw new RuntimeException("第"+num+"个事务关闭失败!", e); } } }}
怎么样 是不是很长,其实你可以不用看这段代码。根本没什么卵用,就是改了一个close方法。让它实现把传进来的connection对象加到pool-连接池去。这样让别人调用时可以实现方法1中把connection对象还回来切程序员在编写代码的时候还是按照以前的习惯调用close方法。
解决方法三 真正的动态代理
cn.hncu.pool.day2.v2.ConnsUtils3
package cn.hncu.pool.day2.v2;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.sql.Array;import java.sql.Blob;import java.sql.CallableStatement;import java.sql.Clob;import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.DriverManager;import java.sql.NClob;import java.sql.PreparedStatement;import java.sql.SQLClientInfoException;import java.sql.SQLException;import java.sql.SQLWarning;import java.sql.SQLXML;import java.sql.Savepoint;import java.sql.Statement;import java.sql.Struct;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.concurrent.Executor;import cn.hncu.util.ConnFactory;public class ConnsUtils3 { private static List<Connection> pool = new ArrayList<Connection>(); private static final int NUM=3; static{ //采用配置文件的方式连接数据库 try { Properties p = new Properties(); p.load(ConnFactory.class.getClassLoader().getResourceAsStream("jdbc.properties")); String driver =p.getProperty("driver"); String url = p.getProperty("url"); String userName=p.getProperty("userName"); String password = p.getProperty("password"); //1加载连接器 Class.forName(driver); for (int i = 0; i < NUM; i++) { //2建立连接 final Connection con = DriverManager.getConnection(url, userName,password); Connection conn = (Connection)Proxy.newProxyInstance( ConnsUtils3.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equalsIgnoreCase("close")){ pool.add(con); return null; }else{ return method.invoke(con, args); } } } ); pool.add(conn);//将代理后的的conn放入连接池 } } catch (Exception e) { e.printStackTrace(); } } public static synchronized Connection getCon() throws InterruptedException{ if(pool.size()<=0){ Thread.sleep(100); return getCon(); } return pool.remove(0); }}
cn.hncu.pool.day2.v2.TestPool
package cn.hncu.pool.day2.v2;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;public class TestPool { public static void main(String[] args) { Connection con = null; try { con= ConnsUtils3.getCon(); con.setAutoCommit(false); new OneThread(1).start(); new OneThread(2).start(); new OneThread(3).start(); new OneThread(4).start(); new OneThread(5).start(); Statement st = con.createStatement(); String sql ="insert into student values('p00a','测试一',23)"; st.execute(sql); sql ="insert into student values('p0a0','测试二',29)"; st.execute(sql); System.out.println("主线程准备提交"); con.commit(); System.out.println("主线程已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("主线程回滚"); } catch (SQLException e1) { throw new RuntimeException("主线程事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); con.close(); } } catch (Exception e) { throw new RuntimeException("主线程事务关闭失败!", e); } } }}class OneThread extends Thread{ private int num; public OneThread(int num) { this.num = num; } @Override public void run() { Connection con = null; try { con= ConnsUtils3.getCon(); con.setAutoCommit(false); Statement st = con.createStatement(); String sql ="insert into student values('p0"+num+"1','测试一"+num+"',25)"; st.execute(sql); sql ="insert into student values('p"+num+"01','测试二"+num+"',26)"; st.execute(sql); System.out.println("线程"+num+"准备提交"); con.commit(); System.out.println("线程"+num+"已经提交"); } catch (Exception e) { try { con.rollback(); System.out.println("线程"+num+"回滚"); } catch (SQLException e1) { throw new RuntimeException("第"+num+"个事务回滚失败!", e1); } }finally{ try { if(con!=null){ con.setAutoCommit(true); con.close(); } } catch (Exception e) { throw new RuntimeException("第"+num+"个事务关闭失败!", e); } } }}
怎么样,是不是比起方法二 简洁多了。我也是这样认为的,哈哈。其实就是用动态代理技术,将connection对象的close方法拦截住,然后把拦截到的connection对象加到pool连接池中 至于其他的方法都放行。
让我们来学一下动态代理
动态代理要有接口,具体的代理对象。
动态代理其实很简单,就是java.lang.reflect包里的一个Proxy类的newProxyInstance静态方法,调用一下就好了。返回的就是被代理后的对象。
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
解释一下参数的意思:
第一个参数:是类加载的空间,可以用当前类或者系统的加载类
第二个参数:我们要代理对象实现的接口,可以是多个,所以是一个数组
第三个参数:和按钮监听一样,就是实现这个InvocationHandler 的类都行
然后实现InvocationHandler 的就要实现里面的抽象方法invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
再来解释一下这几个参数的意思
第一个参数:被代理的对象
第二个参数:学过类反射的都应该知道,这是利用类反射所拿到的方法
第三个参数:方法所需的参数。
然后在这个invoke方法里面,你就可以做你想做的事。 拦截方法,输入输出呀什么的,想干嘛就干嘛 很强大,很java。放行就是调用方法的invoke方法就执行这个方法了。
下面我们给几个简单一点例子理解一下动态代理
1、房东-中介-房客
IRenter接口
package cn.hncu.pool.day2.proxy.v1;public interface IRenter { public void rent(int i);}
Renter
package cn.hncu.pool.day2.proxy.v1;public class Renter implements IRenter{ @Override public void rent(int i) { System.out.println("给你"+i+"个房间,交费500元"); } @Override public String toString() { System.out.println("你好:我是房东,请爱惜房间,不要乱涂乱画"); return "你好:我是房东,请爱惜房间,不要乱涂乱画"; }}
Client
package cn.hncu.pool.day2.proxy.v1;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Client { public static void main(String[] args) { final IRenter rent = new Renter();//接口是是IRenter 被代理的对象是rent Object obj = Proxy.newProxyInstance( Client.class.getClassLoader(), new Class[]{IRenter.class}, new InvocationHandler() { //动态代理最主要的方法 @Override//proxy是被代理的对象,method是用类加载的方法,args是参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我是中介,我收取了一定的中介费用"); Object oo =method.invoke(rent, args);//在代理里面invoke就是放行这个方法,这里是什么都没有防范就都放行了 System.out.println("如果还有什么需要请来找我们,我们是最好的"); return oo; } }); //返回的obj就是被代理之后的对象 IRenter rr = (IRenter)obj; rr.rent(5); rr.toString(); //只要是rr里面的方法 都会执行在动态代理中输入的两条语句 }}
下面让我们试一下在拦截一下然后做点什么吧
Client2
package cn.hncu.pool.day2.proxy.v1;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Client2 { public static void main(String[] args) { final IRenter rent = new Renter();//接口是是IRenter 被代理的对象是rent Object obj = Proxy.newProxyInstance( Client2.class.getClassLoader(), new Class[]{IRenter.class}, new InvocationHandler() { //动态代理最主要的方法 @Override//proxy是被代理的对象,method是用类加载的方法,args是参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oo;//在代理里面invoke就是放行这个方法,这里是什么都没有防范就都放行了 if (method.getName().equals("rent")) { System.out.println("我是中介,我收取了一定的中介费用"); oo = method.invoke(rent, args); System.out.println("如果还有什么需要请来找我们,我们是最好的"); }else{ oo = method.invoke(rent, args); //这里不执行两条语句 直接放行 } return oo; } }); //返回的obj就是被代理之后的对象 IRenter rr = (IRenter)obj; rr.rent(5); rr.toString(); //这种方法的代理就是只有是rent方法才会执行两条输出语句,而其他的就直接放行 原样输出 }}
2、代理java API中的接口
幻读 :在执行方法的时候告诉你执行了什么方法
ProxyDemo2
package cn.hncu.pool.day2.proxy.v2;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.List;/* * 代理java API中的接口 * * */public class ProxyDemo2 { /* * 幻读 :在执行方法的时候告诉你执行了什么方法 * */ public static void main(String[] args) { Object obj = Proxy.newProxyInstance( ProxyDemo2.class.getClassLoader(), new Class[]{List.class}, new A() ); List list = (List) obj; list.add(1); list.add("你好"); list.remove(0); list.get(0); } static class A implements InvocationHandler{ private List list= new ArrayList(); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("你现在执行的是"+method.getName()+"方法"); Object oo = method.invoke(list, args); return oo; } }}
3、做一个动态代理的模板
ProxyUtil
package cn.hncu.pool.day2.proxy.v3.utils;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyUtil implements InvocationHandler { private Object srcObj = null; private ProxyUtil(Object srcObj) { this.srcObj = srcObj; } public static Object getProxy(Object srcObj){ Object obj = Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), srcObj.getClass().getInterfaces(), new ProxyUtil(srcObj)); return obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("你现在执行的方法是:"+method.getName()+"方法,正在被工具类处理。。。"); return method.invoke(srcObj, args); }}
IAnimal接口
package cn.hncu.pool.day2.proxy.v3.domain;public interface IAnimal { public void run();}
IPerson接口
package cn.hncu.pool.day2.proxy.v3.domain;public interface IPerson { public void sayHi();}
Person
package cn.hncu.pool.day2.proxy.v3.domain;public class Person implements IPerson{ private String name; public Person(String name) { this.name = name; } @Override public void sayHi() { System.out.println("你好啊,"+name+",祝你七夕节有情人终成眷属!"); }}
Dog
package cn.hncu.pool.day2.proxy.v3.domain;public class Dog implements IAnimal{ private String name; public Dog(String name) { this.name = name; } @Override public void run() { System.out.println("Dog:"+name+",正在吃骨头,很开心"); }}
Clinet
package cn.hncu.pool.day2.proxy.v3;import cn.hncu.pool.day2.proxy.v3.domain.Dog;import cn.hncu.pool.day2.proxy.v3.domain.IAnimal;import cn.hncu.pool.day2.proxy.v3.domain.IPerson;import cn.hncu.pool.day2.proxy.v3.domain.Person;import cn.hncu.pool.day2.proxy.v3.utils.ProxyUtil;public class Client { public static void main(String[] args) { IPerson person = new Person("曹思琪"); IPerson person2 =(IPerson)ProxyUtil.getProxy(person);//被代理之后的person person2.sayHi(); IAnimal dog = new Dog("EDG-Nice"); IAnimal dog2 = (IAnimal)ProxyUtil.getProxy(dog); dog2.run(); }}
好了动态代理的学习到此为止。QWQ~~~
- mysql:day5-详解多线程状态下的事务(连接池、动态代理技术)
- 采用动态代理技术,实现标准的连接池
- JAVAWEB开发之事务详解(mysql与JDBC下使用方法、事务的特性、锁机制)和连接池的详细使用(dbcp以c3p0)
- 多线程共享MySQL连接时,使用事务的危险!
- 动态代理模式封装事务详解
- 连接池(事务和多线程问题)
- 25、连接池(DBCP、C3P0)、动态代理与分页技术
- .NET多线程技术详解(3) 线程状态
- MySQL的事务、连接池以及数据源
- Proxy(动态代理)封装(service层的)事务
- Solaris10 下的多线程和Mysql多线程连接
- MYSQL的事务详解
- mysql的事务详解
- JAVA动态代理技术详解 Proxy
- 连接池4:动态代理
- 动态代理模拟连接池
- 动态代理封装事务
- 特定需求下动态代理导致的Spring事务不能回滚
- Tomcat默认的Session持久化的效果
- 《高质量C++编程指南》摘录8
- POJ 1928 The Peanuts
- 漫谈iOS程序的证书和签名机制
- 用Swift写一个发送邮件的iOS用户反馈
- mysql:day5-详解多线程状态下的事务(连接池、动态代理技术)
- 大三实习的工作总结。
- java抽象类、抽象方法
- QT多语言翻译工作
- python 变量命名规范
- 海量数据处理——倒排索引
- java线程yield(),sleep(),wait()区别
- Java NIO 之 Scatter 和gather
- [iOS 登陆加密] RSA加密