• 数据库连接池、动态代理


    http://blog.csdn.net/lengjinghk/article/details/52170808

    在web项目中,Java访问数据库采用的是多用户操作,需要频繁连接数据库,一种方法是来一个请求给一个操作对象,这种方法想法简单,但存在巨大隐患,如果访问量特别的大,数据库连接对象过多,可能导致奔溃。好的方法是,采用数据库连接时统一管理,包括数据库连接对象的个数限制以及使用后回收。

    这里写图片描述

    说到管理,根据程序员习惯,拿到连接对象进行完操作后,一般会关闭连接对象,这就会产生一个问题,下一次别的用户再拿到回收后的关闭对象后,由于对象已关闭,再进行其他操作的话,会产生异常。所以我们要修改close()这个函数的功能。

    思路:要修改函数功能,基本上是采用覆盖的方法,一种方式是采用装饰模式,即继承加组合,但这种方式有个弊端,如果要实现的接口有很多函数,代码量非常大,所以一般不采用。另一种方式是采用代理模式。下面想详细叙述

    代理要用到一个关键的API 类,即Proxy,此外要用到一个接口和接口的一个实例对象。 
    Proxy.newProxyInstance(loader, interfaces, h); 
    第一个参数:与被代理对象处于同一空间的类加载器 
    第二个参数:要实现接口数组 
    第三个参数:实现功能的句柄对象

    下面是一个租房者通过中介租房的例子来演示:

    接口

    public interface IRenter {
        public abstract void rent(int n);
    }

    接口实现类

    public class Renter implements IRenter{
    
        @Override
        public void rent(int n) {
            System.out.println("给你"+n+"间房,请交500元钱");
        }
    }
    
    

    关键类

    public class Client {
        private static IRenter rent = new Renter();
    
        public static void main(String[] args) {
    
            Object obj = Proxy.newProxyInstance(Client.class.getClassLoader(), //
                    new Class[] { IRenter.class }, new InvocationHandler() {
    
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            System.out.println("我代理的......");
                            return method.invoke(rent, args);
                        }
                    });
    
            IRenter o = (IRenter) obj;
            o.rent(3);
        }
    }
     

    根据原理。做一个代理工具类:

    public class ProxyUtil implements InvocationHandler{
        private Object srcObj;
    
        public ProxyUtil(Object srcObj) {
            super();
            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 {
    
            return method.invoke(srcObj, args);
        }
    }
    

    数据库连接池的代码实现:

    package me.gacl.demo;
    
    import java.io.InputStream;
    import java.io.PrintWriter;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.LinkedList;
    import java.util.Properties;
    import javax.sql.DataSource;
    
    /**
    * @ClassName: JdbcPool
    * @Description:编写数据库连接池
    * @author: 孤傲苍狼
    * @date: 2014-9-30 下午11:07:23
    *
    */ 
    public class JdbcPool implements DataSource{
    
        /**
        * @Field: listConnections
        *         使用LinkedList集合来存放数据库链接,
        *        由于要频繁读写List集合,所以这里使用LinkedList存储数据库连接比较合适
        */ 
        private static LinkedList<Connection> listConnections = new LinkedList<Connection>();
        
        static{
            //在静态代码块中加载db.properties数据库配置文件
            InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
            Properties prop = new Properties();
            try {
                prop.load(in);
                String driver = prop.getProperty("driver");
                String url = prop.getProperty("url");
                String username = prop.getProperty("username");
                String password = prop.getProperty("password");
                //数据库连接池的初始化连接数大小
                int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));
                //加载数据库驱动
                Class.forName(driver);
                for (int i = 0; i < jdbcPoolInitSize; i++) {
                    Connection conn = DriverManager.getConnection(url, username, password);
                    System.out.println("获取到了链接" + conn);
                    //将获取到的数据库连接加入到listConnections集合中,listConnections集合此时就是一个存放了数据库连接的连接池
                    listConnections.add(conn);
                }
                
            } catch (Exception e) {
                throw new ExceptionInInitializerError(e);
            }
        }
        
        @Override
        public PrintWriter getLogWriter() throws SQLException {
            // TODO Auto-generated method stub
            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 <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;
        }
    
        /* 获取数据库连接
         * @see javax.sql.DataSource#getConnection()
         */
        @Override
        public Connection getConnection() throws SQLException {
            //如果数据库连接池中的连接对象的个数大于0
            if (listConnections.size()>0) {
                //从listConnections集合中获取一个数据库连接
                final Connection conn = listConnections.removeFirst();
                System.out.println("listConnections数据库连接池大小是" + listConnections.size());
                //返回Connection对象的代理对象
                return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        if(!method.getName().equals("close")){
                            return method.invoke(conn, args);
                        }else{
                            //如果调用的是Connection对象的close方法,就把conn还给数据库连接池
                            listConnections.add(conn);
                            System.out.println(conn + "被还给listConnections数据库连接池了!!");
                            System.out.println("listConnections数据库连接池大小为" + listConnections.size());
                            return null;
                        }
                    }
                });
            }else {
                throw new RuntimeException("对不起,数据库忙");
            }
        }
    
        @Override
        public Connection getConnection(String username, String password)
                throws SQLException {
            return null;
        }
    }
     
  • 相关阅读:
    【权限维持】window几种隐藏技术
    Flash XSS 漏洞实例
    nginx_lua_waf 部署、测试记录
    WAF Bypass数据库特性(Access探索篇)
    WAF Bypass数据库特性(MSsql探索篇)
    WAF Bypass数据库特性(Mysql探索篇)
    WAF Bypass数据库特性(Oracle探索篇)
    WAF Bypass 笔记(SQL注入篇)
    如何关闭Struts2的webconsole.html
    Windows Server 2008 R2 WSUS服务器的详细配置和部署
  • 原文地址:https://www.cnblogs.com/newlangwen/p/8017616.html
Copyright © 2020-2023  润新知