什么叫做动态代理:就是不用我们手动去编写代理类了,系统会自动帮你生成,生成的类是在内存里,不占用硬盘空间,也不会像静态代理一样添加一个方法就需要改一遍代理类。动态代理就是一劳永逸。
废话不多说直接看代码
首先需要准备一个.properties配置文件
//此文件为配置文件以key-value键值对的方式出现 //加载mysql驱动 jdbc.driver=com.mysql.jdbc.Driver //数据库链接地址 jdbc.connection.url=jdbc:mysql://localhost:3306/lx1 //数据库用户名 jdbc.connection.username=root //数据库密码 jdbc.connection.password=
如图所示的文件:
接下来就开始编写我们的接口类了
package cn.dao;import java.sql.ResultSet; //接口类 public interface JDBC_operation {void getConnection();//获得连接的方法int executeUpdate(String sql,Object...obj);//增删改 里面需要传入一个sql语句还有一个不定长参数(是为sql语句里面?准备的)ResultSet executeQuery(String sql,Object...obj);//查询 里面需要传入一个sql语句还有一个不定长参数(是为sql语句里面?准备的)void closeAll();//关闭连接资源 }
接下来编写实现类
package cn.dao;import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties;public class JDBC_impl implements JDBC_operation{private static String drivate;private static String url;private static String username;private static String password;private Connection connection;private PreparedStatement preparedStatement;private ResultSet resultSet;//静态代码块获得我们连接数据库所需要的信息static {Properties properties=new Properties();//这个方法可以读取配置文件.propertiesInputStream in = JDBC_impl.class.getClassLoader().getResourceAsStream("database.properties");try {properties.load(in);//load方法可以读取文件//获得配置文件里面的对应内容drivate=properties.getProperty("jdbc.driver");url=properties.getProperty("jdbc.connection.url");username=properties.getProperty("jdbc.connection.username");password=properties.getProperty("jdbc.connection.password");} catch (IOException e) {e.printStackTrace();}}//连接 @Overridepublic void getConnection(){try {//加载驱动 Class.forName(drivate);//获得数据库的连接connection = DriverManager.getConnection(url, username, password);} catch (SQLException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}//增删改 @Overridepublic int executeUpdate(String sql,Object...obj) {try {//用PreparedStatement对象去执行sql代码preparedStatement = connection.prepareStatement(sql);//不定长参数产生的是一个数组所以我们要用for循环去遍历它的长度(不定长参数可以为空)for (int i=0;i<obj.length;i++){//给执行的sql语句里面的?赋值preparedStatement.setObject(i+1,obj[i]);}//执行增删改的方法int i = preparedStatement.executeUpdate();//返回行数return i;} catch (SQLException e) {e.printStackTrace();//捕获到异常则返回-1return -1;}}//查询 @Overridepublic ResultSet executeQuery(String sql,Object...obj) {try {//用PreparedStatement对象去执行sql代码preparedStatement = connection.prepareStatement(sql);//不定长参数产生的是一个数组所以我们要用for循环去遍历它的长度(不定长参数可以为空)for (int i=0;i<obj.length;i++){//给执行的sql语句里面的?赋值preparedStatement.setObject(i+1,obj[i]);}//执行查询的方法resultSet = preparedStatement.executeQuery();//返回结果集return resultSet;} catch (SQLException e) {e.printStackTrace();//捕获到异常则返回-1return null;}}//关闭 @Overridepublic void closeAll() {if(resultSet!=null){try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if(preparedStatement!=null){try {preparedStatement.close();} catch (SQLException e) {e.printStackTrace();}}if(connection!=null){try {connection.close();} catch (SQLException e) {e.printStackTrace();}}} }
好了,接下来就是我们的动态代理了,为什么在这里需要用到动态代理呢是因为JDBC操作的时候总是要连接数据库和释放资源,如果用动态代理就会省略这两步,让系统自动帮我们实现,这样省去了很多的重复操作。
package cn.dao;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //创建动态代理需要实现InvocationHandler接口 面向接口实现的动态代理 public class Agent implements InvocationHandler {private JDBC_operation jdbc;public Agent(JDBC_operation jdbc) {this.jdbc = jdbc;}public Agent() {}@Override//第一个参数proxy是真实对象的真实代理对象,invoke方法可以返回调用代理对象方法的返回结果,也可以返回对象的真实代理对象(可以使用反射获取代理对象的信息)//第二个则是需要代理的接口//第三个则是参数public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long l = System.currentTimeMillis();jdbc.getConnection();//代理实现的方法System.out.println("已连接");Object o = method.invoke(jdbc, args);//需要传递要代理的接口以及参数jdbc.closeAll();//代理实现的方法System.out.println("已关闭");long l1 = System.currentTimeMillis();System.out.println("总用毫秒数:"+(l1-l)+"ms");return o;}}
接下来我们就去测试一下
package cn.dao;import java.lang.reflect.Proxy; import java.sql.ResultSet; import java.sql.SQLException;public class Test {public static void main(String[] args) throws SQLException {JDBC_operation jdbc=new JDBC_impl();//实例化自己定义的方法实现类对象//第一个参数: 用哪个类加载器去加载代理对象//第二个参数:动态代理类需要实现的接口//第三个参数:动态代理方法在执行时,会调用InvocationHandler里面的invoke方法去执行JDBC_operation o = (JDBC_operation)Proxy.newProxyInstance(jdbc.getClass().getClassLoader(), new Class[]{JDBC_operation.class}, new Agent(jdbc));String sql="insert into student(stuname) values('哈哈')";int i = o.executeUpdate(sql);if (i>0){System.out.println("插入数据成功");}else {System.out.println("插入数据失败");}} }
结果如下:
这里需要注意一下,查询的话需要把动态代理的关闭资源方法去掉,需要我们调用之后自己手动关闭,因为不关掉就会出现如下错误:
这个的意思是:线程“main”java中的异常。sql。SQLException:在com处ResultSet关闭后,不允许操作。mysgl。jdbc。SQLError。原因是数据库不允许这样操作,所以我们直接用对象调用关闭的方法就好了
增删改不会出现这种错误