Java 9 Module
This article covers a Java 9 module example. You will modify the custom connection pool with the Java 9 module example. We recommend that you read the following articles before you begin.
1st Module
Create a new Java Project in Eclipse. It doesn't matter what you name your project. Create the following classes in your project.
DBConnectionPool.java
package net.java_school.db.dbpool; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Date; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class DBConnectionPool { private static final Logger logger = Logger.getLogger(DBConnectionPool.class.getName()); // Number of connections currently in use private int checkedOut; // Free Connection List private Vector<Connection> freeConnections = new Vector<Connection>(); // Maximum number of connections private int maxConn; // Waiting time (maximum time to wait when there is no connection in the pool) private int maxWait; // Connection Pool Name private String poolName; // DB Password private String passwd; // DB URL private String URL; // DB UserID private String userID; // Constructor public DBConnectionPool(String poolName, String URL, String userID, String passwd, int maxConn, int initConn, int waitTime) { this.poolName = poolName; this.URL = URL; this.userID = userID; this.passwd = passwd; this.maxConn = maxConn; this.maxWait = waitTime; for (int i = 0; i < initConn; i++) { freeConnections.addElement(newConnection()); } } // Returning Connection // @param con : Connection to return public synchronized void freeConnection(Connection con) { freeConnections.addElement(con); checkedOut--; //Notify thread waiting to get Connection notifyAll(); } // Get Connection @SuppressWarnings("resource") public synchronized Connection getConnection() { Connection con = null; //If Connection is in Free List, get the first of List if (freeConnections.size() > 0) { con = (Connection) freeConnections.firstElement(); freeConnections.removeElementAt(0); try { //If the connection is closed by the DBMS, request again if (con.isClosed()) { logger.log(Level.SEVERE, "Removed bad connection from " + poolName); con = getConnection(); } } //If strange connection occurs, request again catch (SQLException e) { logger.log(Level.SEVERE, "Removed bad connection from " + poolName); con = getConnection(); } } //If Connection is not in Free List, create new else if (maxConn == 0 || checkedOut < maxConn) { con = newConnection(); } if (con != null) { checkedOut++; } return con; } // Get Connection // @param timeout : Maximum Wait Time to Obtain a Connection public synchronized Connection getConnection(long timeout) { long startTime = new Date().getTime(); Connection con; while ((con = getConnection()) == null) { try { wait(timeout * maxWait); } catch (InterruptedException e) {} if ((new Date().getTime() - startTime) >= timeout) { //Wait timeout return null; } } return con; } // Get Connection private Connection newConnection() { Connection con = null; try { if (userID == null) { con = DriverManager.getConnection(URL); } else { con = DriverManager.getConnection(URL, userID, passwd); } logger.info("Created a new connection in pool " + poolName); } catch (SQLException e) { StringBuffer sb = new StringBuffer(); sb.append("Can't create a new connection for "); sb.append(URL); sb.append(" user: "); sb.append(userID); sb.append(" passwd: "); sb.append(passwd); logger.log(Level.SEVERE, sb.toString()); return null; } return con; } }
DBConnectionPoolManager.java
package net.java_school.db.dbpool; import java.sql.Connection; import java.util.Hashtable; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class DBConnectionPoolManager { private static final Logger logger = Logger.getLogger(DBConnectionPoolManager.class.getName()); // To apply the singleton pattern to the DBConnectionPoolManager (keep only one instance), declare it as static static private DBConnectionPoolManager instance; private Vector<String> drivers = new Vector<String>(); private Hashtable<String, DBConnectionPool> pools = new Hashtable<String, DBConnectionPool>(); // Obtaining instance of DBConnectionPoolManager // @return DBConnectionManger static synchronized public DBConnectionPoolManager getInstance() { if (instance == null) { instance = new DBConnectionPoolManager(); } return instance; } // Default Constructor private DBConnectionPoolManager() {} // Send current Connection to Free Connection List // @param name : Pool Name // @param con : Connection public void freeConnection(String name, Connection con) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { pool.freeConnection(con); } logger.info("One Connection of " + name + " was freed"); } // Obtain Open Connection. // Creates a new connection if there are no open connections and the maximum number of connections has not been reached. // Waits for the default wait time when there are no open connections currently and the maximum number of connections is in use. // @param name : Pool Name // @return Connection : The connection or null public Connection getConnection(String name) { DBConnectionPool pool = (DBConnectionPool) pools.get(name); if (pool != null) { return pool.getConnection(10); } return null; } // Create a Connection Pool // @param poolName : Name of Pool to create // @param url : DB URL // @param userID : DB UserID // @param passwd : DB Password private void createPools(String poolName, String url, String userID, String passwd, int maxConn, int initConn, int maxWait) { DBConnectionPool pool = new DBConnectionPool(poolName, url, userID, passwd, maxConn, initConn, maxWait); pools.put(poolName, pool); logger.info("Initialized pool " + poolName); } // Initialization public void init(String poolName, String driver, String url, String userID, String passwd, int maxConn, int initConn, int maxWait) { loadDrivers(driver); createPools(poolName, url, userID, passwd, maxConn, initConn, maxWait); } // JDBC Driver Loading // @param driverClassName : The JDBC driver for the DB you want to use. private void loadDrivers(String driverClassName) { try { Class.forName(driverClassName); drivers.addElement(driverClassName); logger.info("Registered JDBC driver " + driverClassName); } catch (Exception e) { logger.log(Level.SEVERE, "Can't register JDBC driver: " + driverClassName); } } public Hashtable<String,DBConnectionPool> getPools() { return pools; } public int getDriverNumber() { return drivers.size(); } }
ConnectionManager.java
package net.java_school.db.dbpool; import java.sql.Connection; public abstract class ConnectionManager { protected DBConnectionPoolManager poolManager; protected String poolName; public ConnectionManager() { this.poolManager = DBConnectionPoolManager.getInstance(); } public Connection getConnection() { return (poolManager.getConnection(poolName)); } public void freeConnection(Connection con) { poolManager.freeConnection(poolName, con); } public abstract void initPoolManager(String poolName, String driver, String url, String userID, String passwd, int maxConn, int initConn, int maxWait); public int getDriverNumber() { return poolManager.getDriverNumber(); } }
The module-info.java is a module descriptor source file. Create this file in the src directory.
module-info.java
module net.java_school.db.dbpool { requires java.logging; requires transitive java.sql; exports net.java_school.db.dbpool; }
2nd Module
Create a new Java Project in Eclipse. Create the following classes in your project.
OracleConnectionManager.java
package net.java_school.db.dbpool.oracle; import java.io.IOException; import java.net.URL; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import net.java_school.db.dbpool.ConnectionManager; public class OracleConnectionManager extends ConnectionManager { private static final Logger logger = Logger.getLogger(OracleConnectionManager.class.getName()); public OracleConnectionManager() { this.poolName = "oracle"; String configFile = "oracle.properties"; try { Properties prop = readProperties(configFile); String dbServer = prop.getProperty("dbServer"); String port = prop.getProperty("port"); String dbName = prop.getProperty("dbName"); String userID = prop.getProperty("userID"); String passwd = prop.getProperty("passwd"); int maxConn = Integer.parseInt(prop.getProperty("maxConn")); int initConn = Integer.parseInt(prop.getProperty("initConn")); int maxWait = Integer.parseInt(prop.getProperty("maxWait")); String driver = "oracle.jdbc.driver.OracleDriver"; String JDBCDriverType = "jdbc:oracle:thin"; String url = JDBCDriverType + ":@" + dbServer + ":" + port + ":" + dbName; initPoolManager(this.poolName, driver, url, userID, passwd, maxConn, initConn, maxWait); } catch (IOException e) { logger.log(Level.SEVERE, "Error reading properties of " + configFile); throw new RuntimeException(e); } } protected synchronized Properties readProperties(String configFile) throws IOException { ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader(); URL url = currentThreadClassLoader.getResource(configFile); Properties properties = new Properties(); properties.load(url.openStream()); return properties; } @Override public void initPoolManager(String poolName, String driver, String url, String userID, String passwd, int maxConn, int initConn, int maxWait) { this.poolManager.init(poolName, driver, url, userID, passwd, maxConn, initConn, maxWait); } }
module-info.java
module net.java_school.db.dbpool.oracle { requires net.java_school.db.dbpool; exports net.java_school.db.dbpool.oracle; provides net.java_school.db.dbpool.ConnectionManager with net.java_school.db.dbpool.oracle.OracleConnectionManager; }
Add ojdbc6.jar to the project's build path using Add External JARs... button.
The second module depends on the first module.
With the help of Eclipse's code assist feature, you can easily set up dependencies.
Create a properties file for the Oracle database in the src folder.
oracle.properties
############################################ # Database Connection Properties for Oracle ############################################ # Database Server Name OR IP address dbServer = 127.0.0.1 # The port number your DB server listents to. port = 1521 # Database Name dbName = XE # Database User userID = scott # Database Password passwd = tiger # Maximum Connection Number maxConn = 20 # Inital Connection Number initConn = 5 # Maximum Wait Time maxWait = 5
3rd Module
Create a new Java Project in Eclipse. Create the following classes in your project.
MySqlConnectionManager.java
package net.java_school.db.dbpool.mysql; import java.io.IOException; import java.net.URL; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import net.java_school.db.dbpool.ConnectionManager; public class MySqlConnectionManager extends ConnectionManager { private static final Logger logger = Logger.getLogger(MySqlConnectionManager.class.getName()); public MySqlConnectionManager() { this.poolName = "mysql"; String configFile = "mysql.properties"; try { Properties prop = readProperties(configFile); String dbServer = prop.getProperty("dbServer"); String port = prop.getProperty("port"); String dbName = prop.getProperty("dbName"); String userID = prop.getProperty("userID"); String passwd = prop.getProperty("passwd"); int maxConn = Integer.parseInt(prop.getProperty("maxConn")); int initConn = Integer.parseInt(prop.getProperty("initConn")); int maxWait = Integer.parseInt(prop.getProperty("maxWait")); String driver = "com.mysql.jdbc.Driver"; String JDBCDriverType = "jdbc:mysql"; String url = JDBCDriverType + "://" + dbServer + ":" + port + "/" + dbName + "?useUnicode=yes&characterEncoding=UTF-8"; initPoolManager(this.poolName, driver, url, userID, passwd, maxConn, initConn, maxWait); } catch (IOException e) { logger.log(Level.SEVERE, "Error reading properties of " + configFile); throw new RuntimeException(e); } } protected synchronized Properties readProperties(String configFile) throws IOException { ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader(); URL url = currentThreadClassLoader.getResource(configFile); Properties properties = new Properties(); properties.load(url.openStream()); return properties; } @Override public void initPoolManager(String poolName, String driver, String url, String userID, String passwd, int maxConn, int initConn, int maxWait) { this.poolManager.init(poolName, driver, url, userID, passwd, maxConn, initConn, maxWait); } }
Create a properties file for the MySQL database in the src folder.
mysql.properties
############################################ # Database Connection Properties for MySQL ############################################ # Database Server Name OR IP address dbServer = localhost # The port number your DB server listents to. port = 3306 # Database Name dbName = xe # Database User userID = scott # Database Password passwd = tiger # Maximum Connection Number maxConn = 20 # Inital Connection Number initConn = 5 # Maximum Wait Time maxWait = 5
Create a MySQL user and database.
mysql --user=root --password mysql create user 'scott'@'%' identified by 'tiger'; grant all privileges on *.* to 'scott'@'%'; create database xe; exit;
mysql --user=scott --password xe CREATE TABLE DEPT ( DEPTNO DECIMAL(2), DNAME VARCHAR(14), LOC VARCHAR(13), CONSTRAINT PK_DEPT PRIMARY KEY (DEPTNO) ); CREATE TABLE EMP ( EMPNO DECIMAL(4), ENAME VARCHAR(10), JOB VARCHAR(9), MGR DECIMAL(4), HIREDATE DATE, SAL DECIMAL(7,2), COMM DECIMAL(7,2), DEPTNO DECIMAL(2), CONSTRAINT PK_EMP PRIMARY KEY (EMPNO), CONSTRAINT FK_DEPTNO FOREIGN KEY (DEPTNO) REFERENCES DEPT(DEPTNO) ); CREATE TABLE SALGRADE ( GRADE TINYINT, LOSAL SMALLINT, HISAL SMALLINT ); INSERT INTO DEPT VALUES (10,'ACCOUNTING','NEW YORK'); INSERT INTO DEPT VALUES (20,'RESEARCH','DALLAS'); INSERT INTO DEPT VALUES (30,'SALES','CHICAGO'); INSERT INTO DEPT VALUES (40,'OPERATIONS','BOSTON'); INSERT INTO EMP VALUES (7369,'SMITH','CLERK',7902,STR_TO_DATE('17-12-1980','%d-%m-%Y'),800,NULL,20); INSERT INTO EMP VALUES (7499,'ALLEN','SALESMAN',7698,STR_TO_DATE('20-2-1981','%d-%m-%Y'),1600,300,30); INSERT INTO EMP VALUES (7521,'WARD','SALESMAN',7698,STR_TO_DATE('22-2-1981','%d-%m-%Y'),1250,500,30); INSERT INTO EMP VALUES (7566,'JONES','MANAGER',7839,STR_TO_DATE('2-4-1981','%d-%m-%Y'),2975,NULL,20); INSERT INTO EMP VALUES (7654,'MARTIN','SALESMAN',7698,STR_TO_DATE('28-9-1981','%d-%m-%Y'),1250,1400,30); INSERT INTO EMP VALUES (7698,'BLAKE','MANAGER',7839,STR_TO_DATE('1-5-1981','%d-%m-%Y'),2850,NULL,30); INSERT INTO EMP VALUES (7782,'CLARK','MANAGER',7839,STR_TO_DATE('9-6-1981','%d-%m-%Y'),2450,NULL,10); INSERT INTO EMP VALUES (7788,'SCOTT','ANALYST',7566,STR_TO_DATE('13-7-1987','%d-%m-%Y')-85,3000,NULL,20); INSERT INTO EMP VALUES (7839,'KING','PRESIDENT',NULL,STR_TO_DATE('17-11-1981','%d-%m-%Y'),5000,NULL,10); INSERT INTO EMP VALUES (7844,'TURNER','SALESMAN',7698,STR_TO_DATE('8-9-1981','%d-%m-%Y'),1500,0,30); INSERT INTO EMP VALUES (7876,'ADAMS','CLERK',7788,STR_TO_DATE('13-7-1987', '%d-%m-%Y'),1100,NULL,20); INSERT INTO EMP VALUES (7900,'JAMES','CLERK',7698,STR_TO_DATE('3-12-1981','%d-%m-%Y'),950,NULL,30); INSERT INTO EMP VALUES (7902,'FORD','ANALYST',7566,STR_TO_DATE('3-12-1981','%d-%m-%Y'),3000,NULL,20); INSERT INTO EMP VALUES (7934,'MILLER','CLERK',7782,STR_TO_DATE('23-1-1982','%d-%m-%Y'),1300,NULL,10); INSERT INTO SALGRADE VALUES (1,700,1200); INSERT INTO SALGRADE VALUES (2,1201,1400); INSERT INTO SALGRADE VALUES (3,1401,2000); INSERT INTO SALGRADE VALUES (4,2001,3000); INSERT INTO SALGRADE VALUES (5,3001,9999); COMMIT; exit;
module-info.java
module net.java_school.db.dbpool.mysql { requires net.java_school.db.dbpool; exports net.java_school.db.dbpool.mysql; provides net.java_school.db.dbpool.ConnectionManager with net.java_school.db.dbpool.mysql.MySqlConnectionManager; }
Add the MySQL JDBC driver file using the Add External JARs... button.
4th Module
Create a new Java Project in Eclipse. Create the following classes in your project.
GetEmp.java
package net.java_school.test; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import net.java_school.db.dbpool.mysql.MySqlConnectionManager; import net.java_school.db.dbpool.oracle.OracleConnectionManager; public class GetEmp { public static void main(String[] args) { OracleConnectionManager oracleConnectionManager = new OracleConnectionManager(); Connection con = null; PreparedStatement stmt = null; ResultSet rs = null; String sql = "SELECT * FROM EMP"; try { con = oracleConnectionManager.getConnection(); stmt = con.prepareStatement(sql); rs = stmt.executeQuery(); while (rs.next()) { String empno = rs.getString(1); String ename = rs.getString(2); String job = rs.getString(3); String mgr = rs.getString(4); String hiredate = rs.getString(5); String sal = rs.getString(6); String comm = rs.getString(7); String depno = rs.getString(8); System.out.println(empno + " : " + ename + " : " + job + " : " + mgr + " : " + hiredate + " : " + sal + " : " + comm + " : " + depno); } } catch (Exception e) { e.printStackTrace(); } finally { try { rs.close(); } catch (SQLException e) {} try { stmt.close(); } catch (SQLException e) {} oracleConnectionManager.freeConnection(con); } MySqlConnectionManager mysqlConnectionManager = new MySqlConnectionManager(); try { con = mysqlConnectionManager.getConnection(); stmt = con.prepareStatement(sql); rs = stmt.executeQuery(); while (rs.next()) { String empno = rs.getString(1); String ename = rs.getString(2); String job = rs.getString(3); String mgr = rs.getString(4); String hiredate = rs.getString(5); String sal = rs.getString(6); String comm = rs.getString(7); String depno = rs.getString(8); System.out.println(empno + " : " + ename + " : " + job + " : " + mgr + " : " + hiredate + " : " + sal + " : " + comm + " : " + depno); } } catch (Exception e) { e.printStackTrace(); } finally { try { rs.close(); } catch (SQLException e) {} try { stmt.close(); } catch (SQLException e) {} mysqlConnectionManager.freeConnection(con); } System.out.println("Driver Number: " + mysqlConnectionManager.getDriverNumber()); } }
module-info.java
module main.app { requires java.sql; requires net.java_school.db.dbpool.oracle; requires net.java_school.db.dbpool.mysql; uses net.java_school.db.dbpool.oracle.OracleConnectionManager; uses net.java_school.db.dbpool.mysql.MySqlConnectionManager; }
Test
Run GetEmp.java by selecting Run As -- Java Application.
Sep 17, 2019 11:46:41 AM net.java_school.db.dbpool.DBConnectionPoolManager loadDrivers INFO: Registered JDBC driver oracle.jdbc.driver.OracleDriver Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool oracle Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool oracle Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool oracle Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool oracle Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool oracle Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPoolManager createPools INFO: Initialized pool oracle 7369 : SMITH : CLERK : 7902 : 1980-12-17 00:00:00 : 800 : null : 20 7499 : ALLEN : SALESMAN : 7698 : 1981-02-20 00:00:00 : 1600 : 300 : 30 7521 : WARD : SALESMAN : 7698 : 1981-02-22 00:00:00 : 1250 : 500 : 30 7566 : JONES : MANAGER : 7839 : 1981-04-02 00:00:00 : 2975 : null : 20 7654 : MARTIN : SALESMAN : 7698 : 1981-09-28 00:00:00 : 1250 : 1400 : 30 7698 : BLAKE : MANAGER : 7839 : 1981-05-01 00:00:00 : 2850 : null : 30 7782 : CLARK : MANAGER : 7839 : 1981-06-09 00:00:00 : 2450 : null : 10 7788 : SCOTT : ANALYST : 7566 : 1987-07-13 00:00:00 : 3000 : null : 20 7839 : KING : PRESIDENT : null : 1981-11-17 00:00:00 : 5000 : null : 10 7844 : TURNER : SALESMAN : 7698 : 1981-09-08 00:00:00 : 1500 : 0 : 30 7876 : ADAMS : CLERK : 7788 : 1987-07-13 00:00:00 : 1100 : null : 20 7900 : JAMES : CLERK : 7698 : 1981-12-03 00:00:00 : 950 : null : 30 7902 : FORD : ANALYST : 7566 : 1981-12-03 00:00:00 : 3000 : null : 20 7934 : MILLER : CLERK : 7782 : 1982-01-23 00:00:00 : 1300 : null : 10 Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPoolManager freeConnection INFO: One Connection of oracle was freed Sep 17, 2019 11:46:42 AM net.java_school.db.dbpool.DBConnectionPoolManager loadDrivers INFO: Registered JDBC driver com.mysql.jdbc.Driver Sep 17, 2019 11:46:43 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool mysql Sep 17, 2019 11:46:43 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool mysql Sep 17, 2019 11:46:43 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool mysql Sep 17, 2019 11:46:43 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool mysql Sep 17, 2019 11:46:43 AM net.java_school.db.dbpool.DBConnectionPool newConnection INFO: Created a new connection in pool mysql Sep 17, 2019 11:46:43 AM net.java_school.db.dbpool.DBConnectionPoolManager createPools INFO: Initialized pool mysql 7369 : SMITH : CLERK : 7902 : 1980-12-17 : 800.00 : null : 20 7499 : ALLEN : SALESMAN : 7698 : 1981-02-20 : 1600.00 : 300.00 : 30 7521 : WARD : SALESMAN : 7698 : 1981-02-22 : 1250.00 : 500.00 : 30 7566 : JONES : MANAGER : 7839 : 1981-04-02 : 2975.00 : null : 20 7654 : MARTIN : SALESMAN : 7698 : 1981-09-28 : 1250.00 : 1400.00 : 30 7698 : BLAKE : MANAGER : 7839 : 1981-05-01 : 2850.00 : null : 30 7782 : CLARK : MANAGER : 7839 : 1981-06-09 : 2450.00 : null : 10 7788 : SCOTT : ANALYST : 7566 : 1987-06-28 : 3000.00 : null : 20 7839 : KING : PRESIDENT : null : 1981-11-17 : 5000.00 : null : 10 7844 : TURNER : SALESMAN : 7698 : 1981-09-08 : 1500.00 : 0.00 : 30 7876 : ADAMS : CLERK : 7788 : 1987-07-13 : 1100.00 : null : 20 7900 : JAMES : CLERK : 7698 : 1981-12-03 : 950.00 : null : 30 7902 : FORD : ANALYST : 7566 : 1981-12-03 : 3000.00 : null : 20 7934 : MILLER : CLERK : 7782 : 1982-01-23 : 1300.00 : null : 10 Sep 17, 2019 11:46:43 AM net.java_school.db.dbpool.DBConnectionPoolManager freeConnection INFO: One Connection of mysql was freed Driver Number: 2
Command Line Test
Create src, mods, jars folders in the specified directory and copy the files as shown below.
src/
├── net.java_school.db.dbpool
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ ├── DBConnectionPool.java
│ │ ├── DBConnectionPoolManager.java
│ │ └── ConnectionManager.java
│ └── module-info.java
├── net.java_school.db.dbpool.oracle
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── oracle
│ │ └── OracleConnectionManager.java
│ ├── module-info.java
│ └── oracle.properties
├── net.java_school.db.dbpool.mysql
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── mysql
│ │ └── MySqlConnectionManager.java
│ ├── module-info.java
│ └── mysql.properties
mods/
jars/
├── ojdbc6.jar
└── mysql-connector-java-5.1.48.jar
Compile with the following command:
javac -d mods --module-source-path src $(find src -name "*.java")
The above command can only be executed on Unix, macOS and Linux.
The following command can be executed including windows.
javac -d mods --module-source-path src -m main.app,net.java_school.db.dbpool,net.java_school.db.dbpool.oracle,net.java_school.db.dbpool.mysql
The above command should be run from the directory with the following three folders:
$ ls jars mods src
src/
├── net.java_school.db.dbpool
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ ├── DBConnectionPool.java
│ │ ├── DBConnectionPoolManager.java
│ │ └── ConnectionManager.java
│ └── module-info.java
├── net.java_school.db.dbpool.oracle
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── oracle
│ │ └── OracleConnectionManager.java
│ ├── module-info.java
│ └── oracle.properties
├── net.java_school.db.dbpool.mysql
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── mysql
│ │ └── MySqlConnectionManager.java
│ ├── module-info.java
│ └── mysql.properties
mods/
├── net.java_school.db.dbpool
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ ├── DBConnectionPool.class
│ │ ├── DBConnectionPoolManager.class
│ │ └── ConnectionManager.class
│ └── module-info.class
├── net.java_school.db.dbpool.oracle
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── oracle
│ │ └── OracleConnectionManager.class
│ └── module-info.class
├── net.java_school.db.dbpool.mysql
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── mysql
│ │ └── MySqlConnectionManager.class
│ └── module-info.class
jars/
├── ojdbc6.jar
└── mysql-connector-java-5.1.48.jar
Class files are created in the mods folder, but Java property files are not copied to the mods folder.
Before testing, copy the Java property file from the src folder and paste it in the same location as the module descriptor created in the mods folder.
src/
├── net.java_school.db.dbpool
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ ├── DBConnectionPool.java
│ │ ├── DBConnectionPoolManager.java
│ │ └── ConnectionManager.java
│ └── module-info.java
├── net.java_school.db.dbpool.oracle
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── oracle
│ │ └── OracleConnectionManager.java
│ ├── module-info.java
│ └── oracle.properties
├── net.java_school.db.dbpool.mysql
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── mysql
│ │ └── MySqlConnectionManager.java
│ ├── module-info.java
│ └── mysql.properties
mods/
├── net.java_school.db.dbpool
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ ├── DBConnectionPool.class
│ │ ├── DBConnectionPoolManager.class
│ │ └── ConnectionManager.class
│ └── module-info.class
├── net.java_school.db.dbpool.oracle
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── oracle
│ │ └── OracleConnectionManager.class
│ ├── module-info.class
│ └── oracle.properties
├── net.java_school.db.dbpool.mysql
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── mysql
│ │ └── MySqlConnectionManager.class
│ ├── module-info.class
│ └── mysql.properties
jars/
├── ojdbc6.jar
└── mysql-connector-java-5.1.48.jar
Run with the following command:
java -p mods:jars -m main.app/net.java_school.test.GetEmp
Create instance using ServiceLoader
Modify the descriptors of modules except net.java_school.db.dbpool as follows.
module main.app { requires net.java_school.db.dbpool; uses net.java_school.db.dbpool.ConnectionManager; }
module net.java_school.db.dbpool.oracle { requires net.java_school.db.dbpool; provides net.java_school.db.dbpool.ConnectionManager with net.java_school.db.dbpool.oracle.OracleConnectionManager; }
module net.java_school.db.dbpool.mysql { requires net.java_school.db.dbpool; provides net.java_school.db.dbpool.ConnectionManager with net.java_school.db.dbpool.mysql.MySqlConnectionManager; }
Modify GetEmp.java as follows.
package net.java_school.test; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ServiceLoader; import net.java_school.db.dbpool.ConnectionManager; public class GetEmp { public static void main(String[] args) { Iterable<ConnectionManager> managers = ServiceLoader.load(ConnectionManager.class); for (ConnectionManager manager : managers) { Connection con = null; PreparedStatement stmt = null; ResultSet rs = null; String sql = "SELECT * FROM EMP"; try { con = manager.getConnection(); stmt = con.prepareStatement(sql); rs = stmt.executeQuery(); while (rs.next()) { String empno = rs.getString(1); String ename = rs.getString(2); String job = rs.getString(3); String mgr = rs.getString(4); String hiredate = rs.getString(5); String sal = rs.getString(6); String comm = rs.getString(7); String depno = rs.getString(8); System.out.println(empno + " : " + ename + " : " + job + " : " + mgr + " : " + hiredate + " : " + sal + " : " + comm + " : " + depno); } } catch (Exception e) { e.printStackTrace(); } finally { try { rs.close(); } catch (SQLException e) {} try { stmt.close(); } catch (SQLException e) {} manager.freeConnection(con); } System.out.println("Driver Number: " + manager.getDriverNumber()); } } }
Create only instances of filtered classes
Add the following to the net.java_school.db.dbpool module.
package net.java_school.db.dbpool; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Oracle { public boolean value() default true; }
Modify the class declaration of OracleConnectionManager.java as below.
import net.java_school.db.dbpool.Oracle; @Oracle public class OracleConnectionManager extends ConnectionManager { //.. }
Modify GetEmp.java as follows.
package net.java_school.test; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ServiceLoader; import net.java_school.db.dbpool.ConnectionManager; import net.java_school.db.dbpool.Oracle; public class GetEmp { public static void main(String[] args) { ServiceLoader<ConnectionManager> managers = ServiceLoader.load(ConnectionManager.class); ConnectionManager manager = managers.stream() .filter(provider -> isOracle(provider.type())) .map(ServiceLoader.Provider::get).findAny().get(); Connection con = null; PreparedStatement stmt = null; ResultSet rs = null; String sql = "SELECT * FROM EMP"; try { con = manager.getConnection(); stmt = con.prepareStatement(sql); rs = stmt.executeQuery(); while (rs.next()) { String empno = rs.getString(1); String ename = rs.getString(2); String job = rs.getString(3); String mgr = rs.getString(4); String hiredate = rs.getString(5); String sal = rs.getString(6); String comm = rs.getString(7); String depno = rs.getString(8); System.out.println(empno + " : " + ename + " : " + job + " : " + mgr + " : " + hiredate + " : " + sal + " : " + comm + " : " + depno); } } catch (Exception e) { e.printStackTrace(); } finally { try { rs.close(); } catch (SQLException e) {} try { stmt.close(); } catch (SQLException e) {} manager.freeConnection(con); } System.out.println("Driver Number: " + manager.getDriverNumber()); } private static boolean isOracle(Class<?> clazz) { return clazz.isAnnotationPresent(Oracle.class) && clazz.getAnnotation(Oracle.class).value() == true; } }
Source: https://github.com/kimjonghoon/java-module-test
References