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~~~

1 0
原创粉丝点击