问题:
如下面代码:
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~~~