Java 프레임워크 만들기 - JSP

자바 JNDI 연동 1 - Java JNDI(Java Naming and Directory Interface), 이클립스(Eclipse)

carrotweb 2021. 6. 25. 21:27
728x90
반응형

이번에는 데이터베이스 커넥션 풀을 DBCP가 아닌 JNDI를 이용하겠습니다.

JNDI(Java Naming and Directory Interface)는 네이밍 서비스로 부터 제공하는 자원(데이터 및 객체)를 찾아 참고(lookup)하기 위한 자바 API입니다.

데이터베이스 커넥션들을 자바 웹 응용프로그램(Java Web Application)이 아닌 WAS(Web Application Server)에서 데이터베이스 커넥션을 생성하고 풀(Pool)로 관리합니다. 자바 웹 응용프로그램에서는 JDNI의 "lookup()"를 통해 리소스에 접근하고 데이터베이스 커넥션을 가져와 이용합니다.

1. "https://mvnrepository.com"를 접속하고 검색에 "Tomcat JDBC"를 입력하고 검색합니다.

 

"Tomcat JDBC"를 클릭합니다.

 

"Version"중에서 버전인 "8.5.68"를 찾기위해 아래로 스크롤하여 이동합니다.

 

버전 "8.5.68"를 클릭합니다.

테스트할 Tomcat 버전 8.0.36으로 버전에 맞게 "8.5.68"를 선택하였습니다.

테스트할 Tomcat 버전 9.0 이상이라면 "10.0.7"를 선택하시면 됩니다.

 

Tomcat 버전 8.0.36에서 Maven에서 "10.0.7"버전으로 할 경우 다음과 같이 버전이 맞지 않아 에러가 발생합니다. 

6월 25, 2021 21:07:57 오후 org.apache.catalina.startup.ContextConfig processAnnotationsJar
심각: Unable to process Jar entry [module-info.class] from Jar [file:/C:/workspaces/projects/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/test2/WEB-INF/lib/tomcat-juli-10.0.7.jar] for annotations
org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19
	at org.apache.tomcat.util.bcel.classfile.Constant.readConstant(Constant.java:97)
	at org.apache.tomcat.util.bcel.classfile.ConstantPool.<init>(ConstantPool.java:55)
	at org.apache.tomcat.util.bcel.classfile.ClassParser.readConstantPool(ClassParser.java:176)
	at org.apache.tomcat.util.bcel.classfile.ClassParser.parse(ClassParser.java:85)
	at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:2042)
	at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:1988)
	at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1958)
	at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1912)
	at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1157)
	at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:779)
	at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:306)
	at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:95)
	at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5202)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1407)
	at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1397)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Tomcat 버전에 맞게 버전을 선택해야 합니다.

 

"Maven"탭에 있는 스크립트를 복사합니다.

<dependency>
	<groupId>org.apache.tomcat</groupId>
	<artifactId>tomcat-jdbc</artifactId>
	<version>8.5.68</version>
</dependency>

 

2. "test2" 프로젝트의 "pom.xml"을 오픈하여 기존에 있는 "commons-dbcp2"는 주석차리하고 위에서 복사한 스크립트를 붙여넣기하고 저장합니다. 그러면 Maven에서 "tomcat-jdbc-8.5.68.jar", "tomcat-juli-8.5.68.jar"파일들을 자동으로 다운로드 받습니다.

 

다운로드가 완료되면 자동으로 빌드하고 "test2" 프로젝트의 [Java Resources > Libraries > Maven Dependencies]에 "tomcat-jdbc-8.5.68.jar", "tomcat-juli-8.5.68.jar"파일이 연결되어 있는 것을 확인할 수 있습니다.

 

3. "Servers"에서 "Tomcat8-config"이나 "Tomcat9-config"의 "server.xml"를 오픈합니다.

 

"<GlobalNamingResources>"태그안에 "<Resource>"를 추가합니다.

<Resource name="jdbc/test"
	auth="Container"
	type="javax.sql.DataSource"
	driverClassName="org.mariadb.jdbc.Driver"
	url="jdbc:mariadb://localhost:3306/test"
	username="root"
	password="password"
	initialSize="20"
	maxTotal="100"
	maxIdle="100"
	minIdle="20"
	maxWaitMillis="30000"
/>

"name"은 리소스를 구분하기 위한 이름입니다.

리소스 구분을 위헤 "Resource_Type/Resource_Name"으로 사용하는것이 좋습니다.

그래서 JDBC로 구동됨으로 "Resource_Type"은 "jdbc", 데이터베이스 명이 "test"임으로 "Resource_Name"은 "test"으로 하였습니다. "Resource_Name"을 데이터베이스 시스템명과 결합해서 사용한다면 "jdbc/mariadb_test"으로 지정해도 됩니다.

"auth"는 "Container"로 설정합니다. 이유는 컨테이너가 웹 애플리케이션 대신 리소스 관리자에 로그인하 관리하기 위해서입니다. 만약, 웹 애플리케이션에서 프로그램으로 리소스 관리자에 로그인을 할거면 "Application"이로 설정합니다.

이전에 설명들인 것 처럼 "maxTotal"과 "maxIdle", "minIdle", "maxWaitMillis"는 시스템 환경에 맞게 조정하시면 됩니다.

 

Oracle를 사용하신다면 "driverClassName"과 "url"를 다음과 같이 수정하시면 됩니다.

driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:test"

 

MySQL를 사용하신다면 "driverClassName"과 "url"를 다음과 같이 수정하시면 됩니다.

driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/test"

 

MS-SQL를 사용하신다면 "driverClassName"과 "url"를 다음과 같이 수정하시면 됩니다.

driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
url="jdbc:sqlserver://127.0.0.1;DatabaseName=test"

 

만약 속성으로 "maxActive"를 사용하였다면 다음과 같이 경고가 발생하여 적용되지 않습니다. DBCP2에서는 "maxActive"를 "maxTotal"으로 변경해야 합니다.

6월 25, 2021 7:15:24 오후 org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory getObjectInstance
경고: Name = test Property maxActive is not used in DBCP2, use maxTotal instead. maxTotal default value is 8. You have set value of "100" for "maxActive" property, which is being ignored.

 

또한 속성으로 "maxWait"를 사용하였다면 다음과 같이 경고가 발생하여 적용되지 않습니다. DBCP2에서는 "maxWait"를 "maxWaitMillis"으로 변경해야 합니다.

6월 25, 2021 7:15:24 오후 org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory getObjectInstance
경고: Name = test Property maxWait is not used in DBCP2 , use maxWaitMillis instead. maxWaitMillis default value is -1. You have set value of "30000" for "maxWait" property, which is being ignored.

 

4. "Servers"에서 "Tomcat8-config"이나 "Tomcat9-config"의 "context.xml"를 오픈합니다.

 

"<Context>"태그안에 "<ResourceLink>"를 추가합니다.

<ResourceLink global="jdbc/test" name="jdbc/test" type="javax.sql.DataSource"/>

"global"은 "server.xml"파일의 "<GlobalNamingResources>"태그안에 "<Resource>"태그의 "name"속성 값과 동일하게 입력합니다.

"name"은 리소스 링크를 구분하기 위한 이름입니다. 리소스처럼 "Resource_Type/Resource_Name"으로 사용하는것이 좋습니다.

"type"은 "server.xml"파일의 "<GlobalNamingResources>"태그안에 "<Resource>"태그의 "type"속성 값과 동일하게 입력합니다.

 

"<Resource>"태그를 추가하는 방법은 2가지가 있습니다.

위에서 설명한 것처럼 "server.xml"파일의 "<GlobalNamingResources>"태그안에 "<Resource>"태그를 추가하고 "context.xml"파일에 "<ResourceLink>"태그를 추가하는 방법과 "context.xml"파일에 "<Resource>"태그를 추가하는 방법이 있습니다.

 

Tomcat에서는 2가지 방법 모두 "<web-app>"파일에 "<resource-ref>"를 추가하지 않아도 정상적으로 동작합니다. 그러지만 Tomcat에서는 웹 응용 프로그램에 대한 리소스 요구 사항을 문서화하는 것을 권장하고 있습니다.

 

"context.xml"파일에 "<Resource>"태그를 추가한 경우

If a resource has been defined in a <Context> element it is not necessary for that resource to be defined in /WEB-INF/web.xml. However, it is recommended to keep the entry in /WEB-INF/web.xml to document the resource requirements for the web application.

 

"server.xml"파일의 "<GlobalNamingResources>"태그안에 "<Resource>"태그를 추가한 경우

If a resource has been defined using a <ResourceLink>, it is not necessary for that resource to be defined in /WEB-INF/web.xml. However, it is recommended to keep the entry in /WEB-INF/web.xml to document the resource requirements for the web application.

 

그래서 "<web-app>"파일에 "<resource-ref>"를 추가하도록 하겠습니다.

 

5. "src > main > webapp > WEB-INF"의 "web.xml"를 오픈합니다.

 

"<web-app>"안에 "<resource-ref>"를 추가합니다.

<resource-ref>
	<description>MariaDB Connection Pool</description>
	<res-ref-name>jdbc/test</res-ref-name>
	<res-type>javax.sql.DataSource</res-type>
	<res-auth>Container</res-auth>
</resource-ref>

"<description>"는 참조하는 리소스에 대한 설명문입니다.

"<res-ref-name>"는 "참조하는 리소스의 이름입니다. context.xml"파일의 "<ResourceLink>"태그의 "name" 속성 값과 동일하게 입력합니다.

"<res-type>"는 리소스의 타입입니다. "context.xml"파일의 "<ResourceLink>"태그의 "type" 속성 값과 동일하게 입력합니다.

"<res-auth>"는 리소스의 권한입니다. "server.xml"파일의 "<GlobalNamingResources>"태그안에 "<Resource>"태그의 "auth"속성 값과 동일하게 입력합니다.

"<resource-ref>"는 "<description>", "<res-ref-name>", "<res-type>", "<res-auth>"순으로 되어있지 않으면 요소들의 순서가 맞지 않는다는 XML 문제(XML Problem)가 발생합니다.

Multiple annotations found at this line:
	- cvc-complex-type.2.4.a: Invalid content was found starting with element 'description'. One of '{"http://xmlns.jcp.org/xml/ns/
	 javaee":res-type, "http://xmlns.jcp.org/xml/ns/javaee":res-auth, "http://xmlns.jcp.org/xml/ns/javaee":res-sharing-scope, "http://xmlns.jcp.org/
	 xml/ns/javaee":mapped-name, "http://xmlns.jcp.org/xml/ns/javaee":injection-target, "http://xmlns.jcp.org/xml/ns/javaee":lookup-name}' is 
	 expected.
	- Invalid element name: - description One of the following is expected: - res-type - res-auth - res-sharing-scope - mapped-name - 
	 injection-target - lookup-name Error indicated by: {http://xmlns.jcp.org/xml/ns/javaee} with code:

 

그리고 "<res-ref-name>"이 "context.xml"파일의 "<ResourceLink>"태그의 "name" 가 같지 않다면 다음과 같이 "알 수 없는 속성 무시"라는 메시지가 나타나면서 무시됩니다.

org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory getObjectInstance
정보: Name = test Ignoring unknown property: value of "MariaDB Connection Pool" for "description" property

 

 

기존 프로퍼티(properties) 파일을 읽어 데이터베이스 드라이버를 로딩하고 풀(Pool)을 생성했던 데이터베이스 커넥션 풀 매니저와 다르게 JNDI를 이용하여 WAS에서 생성되고 관리되는 풀(Pool)를 이용하기 때문에 프로퍼티(properties) 파일은 수정해야 합니다.

6. "test2" 프로젝트의 "Java Resources"에 "src/main/resources"에서 "/com/home/project/test2/config/database-maria.properties"파일에 수정합니다.

id=databaseMaria
jndi=java:/comp/env/jdbc/test

#driverClassName=org.mariadb.jdbc.Driver
#url=jdbc:mariadb://localhost:3306/test
#username=root
#password=password
#initialSize=8
#maxWaitMillis=-1
#maxTotal=8
#maxIdle=8
#validationQuery=select 1
#validationQueryTimeoutSeconds=-1
#poolStatements=True
#maxOpenPreparedStatements=40
#maxConnLifetimeMillis=-1
#blockWhenExhausted=True
#minIdle=0
#testOnBorrow=False
#testOnReturn=False
#testOnCreate=False
#testWhileIdle=True
#evictionPolicyClassName=org.apache.commons.pool2.impl.DefaultEvictionPolicy
#timeBetweenEvictionRunsMillis=-1
#numTestsPerEvictionRun=3
#minEvictableIdleTimeMillis=1800000
#softMinEvictableIdleTimeMillis=-1

"java:/comp/env/"는 "context"의 정보가 있는 위치입니다. 리소스 이름 앞에 반드시 추가되어야 합니다.

JNDI로만 사용하신다면 이전에 사용한 정보들을 삭제하시면 됩니다.

여기서는 테스트로 실행할 것이기 때문에 주석(#)처리하도록 하겠습니다.

7. "test2" 프로젝트의 "Java Resources/src/main/java"에서 "com.hom.project.test2.database"에서 오른쪽 버튼을 클릭하여 컨텍스트 메뉴 [New > Class]를 클릭하고 "TestDatabaseJNDI.java"를 생성합니다.

 

커넥션 풀이 생성되었는지 확인하기 위해 부울값 필드를 추가하고 커넥션 풀 생성 여부 확인 메서드를 추가합니다.

/**
 * 데이터베이스 프로퍼티
 */
private Properties databaseInfo = new Properties();

/**
 * 데이터베이스 커넥션 풀 생성 여부
 */
private boolean initDatabasePool = false;

/**
 * 데이터베이스 커넥션 풀 생성 여부를 가져옵니다.
 * @return 데이터베이스 커넥션 풀 생성 여부
 */
public boolean isInitDatabasePool() {
	return initDatabasePool;
}

 

 

데이터베이스 프로퍼티(properties) 파일을 읽어 프로퍼티로 로드하게 메소드를 추가합니다.

/**
 * 데이터베이스 매니저 프로퍼티를 로드하고 검증합니다.
 * @param databaseManagerPath 데이터베이스 매니저 프로퍼티 경로
 * @return 프로퍼티 로드 여부
 */
private boolean loadProperties(String databaseManagerPath) {
	boolean result = true;

	InputStream inputStream = getClass().getResourceAsStream(databaseManagerPath);
	if (inputStream != null) {
		try {
			databaseInfo.load(inputStream);
			System.out.println("데이터베이스 프로퍼티를 읽음");

			String id = databaseInfo.getProperty("id");
			if (id == null || id.trim().isEmpty()) {
				System.out.println("데이터베이스 프로퍼티에 id가 없음");
				result = false;
			}
			String jndi = databaseInfo.getProperty("jndi");
			if (jndi == null || jndi.trim().isEmpty()) {
				System.out.println("데이터베이스 프로퍼티에 jndi가 없음");
				result = false;
			}

			if (!result) {
				System.out.println("데이터베이스 프로퍼티 정보가 정확하지 않음");
			}
		} catch (IOException e) {
			System.out.println("데이터베이스 프로퍼티를 읽지 못함");
			result = false;
			e.printStackTrace();
		} finally {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	} else {
		System.out.println("데이터베이스 프로퍼티를 읽지 못함");
		result = false;
	}
	return result;
}

 

"id"로 여러개의 데이터베이스들을 구분하여 관리 할 수 있도록 메소드를 추가합니다.

/**
 * 데이터베이스 프로퍼티에 id를 가져옵니다.
 * @return id
 */
public String getId() {
	return databaseInfo.getProperty("id") == null ? "" : databaseInfo.getProperty("id").trim();
}

 

클래스 생성자를 통해 데이터베이스 프로퍼티 파일을 읽게 생성자를 추가합니다.

/**
 * 생성자
 * @param databaseManagerPath 데이터베이스 매니저 프로퍼티 경로
 */
public TestDatabaseJNDI(String databaseManagerPath) {
	if (loadProperties(databaseManagerPath)) {
		initDatabasePool = true;
	}
}

 

JNDI의 lookup를 통해 WAS(Web Application Server)에서 관리되는 데이터베이스 커넥션 풀에서 커넥션을 가져오는 메소드를 추가합니다.

/**
 * 데이터베이스 커넥션 풀에서 데이터베이스 연결 객체를 가져옵니다.
 * @return 데이터베이스 연결 객체
 */
public Connection getConnection() {
	Connection connection = null;

	String jndi = databaseInfo.getProperty("jndi");

	try {
		Context initContext = new InitialContext();
		if(initContext != null)
		{
			DataSource dataSource = (DataSource)initContext.lookup(jndi);
			if(dataSource != null) {
				connection = dataSource.getConnection();
				System.out.println("[" + Thread.currentThread().getName() + "] 데이터베이스 커넥션 객체[" + connection.toString() + "]를 가져옴");
			} else {
				System.out.println("[" + Thread.currentThread().getName() + "] 데이터베이스 커넥션 객체를 가져오지 못함");
			}
		}
	} catch (NamingException e) {
		System.out.println("JNDI에서 lookup으로 " + jndi + "를 찾지 못하였습니다.");
		e.printStackTrace();
	} catch (SQLException e) {
		System.out.println("[" + Thread.currentThread().getName() + "] 데이터베이스 커넥션 객체를 가져오지 못함");
		e.printStackTrace();
	}

	return connection;
}

 

다음처럼 "java:/comp/env"으로 "lookup()"하여 찾은 "Context"에서 다시 "lookup()"하여 "DataSource"를 찾게 하셔도 됩니다.

DataSource dataSource = null;
Context envContext = (Context)initContext.lookup("java:/comp/env");
if (envContext != null) {
	dataSource = (DataSource)envContext.lookup(jndi);
	if (dataSource != null) {
		connection = dataSource.getConnection();
		System.out.println("[" + Thread.currentThread().getName() + "] 데이터베이스 커넥션 객체[" + connection.toString() + "]를 가져옴");
	} else {
		System.out.println("[" + Thread.currentThread().getName() + "] 데이터베이스 커넥션 객체를 가져오지 못함");
	}
}

위에처럼 사용하실려면 "database-maria.properties"파일에 "jndi"를 "java:/comp/env/jdbc/test"에서 "jdbc/test"으로 변경해야 합니다.

 

커넥션을 반환하는 메소드를 추가합니다.

/**
 * 데이터베이스 커넥션 풀에 데이터베이스 연결 객체를 반환합니다.
 * @param connection 데이터베이스 연결 객체
 */
public void closeConnection(Connection connection) {
	try {
		System.out.println("[" + Thread.currentThread().getName() + "] 데이터베이스 커넥션 객체[" + connection.toString() + "]를 반환함");
		connection.close();
	} catch (SQLException e) {
		e.printStackTrace();
	}
}

 

JNDI로 WAS(Web Application Server)에서 관리되어 "destroyDatabasePool()"메소드는 기존 코드를 위해 내용없이 추가합니다.

/**
 * 데이터베이스 커넥션 풀을 파괴합니다.
 */
public void destroyDatabasePool() {
}

 

8. "test2" 프로젝트의 "Java Resources/src/main/java"에서 "com.home.project.test2.listener.TestServletContextListener"의 "contextInitialized()"메소드에 있는 "databaseMappingMap"의 인자를 "TestDatabaseConectionPool"에서

// DBId-Database 맵
Map<String, TestDatabaseConectionPool> databaseMappingMap = new HashMap<String, TestDatabaseConectionPool>();

String databaseManagers = sce.getServletContext().getInitParameter("DatabaseManager");
if (databaseManagers != null && !databaseManagers.trim().isEmpty()) {
	String[] databaseManagerPaths = databaseManagers.trim().split("\n|,|;|\\s+");
	for (String databaseManagerPath : databaseManagerPaths) {
		databaseManagerPath = databaseManagerPath.trim();
		if (!databaseManagerPath.isEmpty()) {
			TestDatabaseConectionPool testDatabaseManager = new TestDatabaseConectionPool(databaseManagerPath);
			if (testDatabaseManager.isInitDatabasePool()) {
				databaseMappingMap.put(testDatabaseManager.getId(), testDatabaseManager);
			}
		}
	}
}

"TestDatabaseJNDI"로 수정합니다.

// DBId-Database 맵
Map<String, TestDatabaseJNDI> databaseMappingMap = new HashMap<String, TestDatabaseJNDI>();

String databaseManagers = sce.getServletContext().getInitParameter("DatabaseManager");
if (databaseManagers != null && !databaseManagers.trim().isEmpty()) {
	String[] databaseManagerPaths = databaseManagers.trim().split("\n|,|;|\\s+");
	for (String databaseManagerPath : databaseManagerPaths) {
		databaseManagerPath = databaseManagerPath.trim();
		if (!databaseManagerPath.isEmpty()) {
			TestDatabaseJNDI testDatabaseManager = new TestDatabaseJNDI(databaseManagerPath);
			if (testDatabaseManager.isInitDatabasePool()) {
				databaseMappingMap.put(testDatabaseManager.getId(), testDatabaseManager);
			}
		}
	}
}

 

"contextInitialized()"메소드에서 DAO를 "databaseMappingMap"의 형 변환을 "TestDatabaseConectionPool"에서

if (repositoryeInstance != null) {
	Field[] Fields = findClass.getDeclaredFields();
	for (Field field : Fields) {
		TestAnnAutowired testAnnAutowired = field.getAnnotation(TestAnnAutowired.class);
		TestAnnQualifier testAnnQualifier = field.getAnnotation(TestAnnQualifier.class);
		if (testAnnAutowired != null && testAnnQualifier != null) {
			System.out.println("[Repository Field] " + field.getType().getName() + " 타입의 " + field.getName() + " 맴버 필드을 찾음");
			TestDatabaseConectionPool testDatabaseManager = (TestDatabaseConectionPool) databaseMappingMap.get(testAnnQualifier.value());
			if (testDatabaseManager != null) {
				field.setAccessible(true);
				try {
					field.set(repositoryeInstance, testDatabaseManager);
					System.out.println("[Repository Field] " + field.getName() + "에 의존성 주입을 처리함");
				} catch (IllegalArgumentException | IllegalAccessException e) {
					e.printStackTrace();
					System.out.println("[Repository Field] " + field.getName() + "에 의존성 주입을 처리하지 못함");
				}
			}
		}
	}
}

"TestDatabaseJNDI"로 수정합니다.

if (repositoryeInstance != null) {
	Field[] Fields = findClass.getDeclaredFields();
	for (Field field : Fields) {
		TestAnnAutowired testAnnAutowired = field.getAnnotation(TestAnnAutowired.class);
		TestAnnQualifier testAnnQualifier = field.getAnnotation(TestAnnQualifier.class);
		if (testAnnAutowired != null && testAnnQualifier != null) {
			System.out.println("[Repository Field] " + field.getType().getName() + " 타입의 " + field.getName() + " 맴버 필드을 찾음");
			TestDatabaseJNDI testDatabaseManager = (TestDatabaseJNDI) databaseMappingMap.get(testAnnQualifier.value());
			if (testDatabaseManager != null) {
				field.setAccessible(true);
				try {
					field.set(repositoryeInstance, testDatabaseManager);
					System.out.println("[Repository Field] " + field.getName() + "에 의존성 주입을 처리함");
				} catch (IllegalArgumentException | IllegalAccessException e) {
					e.printStackTrace();
					System.out.println("[Repository Field] " + field.getName() + "에 의존성 주입을 처리하지 못함");
				}
			}
		}
	}
}

 

"contextDestroyed()"메소드에서 "databaseMappingMap"의 인자를 "TestDatabasePoolManager"에서

public void contextDestroyed(ServletContextEvent sce)  {
	System.out.println("ServletContext 파괴 실행"); 
	@SuppressWarnings("unchecked")
	Map<String, TestDatabasePoolManager> databaseMappingMap = (Map<String, TestDatabasePoolManager>)sce.getServletContext().getAttribute("DatabaseMappingMap");
	Iterator<String> keyIter = databaseMappingMap.keySet().iterator();
	while (keyIter.hasNext()) {
		String dbId = (String) keyIter.next();
		TestDatabasePoolManager testDatabaseManager = databaseMappingMap.get(dbId);
		testDatabaseManager.destroyDatabasePool();
	}
}

"TestDatabaseJNDI"로 수정합니다.

public void contextDestroyed(ServletContextEvent sce)  {
	System.out.println("ServletContext 파괴 실행"); 
	@SuppressWarnings("unchecked")
	Map<String, TestDatabaseJNDI> databaseMappingMap = (Map<String, TestDatabaseJNDI>)sce.getServletContext().getAttribute("DatabaseMappingMap");
	Iterator<String> keyIter = databaseMappingMap.keySet().iterator();
	while (keyIter.hasNext()) {
		String dbId = (String) keyIter.next();
		TestDatabaseJNDI testDatabaseManager = databaseMappingMap.get(dbId);
		testDatabaseManager.destroyDatabasePool();
	}
}

 

728x90
반응형