代理模式

需求:对系统中已有的某个类的功能,进行扩展(增强)

     要求:在不修改源码的情况下,对已有的功能进行增强

     

静态代理

抽象接口:保证包含增强功能的对象和原有功能的对象,对外提供相同的方法

目标对象:封装了原有功能

代理对象:封装了增强功能和原有功能(通过持有一个目标对象的引用实现)

 问题:代码不够灵活,产生大量冗余工作

动态代理

动态代理的实现API:

Proxy :

帮助程员产生代理对象,提供产生代理类和代理对象的静态方法

      InvocationHandler :

句柄接口,拦截到,所有代理对象调用的方法(所有代理对象调用的方法,都可以被

InvocationHandler拦截到)

模拟实现数据库连接池

 

数据库的操作:考虑性能问题

频繁的连接和断开数据,本身很消耗资源(操作数据的性能)

---对数据库连接对象,进行池管理(由池中获得资源,用完之后将资源再次放入)

数据库连接工具 java 数据库连接工具推荐_封装

 

连接池的具体实现:

 

1 创建一个集合对象,封装n个Connection对象

 

2 定义获得连接

 

3 和归还连接的功能

实现代码:



1 public class DBPoolUtils {
 2     private static String driver;
 3     private static String url;
 4     private static String username;
 5     private static String password;
 6     private static int maxconn;//线程池最大的连接数
 7     
 8     //定义一个集合表示线程池
 9     static List<Connection> list=new ArrayList<Connection>();
10     //类加载的时候就初始化,创建好连接对象
11     static{
12         Properties properties=new Properties();
13         try {
14             //读取配置文件信息
15             properties.load(DBPoolUtils.class.getResourceAsStream("mysql.properties"));
16             driver=properties.getProperty("driver");
17             url=properties.getProperty("url");
18             username=properties.getProperty("username");
19             password=properties.getProperty("password");
20             maxconn=Integer.parseInt(properties.getProperty("maxconn"));
21             Class.forName(driver);
22             /*
23              * 创建连接对象
24              * 因为当用户关闭的时候要把线程连接对象还到线程池中,
25              * 所有拿到的对象与还回来的对象都应该是代理对象。
26              * 对close()方法进行拦截,把原来断开连接改成将线程连接对象还到连接池
27              */            
28             for (int i = 0; i < maxconn; i++) {
29                 final Connection conn=DriverManager.getConnection(url, username, password);
30                 //创建代理对象
31                 Object connProxy=Proxy.newProxyInstance(
32                         DBPoolUtils.class.getClassLoader(),//自定义类的类加载器
33                         new Class<?>[]{Connection.class},//实现的接口的class文件数组
34                         new InvocationHandler() {//匿名内部类实现InvocationHandler
35                             
36                             @Override
37                             public Object invoke(
38                                     Object proxy,//代理对象
39                                     Method method,//代理对象实现接口中调用的方法
40                                     Object[] args//代理对象实现接口中调用的方法中的参数
41                                     )throws Throwable {
42                                 //拦截close()方法,将原来的断开连接改为还回连接池,即:将当前的代理对象加到线程池中
43                                 String methodName=method.getName();
44                                 if ("close".equals(methodName)) {
45                                     list.add((Connection) proxy);
46                                     //唤醒等待的线程
47                                     synchronized (list) {
48                                         list.notifyAll();
49                                     }
50                                 }
51                                 //放行:调用原来的对象方法
52                                 Object obj=method.invoke(conn, args);    
53                                 return obj;
54                             }
55                         });
56                 //将创建好的代理线程对象加线程池
57                 list.add((Connection) connProxy);
58             }
59         } catch (IOException e) {
60             e.printStackTrace();
61         } catch (ClassNotFoundException e) {
62             e.printStackTrace();
63         } catch (SQLException e) {
64             e.printStackTrace();
65         }        
66     }
67     /**
68      * 对外提供一个连接对象
69      * @return
70      */
71     public static Connection getConnection(){
72         //当线程池中没有连接对象的时候,让线程等待,而不报异常,等待其他线程返回时再唤醒
73         synchronized (list) {
74             if (list.size()==0) {
75                 try {
76                     list.wait();
77                 } catch (InterruptedException e) {
78                     e.printStackTrace();
79                 }
80             }
81         }        
82         //每次从线程池中取出第一个线程
83         Connection conn=list.remove(0);
84         System.out.println("剩余:"+list.size());
85         return conn;
86     }
87 }