- Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathConnectionPoolManager.java
More file actions
Latest commit
140 lines (131 loc) · 6.92 KB
/
Copy pathConnectionPoolManager.java
File metadata and controls
140 lines (131 loc) · 6.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
packageconnection_util;
importjava.lang.reflect.Proxy;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.SQLException;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.concurrent.ArrayBlockingQueue;
importjava.util.concurrent.BlockingQueue;
publicfinalclassConnectionPoolManager {
/* Извлекаем данные из application.properties */
privatestaticfinalStringPASSWORD_KEY = "db.password";
privatestaticfinalStringUSERNAME_KEY = "db.username";
privatestaticfinalStringURL_KEY = "db.url";
privatestaticfinalStringPOOL_SIZE_KEY = "db.pool.size";
/* Задаем размер пула по-умолчанию */
privatestaticfinalIntegerDEFAULT_POOL_SIZE = 10;
/*
Потокобезопасная блокирующая очередь для
хранения наших прокси - соединений
*/
privatestaticBlockingQueue<Connection> pool;
/* Список наших реальных соединений */
privatestaticList<Connection> sourceConnections;
static {
loadDriver();
initConnectionPool();
}
/* Приватный конструктор данного класса */
privateConnectionPoolManager() {
}
privatestaticvoidinitConnectionPool() {
/* Извлекаем значение размера будущего пула соединений из файла*/
StringpoolSize = PropertiesUtil.get(POOL_SIZE_KEY);
/*
Существует вероятность, что в ходе извлечения данных из файла
свойств, либо в момент преобразования данных в int может произойти
ошибка (вот какая интересно?). Для того чтобы этого избежать
воспользуемся тернарным оператором и как вариант подставим дефолтный
размер пула.
*/
intsize = poolSize == null ? DEFAULT_POOL_SIZE : Integer.parseInt(poolSize);
/* Создаем очередь для хранения наших прокси - соединений */
pool = newArrayBlockingQueue<>(size);
/*
Создаем список для хранения наших реальных соединений.
К нему мы обратимся в момент закрытия всех реальных
соединений.
*/
sourceConnections = newArrayList<>(size);
/*
В цикле создаем реальное и прокси - соединение с базой.
Помещаем и то и другое в свои коллекции данных.
*/
for (inti = 0; i < size; i++) {
Connectionconnection = openConnection();
/*
В общем случае прокси-объект - это объект, который служит
посредником для доступа к другому объекту, каким-то образом
меняя свойства или поведение этого объекта.
Так что со стороны клиента (т.е. объекта-пользователя)
поведение выглядит несколько не так, как было бы при
непосредственном доступе.
Используется также в случаях, когда прямой доступ к
используемому объекту по какой-то причине невозможен.
('прокси - объект' - паттерн проектирования)
Самое простое — использовать java.lang.reflect.Proxy,
который является частью JDK. Этот класс может создать
прокси-класс или напрямую его инстанс.
Пользоваться прокси, встроенным в Java, очень просто.
Все что нужно — реализовать java.lang.InvocationHandler,
чтобы прокси-объект мог его вызывать.
Интерфейс InvocationHandler крайне прост и содержит только
один метод: invoke(). При его вызове, аргументы содержат
проксируемый оригинальный объект, вызванный метод
(как отражение объекта Method) и массив объектов исходных
аргументов.
*/
ConnectionproxyConnection = (Connection) Proxy.newProxyInstance(
ConnectionPoolManager.class.getClassLoader(),
newClass[]{Connection.class},
(proxy, method, args) -> method.getName().equals("close")
? pool.add((Connection) proxy)
: method.invoke(connection, args));
pool.add(proxyConnection);
sourceConnections.add(connection);
}
}
/* Методы для получения прокси - соединения из пула */
publicstaticConnectiongetConnectionFromPool() {
try {
returnpool.take();
} catch (InterruptedExceptione) {
thrownewRuntimeException(e);
}
}
/*
Приватный метод для создания соединения с базой данных
сделанный для защиты от случайного создания соединения
сверх размера пула.
*/
privatestaticConnectionopenConnection() {
try {
returnDriverManager.getConnection(
PropertiesUtil.get(URL_KEY),
PropertiesUtil.get(USERNAME_KEY),
PropertiesUtil.get(PASSWORD_KEY)
);
} catch (SQLExceptione) {
thrownewRuntimeException(e);
}
}
/* Загружаем драйвер PostgreSQL */
privatestaticvoidloadDriver() {
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundExceptione) {
thrownewRuntimeException(e);
}
}
/* Метод закрывает реальные соединения с базой данных всего пула */
publicstaticvoidclosePool() {
try {
for (ConnectionsourceConnection : sourceConnections) {
sourceConnection.close();
}
} catch (SQLExceptione) {
thrownewRuntimeException(e);
}
}
}