Java中用动态代理实现标准的DataSource数据源连接池
2017-12-24 17:46
281 查看
首先简单谈谈为什么要用连接池?
大家知道,我们平常连接数据库的时候,首先需要获取到数据库的连接 Java中对应的是 Connection,建立获取数据库连接是比较消耗资源的,而且每次建立获取连接也比较浪费时间,可以试想,如果每次请求过来,需要访问数据库时,都去重新建立并获取新的连接,就会浪费大量的资源和时间,此时客户端的相应时间肯定会较长,这并不是我们想看到的。因此这时候我们就要想办法避免这种现象,所以这时候就可以用连接池来解决。其实简单的说,连接池实现的主要目的就是,获取连接的时候从池中获取已经初始化好的连接,这样做就不用每次都建立新的连接,就能节省资源的消耗,也能提高效率。然后在用完连接以后,调用conn.close( ); 关闭连接的时候并不是真去把这个连接关闭掉,而是应该把这个连接放回到池中,下次请求过来了,可以继续使用。
Java中连接池具体的实现一般有两种方式,一种是用包装类来实现,另一种是用动态代理来实现
现在常见的开源的Java连接池有DBCP和C3P0等,其中DBCP就是上边说的利用包装类来实现的,而C3P0是动态代理实现的。
今天只简单的讲一下动态代理的实现,关于包装类的实现方法,有时间的话,我也会整理一下
下面我们简单讲一下动态代理的实现,用动态代理写一个简单的连接池,供新同学参考,高手请自动忽略
首先贴一下为这次例子我建的一个简单的学生表,数据库是自己电脑虚拟机Linux上装的MySql数据库
超级的简单的一个表,就不多解释了。下面开始进入正题...
第一步:我们需要写一个标准的数据源DataSource,Java中DataSource是一个标准的数据源接口
/** * * @author caoju * */ public class MyDataSource implements DataSource{ private static LinkedList<Connection> pool = new LinkedList<Connection>(); private static final String name = "com.mysql.jdbc.Driver"; private static final String url = "jdbc:mysql://192.168.199.188:3306/cj"; private static final String user = "root"; private static final String password = "123456"; static{//利用静态代码块儿在类一加载的时候就初始化10个连接到池中 try { Class.forName(name); for(int i=0;i<10;i++){ Connection conn = DriverManager.getConnection(url, user, password); pool.add(conn); } } catch (Exception e) { e.printStackTrace(); } } @Override public Connection getConnection() throws SQLException { if(pool.size()>0){ final Connection conn = pool.remove(); //返回动态代理对象 return (Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("close".equals(method.getName())){ return pool.add(conn); }else { return method.invoke(conn, args); } } }); }else{ throw new RuntimeException("对不起,服务器忙..."); } } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { // TODO Auto-generated method stub } @Override public void setLoginTimeout(int seconds) throws SQLException { // TODO Auto-generated method stub } @Override public int getLoginTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { // TODO Auto-generated method stub return null; } @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 Connection getConnection(String username, String password) throws SQLException { // TODO Auto-generated method stub return null; } }
返回动态代理对象需要注意几点:一,代理对象需要和被代理的对象用一个类加载器;二,代理对象需要和被代理的对象实现同样的接口;三,需要new InvocationHandler()
来处理对象中具体的方法
第二步:建一个实体类对象,用来接收封装查询出来的数据
public class Student implements Serializable{ private static final long serialVersionUID = -1672204456370247243L; private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } }这就是个普通的bean对象,很简单,没啥可说的。
第三步:写一个调用端来测试写的连接池
/** * * @author caoju * */ public class Client { public static void main(String[] args) { DataSource ds = new MyDataSource(); Connection conn = null; PreparedStatement ps = null; try { conn = ds.getConnection(); ps = conn.prepareStatement("select * from student"); ResultSet rs = ps.executeQuery(); List<Student> stuList = new ArrayList<Student>(); while(rs.next()){ Student student = new Student(); String id = rs.getString("id"); String name = rs.getString("name"); student.setId(id); student.setName(name); stuList.add(student); } for (Student student : stuList) { System.out.println(student); } } catch (Exception e) { 4000 e.printStackTrace(); }finally{ if(ps!=null){ try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
可以打断点看一下,返回的 conn 对象已经是$Proxy0,说明返回的已经是代理的对象了,而不是conn自身,而在返回的代理的对象里,我们已经对Close方法做了处理,所以就简单的实现了调用close的时候,不是真正的关闭数据库连接资源,而是把使用完的连接资源还回池中,供别的请求使用或者下次继续使用。
最后运行结果:
好了,一个简单的连接池就实现了,虽然代码比较简陋,但是能讲清楚里边的原理就好啦,哈哈。
大家可以动手试一试,过程中需要导入MySQL的驱动包,不要忘记啦。
相关文章推荐
- Java 的动态代理实例(JDBC的数据库的连接池(DataSource))
- 【java】动态代理+ThreadLocal实现数据源及事务管理
- 采用动态代理技术,实现标准的连接池
- 【Java】mybatis用AbstractRoutingDataSource实现动态数据源时的事务管理
- Java中用包装模式实现标准的DataSource数据源连接池
- 使用JAVA中的动态代理实现数据库连接池
- 使用JAVA中的动态代理实现数据库连接池
- 迈出AOP第一步--使用Java 动态代理实现AOP[zz]
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP
- 设计模式:用Java动态代理实现AOP
- Java动态代理实现
- 使用Java动态代理实现AOP
- 用Java动态代理实现AOP
- Java动态代理实现
- 使用JAVA中的动态代理实现数据库连接池
- Java动态代理实现AOP
- 用Java动态代理实现AOP
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP(转)
- 用Java动态代理实现AOP