首页 > 其他 > 详细

使用静态工厂方法创建连接池(关于代理和包装的使用)

时间:2014-02-10 16:38:27      阅读:324      评论:0      收藏:0      [点我收藏+]

创建Connection的过程是非常耗时的,为了保证Conection可以重用。应该将Connection进行池管理。

使用静态工厂方法管理一个唯一的连接:

bubuko.com,布布扣
package cn.itcast.utils;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Enumeration;
/**
 * 用静态工厂方法管理一个唯一的可重用的连接
 */
public class ConnUtils {
    private static Connection con;
    //在静态代码块中创建与数据库的连接
    static{
        try{
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql:///db909?characterEncoding=UTf8";
            con = DriverManager.getConnection(url,"root","1234");
        }catch(Exception e){
            throw new RuntimeException(e.getMessage(),e);
        }
    }
    //使用一个静态方法-静态工厂方法,返回connection实例
    public static Connection getCon(){
        return con;
    }
}
bubuko.com,布布扣

连接池的实现

为什么要有连接池?

1:维护多个连接。必须要保证每一个线程获取到的是不同的connection对象。

2:提供一个方法可以回收连接。

以下是最基本的实现,但是实际都不这么用的代码段:

bubuko.com,布布扣
package cn.itcast.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;
public class ConnUtils2 {
    //声明一个容器,放所有声明的连接Connection
    private static List<Connection> pool = new ArrayList<Connection>();
    static{
        try{
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql:///db909?characterEncoding=UTf8";
            for(int i=0;i<3;i++){
                //创建三个连接
                Connection con = DriverManager.getConnection(url,"root","1234");
                //将这个三个连接放到pool中去
                pool.add(con);
            }
            System.err.println("连接是:"+pool);
        }catch(Exception e){
            throw new RuntimeException(e.getMessage(),e);
        }
    }
    public static Connection getCon(){
        synchronized (pool) {
            Connection con = pool.remove(0);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.err.println("还有:"+pool.size());
            return con;
        }
    }
    //手工的还连接
    public static void back(Connection con){
        System.err.println("还连接:"+con);
        pool.add(con);
    }
}
bubuko.com,布布扣

6、在代码中调用close时也可以还连接,对close方法进行修改。

动态代理,作用:

1:对某个方法增强。

2:在不污染源类的情况下,修改原类的行为。

代理类,与被代理类,两个不同的实体。

要求:所有被代理的类,都必须要拥有一个接口。本质上是对方法进行修改,但其实它是通过反射执行的某个方法。

动态代理的核心类:

Proxy – 用于创建给定接口的子类,在内存中动态的创建。$Proxy0.此类只使用一次。

InovocationHandler – 执行句柄。在执行时可以获取被代理类的所有反射。用户的每一次调用都会被这个句柄拦截到。

bubuko.com,布布扣
package cn.itcast.demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyDemo2 {
    public static void main(String[] args) throws Exception {
        final GDG o = new GDG(4);
        System.err.println("1:声明被代理的对象"+o+","+o.getClass());
        Object proxyedObj = 
                Proxy.newProxyInstance(
                        ProxyDemo2.class.getClassLoader(),
                        new Class[]{IGDG.class},
                        new InvocationHandler() {
                            public Object invoke(Object proxy, Method method, Object[] args)
                                    throws Throwable {
                                System.err.println("5:正在调用的方法是:"+method.getName());//talk
                                Object returnValue = method.invoke(o,args);
                                System.err.println("6:通过反射调用目标(被代理类)类的方法成功,返回值是:"+returnValue);
                                return "你不好";
                            }
                        }
                    );
        
        System.err.println("2:代理类创建完成:"+proxyedObj.getClass());
        System.err.println("3:强转成IGDG接口");
        IGDG o2 = (IGDG) proxyedObj;
        System.err.println("4:调用代理类的talk方法");
        String back = o2.talk();
        System.err.println("7:方法都调用完成\t"+back);
    }
}
bubuko.com,布布扣
bubuko.com,布布扣
package cn.itcast.demo;
public class GDG implements IGDG {
    int nu = 0;
    public GDG(int nm) {
        nu=nm;
    }
    public String talk(){
        System.err.println("5.1:开始讲了....."+nu);
        return "你好:"+nu;
    }
}
bubuko.com,布布扣
package cn.itcast.demo;

public interface IGDG {
    String talk();
}

代理的任务

1:在内存中创建某个接口的子类。

2:拦截所有在代理上执行的方法。( 除了getClass方法。)

用动态代理书写连接池

设计:

   代理的目标:原生的connection。

   代理的目的:修改close方法,让close方法不可以关闭连接,且主动收回连接。

通过动态代理,和线程通讯:

   1:对Connection进行代理。

2:在获取Connection时,通过同步,如果没有连接时,就让线程进入等待池。

3:修改close方法,且在还了连接以后唤醒正在等待的线程。

bubuko.com,布布扣
package cn.itcast.utils;
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.util.ArrayList;
import java.util.List;
public class ConnUtils4 {
    //第一步:声明连接池维护所有的连接
    private static List<Connection> pool = new ArrayList<Connection>();
    //第二步:静态代码块中创建多个连接
    static{
        try{
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql:///db909?characterEncoding=UTF8";
            for(int i=0;i<3;i++){
                final Connection con = DriverManager.getConnection(url,"root","1234");//com.mysql.jdbc.Jdbc4Connection@
                //对con对象进行动态代理生成Connectioin接口的子类,同时也是con的代理类。
                Object proxyedCon = 
                        Proxy.newProxyInstance(
                                ConnUtils4.class.getClassLoader(),
                                new Class[]{Connection.class},
                                //声明执行句柄,只对close方法设置拦截
                                new InvocationHandler() {
                                    public Object invoke(Object proxy, Method method, Object[] args)
                                            throws Throwable {
                                        if(method.getName().equals("close")){
                                            System.err.println("有人想关闭连接,不能关,还连接");
                                            //将proxy再加到pool中,这个proxy就是proxyedCon
                                            synchronized (pool) {//将代理对象,再重新加回到pool中来,这个proxy参数,就是this.
                                                pool.add((Connection) proxy);
                                                pool.notify();
                                            }
                                            return null;
                                        }else{
                                            System.err.println("放行"+method.getName());
                                            return method.invoke(con, args);//通过反射执行con即被代理对象的方法。
                                        }
                                    }
                                });
                //一定要将代理对象添加到池中去。
                pool.add((Connection) proxyedCon);
            }
        }catch(Exception e){
            throw new RuntimeException(e.getMessage(),e);
        }
    }
    /**
     * 提供一个静态工厂方法返回一个连接
     */
    public static Connection getCon(){
        synchronized (pool) {
            if(pool.size()==0){
                try {
                    pool.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return getCon();
            }
            Connection con = pool.remove(0);//返回一个代理的connection对象
               System.err.println("还有几个:"+pool.size());
            return con;
        }
    }
}
bubuko.com,布布扣

优化版:

通过类加载器读取一个资源文件:

SomeClass.class.getResource(xxx) – 获取与SomeClass字节码同一个目录下的xxx文件。

SomeClass.class.getClassLoader().getResource(“xxxx”); - 获取classpath根下上的xxx文件。

1:将url,driver,name,pwd写到一个配置文件中去。-properties

2:通过LinkedList来维护一个池。

bubuko.com,布布扣
package cn.itcast.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
public class ConnUtils3 {
    private static LinkedList<Connection> pool = new LinkedList<Connection>();
    static{
        try {
            //声明资源器类 - 
            Properties prop = new Properties();
            //获取这个文件的路径
            URL url = ConnUtils3.class.getClassLoader().getResource("jdbc.properties");
            String path = url.getPath();
            //为了防止有中文或是空格
            path = URLDecoder.decode(path,"UTf-8");
            File file = new File(path);
            //加载jdbc.properties这个文件
            prop.load(new FileInputStream(file));
            //获取信息
            String driver = prop.getProperty("driver");
            Class.forName(driver);
            String jdbcurl = prop.getProperty("url");
            String nm = prop.getProperty("name");
            String pwd = prop.getProperty("pwd");
            //创建三个原生的连接,都将它们代理
            String poolSize = prop.getProperty("poolSize");
            int size = Integer.parseInt(poolSize);
            for(int i=0;i<size;i++){
                final Connection con = DriverManager.getConnection(jdbcurl,nm,pwd);
                //对con进行动态代理
                Object proxyedObj = 
                        Proxy.newProxyInstance(ConnUtils3.class.getClassLoader(),
                                    new Class[]{Connection.class},
                                    new InvocationHandler() {
                                        public Object invoke(Object proxy, Method method, Object[] args)
                                                throws Throwable {
                                            //是否是close方法
                                            if(method.getName().equals("close")){
                                                synchronized (pool) {
                                                    pool.addLast((Connection) proxy);
                                                    pool.notify();
                                                }
                                                return null;//如果调用的是close则不会调用被代理类的方法。
                                            }
                                            return method.invoke(con, args);
                                        }
                                    });
                //将代理对象放到pool中
                pool.add((Connection) proxyedObj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static Connection getConn(){
        synchronized (pool) {
            if(pool.size()==0){
                try {
                    pool.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return getConn();
            }else{
                Connection con = pool.removeFirst();
                System.err.println("还有几个:"+pool.size());
                return con;
            }
        }
    }
    
    
}
bubuko.com,布布扣

再说连接池的作用

1:维护多个连接。

在初始化时创建List,将多个连接放到List中去.

2:可以在close时回收连接

对Connection进行动态代理,

对close方法进行拦截。

标准连接池的实现

1:实现dataSource接口。

2:声明一个集合类用于管理多个连接。

3:必须要拥有一种能力,回收连接。

4:必须要实现一个方法,getConnection以获取一个连接。

5:实现DataSource接口的类,一般不能拥有static池对象。List.

6:在一个程序中,要求只拥有一个DataSource实例就可以了。

简单实现:

bubuko.com,布布扣
    // 声明一个连接池
    private LinkedList<Connection> pool = new LinkedList<Connection>();

    // 在初始化这个DataSourc的子类时在构造方法设置多个连接
    public DBpool() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/contacts?useUnicode=true&characterEncoding=UTF8";
            for (int i = 0; i < 3; i++) {
                Connection con = DriverManager.getConnection(url,"root","admin");
                pool.add(con);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        return pool.removeFirst();
    }
bubuko.com,布布扣

通过代理进行改造:

bubuko.com,布布扣
package javaee.datasource;

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.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;

import javax.sql.DataSource;

public class DBpool implements DataSource {
    // 声明一个连接池
    private LinkedList<Connection> pool = new LinkedList<Connection>();

    // 在初始化这个DataSourc的子类时在构造方法设置多个连接
    public DBpool() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/contacts?useUnicode=true&characterEncoding=UTF8";
            for (int i = 0; i < 3; i++) {
                final Connection con = DriverManager.getConnection(url, "root",
                        "admin");

                Object proxyedConn = Proxy.newProxyInstance(
                        DBpool.class.getClassLoader(),
                        new Class[] { Connection.class },
                        new InvocationHandler() {

                            @Override
                            public Object invoke(Object proxyedConnection,
                                    Method method, Object[] args)
                                    throws Throwable {
                                if (method.getName().equals("close")) {
                                    synchronized (pool) {
                                        pool.addLast((Connection) proxyedConnection);
                                        pool.notify();
                                    }
                                    return null;
                                }

                                // 目标返回值
                                Object returnValue = method.invoke(con, args);

                                return returnValue;
                            }
                        });
                pool.add((Connection) proxyedConn);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        synchronized (pool) {
            if (pool.size() == 0) {
                try {
                    pool.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return getConnection();
            }
        }
        Connection con = pool.removeFirst();
        System.err.println("size:" + pool.size());
        return con;

    }
                //...
}
bubuko.com,布布扣

要求你自己实现一个类MyInputStream读取文件,且不能抛出异常(认识包装)

bubuko.com,布布扣
package javaee.wrapper;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class TestDemo {
    public static void main(String[] args) throws Exception {
        InputStream is=new MyinputStream("d:/a.txt");
        byte[] bt=new byte[1024];
        int len=0;
        while((len=is.read(bt))!=-1){
            String s=new String(bt,0,len);
            System.err.println(s);
        }
        is.close();
    }
}
package javaee.wrapper;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

class MyinputStream extends InputStream {
    private InputStream is;

    public MyinputStream(String path) {
        try {
            is = new FileInputStream(path);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public int read(byte[] b) {
        int i = -1;
        try {
            i = is.read(b);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return i;
    }

    public void close() {
        try {
            is.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public int read() throws IOException {
        // TODO Auto-generated method stub
        return 0;
    }
}
bubuko.com,布布扣

以下通过包装实现对close方法的修改,以回收连接

1:实现Connection接口,拥有一个Connection的成员。

2:修改close方法。

3:其他的方法都调用成员变量的connection。

实现的部分代码:

bubuko.com,布布扣
public class DBpool_wrapper implements DataSource {
    // 声明一个连接池
    private LinkedList<Connection> pool = new LinkedList<Connection>();

    // 在初始化这个DataSourc的子类时在构造方法设置多个连接
    public DBpool_wrapper() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/contacts?useUnicode=true&characterEncoding=UTF8";
            for (int i = 0; i < 3; i++) {
                Connection con = DriverManager.getConnection(url, "root",
                        "admin");
                MyConn conn = new MyConn(con);
                pool.add(conn);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public Connection getConnection() {
        synchronized (pool) {
            if (pool.size() == 0) {
                try {
                    pool.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return getConnection();
            }
            Connection con = pool.removeFirst();
            System.err.println("size:" + pool.size());
            return con;
        }
    }

    public class MyConn implements Connection {
        private Connection conn;

        // 通过构造接收MySql的connection的对象JDBC4Connection@8888
        public MyConn(Connection con) {
            this.conn = con;
        }

        public void close() throws SQLException {
            synchronized (pool) {
                System.err.println("有人还连接:" + this);
                pool.add(this);
                pool.notify();
            }
        }
    }
}
bubuko.com,布布扣

用包装处理get方式的乱码:

bubuko.com,布布扣
package javaee.utils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.apache.taglibs.standard.lang.jstl.ValueSuffix;

public abstract class BaseServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        // getparamters
        String methodName = req.getParameter("cmd");
        // 通过反射调用子类的方法
        try {
            Method method = this.getClass().getMethod(methodName,
                    HttpServletRequest.class, HttpServletResponse.class);
            MyServletRequest myreq = new MyServletRequest(req);
            method.invoke(this, myreq, resp);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw new RuntimeException(e.getMessage(), e);
        }
    }

}

class MyServletRequest extends HttpServletRequestWrapper {
    HttpServletRequest req;

    public MyServletRequest(HttpServletRequest request) {
        super(request);
        this.req = request;
    }

    public String getParameter(String name) {
        // TODO Auto-generated method stub
        String value = req.getParameter(name);
        if (req.getMethod().equals("GET")) {
            System.err.println("Decode");
            try {
                value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return value;
    }

    public String[] getParameterValues(String name) {
        // TODO Auto-generated method stub
        String[] value = req.getParameterValues(name);
        if (req.getMethod().equals("GET")) {
            System.err.println("Decode[]");
            try {
                for (int i = 0; i < value.length; i++) {
                    value[i] = new String(value[i].getBytes("ISO-8859-1"),
                            req.getCharacterEncoding());

                }
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return value;
    }

    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> map = req.getParameterMap();
        if (req.getMethod().equals("GET")) {
            System.err.println("Decode_Map");
            Iterator<String[]> it = map.values().iterator();
            while (it.hasNext()) {
                String[] ss = it.next();
                for (int i = 0; i < ss.length; i++) {
                    try {
                        ss[i] = new String(ss[i].getBytes("ISO-8859-1"),
                                req.getCharacterEncoding());
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            }
            
        }
        return map;
    }
}
bubuko.com,布布扣

7、小总结

1:代理或是包装都是对某个类的方法进行增强。

代理:必须要根据给定的接口,在内存中创建这个接口的子类。$Proxy0。

包装:不需要接口,但声明声明一个类,变成被包装类的子类,同时拥有一个被包装类的成员。

2:代理基本代码:

bubuko.com,布布扣
Object proxyedObj = 
    Proxy.newProxyInstance(ClassLoader,
                           class[]{被代理的类的接口数组.class},
                           new InvocationHandler(){//执行句柄
                                  public Object invode(Object 代理,Method 方法反射,object[] args){
                                          Reutrn method.invode(被代理类,args);
                             }
                           }
bubuko.com,布布扣

3:包装:

如果一个类是某个类的包装类,则:

A extends B{

Privet B b;

}

4:什么情况下,使用包装,什么情况下使用代理

如果官方(SUN)提供了包装类适配器,则应该优先使用包装。如HttpServletRequest,它的包装类就是HtpServletRequestWraper.

如果官方没有提供包装类的适配器,则可以使用动态代理。如Connection。

5:我们已经学习过的类中哪些是包装模式:

GenericServlet- 包装模式。

public abstract class GenericServlet

implements Servlet, ServletConfig, java.io.Serializable

private transient ServletConfig config;

IO

New BufferedReader(New FileReader(new FileInpjutStreamRreader(new FileInputSteam()));

使用静态工厂方法创建连接池(关于代理和包装的使用)

原文:http://www.cnblogs.com/sunhan/p/3542131.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!