JavaBank 예제 모듈화
이 글은 자바 은행 예제를 모듈화하는 과정을 다룬다.
자바 은행 소스에 내려받는다.
git clone https://github.com/kimjonghoon/JavaBank
오라클 JDBC 드라이버와 SLF4J의 Maven central 링크를 클릭해서 내려받은 최신 버전의 slf4j-api 와 slf4j-simple 을 lib/ 폴더에 복사한다.
src/
├── net
│ └── java_school
│ └── bank
│ ├── Account.java
│ ├── Bank.java
│ ├── BankDao.java
│ ├── BankUi.java
│ ├── MyBank.java
│ ├── MyBankDao.java
│ └── Transaction.java
├── simplelogger.properties
lib/
├── ojdbc6.jar
├── slf4j-api-1.7.30.jar
└── slf4j-simple-1.7.30.jar
SCOTT 계정에서 은행 계좌 테이블과 거래명세 테이블, 그리고 입금과 출금 시 거래명세 테이블에 입출금 정보를 인서트하는 트리거를 생성한다.
create table bankaccount ( accountno varchar2(50), owner varchar2(20) not null, balance number, kind varchar2(10), constraint PK_BANKACCOUNT primary key(accountno), constraint CK_BANKACCOUNT_NORMAL CHECK (balance >= CASE WHEN kind='NORMAL' THEN 0 END), constraint CK_BANKACCOUNT_KIND CHECK (kind in ('NORMAL', 'MINUS')) ); create table transaction ( transactiondate timestamp, kind varchar2(10), amount number, balance number, accountno varchar2(50), constraint FK_TRANSACTION FOREIGN KEY(accountno) REFERENCES bankaccount(accountno) ); create or replace trigger bank_trigger after insert or update of balance on bankaccount for each row begin if :new.balance > :old.balance then insert into transaction values ( systimestamp, 'DEPOSIT', :new.balance - :old.balance, :new.balance, :old.accountno ); end if; if :new.balance < :old.balance then insert into transaction values ( systimestamp, 'WITHDRAW', :old.balance - :new.balance, :new.balance, :old.accountno ); end if; end; /
모듈화하기 전 프로그램이 동작하는지 확인한다.
윈도에서 테스트
컴파일
C:\ Command Promptmkdir out set classpath=lib\slf4j-api-1.7.30.jar javac -d out src\net\java_school\bank\*.java
프로퍼티 파일 복사
C:\ Command Promptcopy src\simplelogger.properties out\
실행
C:\ Command Promptset classpath=lib\slf4j-api-1.7.30.jar;lib\slf4j-simple-1.7.30.jar;lib\ojdbc6.jar;out java net.java_school.bank.BankUi
리눅스에서 테스트
컴파일
CP=lib/slf4j-api-1.7.30.jar javac -cp $CP -d out -sourcepath src $(find src -name "*.java")
프로퍼티 파일 복사
cp src/simplelogger.properties out/
실행
CP+=:lib/slf4j-simple-1.7.30.jar CP+=:lib/ojdbc6.jar java -cp $CP:out net.java_school.bank.BankUi
모듈화를 진행하기 전에 다음을 실행하여 자바 은행이 의존하는 외부 라이브러리를 확인한다.
jdeps -summary -cp lib/*.jar out
.. out -> lib/slf4j-api-1.7.30.jar ..
자바 은행이 slf4j-api-1.7.30.jar를 의존함을 확인했다.
이와 같은 라이브러리는 모듈 패스에 추가한다.
모듈화
자바 은행에 사용할, 모듈화된 사용자 정의 커넥션 풀을 내려받는다.
git clone https://github.com/kimjonghoon/java-module-test
java-module-test의 src/ 폴더에 자바 은행을 다음과 같이 배치한다.
--main.app 모듈과 net.java_school.db.dbpool.mysql 모듈은 제거한다--
src/
├── net.java_school.javabank
│ ├── net
│ │ └── java_school
│ │ └── bank
│ │ ├── Account.java
│ │ ├── Bank.java
│ │ ├── BankDao.java
│ │ ├── BankUi.java
│ │ ├── MyBank.java
│ │ ├── MyBankDao.java
│ │ └── Transaction.java
│ ├── module-info.java
│ └── simplelogger.properties
├── net.java_school.db.dbpool.api
│ ├── net
│ │ └── java_school
│ │ └── db
│ │ └── dbpool
│ │ └── api
│ │ └── ConnectionManageable.java
│ └── module-info.java
├── 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
lib/
├── slf4j-simple-1.7.30.jar
jars/
├── ojdbc6.jar
└── slf4j-api-1.7.30.jar
jar 파일을 lib/ 와 jars/ 로 분리해서 배치했는지 설명이 필요하다.
jars/는 모듈 패스에 추가할 것이다.
모듈 패스에 있는, 모듈이 아닌 jar는 자동 모듈이 된다.
lib/는 클래스 패스로 사용할 것이다.
클래스 패스에 있는, 모듈이 아닌 jar는 이름 없는 모듈이 된다.
자동 모듈만이 이름 없는 모듈을 읽을 수 있다.
slf4j-api 가 slf4j-simple 을 읽으리라는 건 이름에서 쉽게 유추할 수 있다.
자동 모듈 slf4j-api 가 이름 없는 모듈 slf4j-simple 을 읽도록 배치한 것이다.
자바 은행 모듈의 디스크립터를 생성한다.
module net.java_school.javabank { requires net.java_school.db.dbpool.api; uses net.java_school.db.dbpool.api.ConnectionManageable; }
자동 모듈의 이름이 어떻게 결정되는지 알기 위해 일단 컴파일한다.
윈도에서 컴파일
C:\ Command Promptjavac -p jars -d out --module-source-path src ^ -m net.java_school.javabank,net.java_school.db.dbpool.api, net.java_school.db.dbpool,net.java_school.db.dbpool.oracle
리눅스에서 컴파일
javac -p jars -d out --module-source-path src $(find src -name "*.java")
컴파일 에러가 발생한다.
src/net.java_school.javabank/net/java_school/bank/MyBankDao.java:12: error: package org.slf4j is not visible import org.slf4j.Logger; ^ (package org.slf4j is declared in module org.slf4j, but module net.java_school.javabank does not read it) src/net.java_school.javabank/net/java_school/bank/MyBankDao.java:13: error: package org.slf4j is not visible import org.slf4j.LoggerFactory; ^ (package org.slf4j is declared in module org.slf4j, but module net.java_school.javabank does not read it) 2 errors
에러 메시지 중
(package org.slf4j is declared in module org.slf4j, but module net.java_school.javabank does not read it)
에서 모듈 이름이 org.slf4j 임을 알 수 있다.
자바 은행 모듈이 org.slf4j 모듈을 사용한다는 선언을 모듈 디스크립터에 추가한다.
module net.java_school.javabank { requires net.java_school.db.dbpool.api; requires org.slf4j; uses net.java_school.db.dbpool.api.ConnectionManageable; }
윈도에서 테스트
컴파일
C:\ Command Promptjavac -p jars -d out --module-source-path src ^ -m net.java_school.javabank,net.java_school.db.dbpool.api, net.java_school.db.dbpool,net.java_school.db.dbpool.oracle
프로퍼티 파일 복사
C:\ Command Promptcopy src\net.java_school.db.dbpool.oracle\oracle.properties ^ out\net.java_school.db.dbpool.oracle\ copy src\net.java_school.javabank\simplelogger.properties ^ out\net.java_school.javabank\
실행
C:\ Command Promptset classpath=lib\slf4j-simple-1.7.30.jar java -p jars;out ^ -m net.java_school.javabank/net.java_school.bank.BankUi
리눅스에서 테스트
컴파일
javac -p jars -d out --module-source-path src $(find src -name "*.java")
프로퍼티 파일 복사
cp src/net.java_school.db.dbpool.oracle/oracle.properties \ out/net.java_school.db.dbpool.oracle/ cp src/net.java_school.javabank/simplelogger.properties \ out/net.java_school.javabank/
실행
CP=lib/slf4j-simple-1.7.30.jar java -cp $CP -p jars:out \ -m net.java_school.javabank/net.java_school.bank.BankUi참조