728x90
반응형

Tomcat 서버 하나에 여러개의 war 파일을 배포하여 사용하며 각 application 별로 Spring의 DBCP 를 이용하여 Connection Pooling 을 한다.

 문제점 

  - db 접속 정보(id/pw) 를 한곳에서 관리할 수 없다.

  - db 접속 정보가 변경되면 각 war 별로 참조하는 파일의 내용을 변경해 줘야 한다. ( ex 암호화 되어 있는 properties 파일 )

  - 개별 connection pooling 의 경우 실수가 발생할 가능성이 높으며 불필요한 서버 리소스가 낭비 된다.


[방안]

  - WAS 에서 제공하는 connection pooling 을 사용 한다.

  - 각 war 에서는 JNDI 로 Lookup 하여 연결 한다.

  - 주의사항 : 접속 하는 데이터베이스는 하나가 된다.

         ex) aaa.war 에서는 test 라는 데이터베이스안에 있는 테이블만 사용

             bbb.war 에서는 real 이라는 데이터베이스 안에 있는 테이블만 사용

             위와 같은 경우 query 에 반드시 aaa.tableName 으로 처리 해줘야 한다.

             이전 처럼 개별로 connection 을 관리할 경우에는 connection 자체를 aaa 또는 bbb 로 하기 때문에 table name 만 써도

             문제되지 않았지만 이부분은 수정이 되어야 한다.


[처리 방법 정리]

1. Tomcat 설정

   server.xml 의 GlobalNameingResource 에 JNDI 내용 추가

 <GlobalNamingResources>

    <Resource name="jdbc/testJNDI"

          factory="com.yhkim.global.datasource.CustomDataSource"

          auth="Container"

          type="javax.sql.DataSource"

          maxActive="100"

          maxIdle="30"

          maxWait="10000"

          username=""

          password=""

          driverClassName="com.mysql.jdbc.Driver"

          url="jdbc:mysql://127.0.0.1:3306/databaseName?zeroDateTimeBehavior=convertToNull"/>

  </GlobalNamingResources>

  노란색 부분을 눈여겨 보자.

  일반적인 JNDI 이용 시 factory 부분은 org.apache.tomcat.jdbc.pool.DataSourceFactory 를 사용한다.

  하지만 그럴 경우 username 과 password 부분을 암호화 해서 사용할 수 없다. 

  따라서 custom factory class 를 작성하여 username 와 password 를 복호화 할 수 있도로 한다.


2. CustomDataSource class 작성

   apache 의 common-dbcp 를 이용하였다. 

   아래 java project 에서 build-path 에 common-dbcp-x.x.jar 파일을 포함하고 

   아래 project 를 globalds.jar (이름은 마음데로) 파일로 export 하여 Tomcat/lib 에 포함시킨다. 

   ../conf/dbinfo.properties 는 즉 설치되는 Tomcat/conf/ 경로가 된다. 

   Tomcat/conf/에 dbinfo.properties 를 만들고 아래 내용을 넣는다. (테스트를 위해 암호화가 아닌 base64 encoding 을 해도 무관)

   username=암호화된아이디

   password=암호화된비밀번호

 public class CustomDataSource extends BasicDataSourceFactory {

public Object getObjectInstance(Object obj, Name name, Context nameCtx, 

                                          @SuppressWarnings("rawtypes") Hashtable environment) throws Exception

{

if(obj instanceof Reference)

{

setUsername((Reference)obj);

setPassword((Reference)obj);

}

return super.getObjectInstance(obj, name, nameCtx, environment);

}


private void setUsername(Reference ref)

throws Exception

{

findDecryptAndReplace("username", ref);

}


private void setPassword(Reference ref)

throws Exception

{

findDecryptAndReplace("password", ref);

}


private void findDecryptAndReplace(String refType, Reference ref)

throws Exception

{

int idx = find(refType, ref);

String decrypted = decrypt(refType);

replace(idx, refType, decrypted, ref);

}


private void replace(int idx, String refType, String newValue, Reference ref)

throws Exception

{

ref.remove(idx);

ref.add(idx, new StringRefAddr(refType, newValue));

}


private String decrypt(String key)throws Exception

{

return getDecViaSeed(getProperty(key));

}


private int find(String addrType, Reference ref)

{

try{

@SuppressWarnings("rawtypes")

Enumeration enu = ref.getAll();

for(int i = 0; enu.hasMoreElements(); i++)

{

RefAddr addr = (RefAddr)enu.nextElement();

if(addr.getType().compareTo(addrType) == 0)

return i;

}

}catch(Exception e){

e.printStackTrace();

}

return 0;

}

public String getDecViaSeed(String str) {

String strDecrypt = "";

try

{

// strDecrypt = 복호화 처리

                   // 실제 테스트를 위해서는 간단히 BASE64 정도로 테스트 해봐도 된다.

}

catch (UnsupportedEncodingException e) 

{

e.printStackTrace();

catch (Exception e) 

{

e.printStackTrace();

}

return strDecrypt;

}

public String getProperty(String key) {

String rtnStr = "";

try {

Properties prop = new Properties();

prop.load(new FileInputStream("../conf/dbinfo.properties"));

rtnStr = prop.getProperty(key);

} catch ( IOException ioe ) {

ioe.printStackTrace();

return null;

} catch ( Exception e ) {

e.printStackTrace();

}

return rtnStr;

}

}

 


3. Tomcat lib 에 필요한 jar 파일 추가

  2번에서 생성한 globalds.jar 과 

  commons-dbcp.jar

  commons-collections.jar

  commons-pool.jar 

  파일을 Tomcat/lib 경로에 포함한다.


4. Application 에서 JNDI 이용하기

web application은 Spring + MyBatis 로 구성되어 있으며 

jdbc 설정.xml 에 아래와 같이 datasource 및 transaction 부분을 설정 한다. (transaction 처리는 상황에 따라 다르게 처리 가능)

bold 처리된 부분만 보면 된다. jndiName 은 tomcat 의 server.xml 에 있는 이름과 동일 해야 한다.

      <beans:bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

  <beans:property name="jndiName" value="jdbc/testNDI"/>

  <beans:property name="resourceRef" value="true"/>

  </beans:bean>

<beans:bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" lazy-init="true">

<beans:property name="dataSource" ref="dataSource"/>

<beans:property name="configLocation" value="classpath:mybatis/mybatis-configuration.xml" />

<beans:property name="mapperLocations" value="classpath:mybatis/query.xml" />

<beans:property name="transactionFactory">

<beans:bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />

</beans:property>

</beans:bean>

<beans:bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

<beans:constructor-arg ref="sqlSessionFactory" />

</beans:bean>

 

<beans:bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<beans:property name="dataSource" ref="dataSource" />

</beans:bean>

<beans:bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

<beans:property name="transactionManager" ref="transactionManager" />

</beans:bean>


5. Application 의 context.xml 설정

META-INF 폴더 밑에 context.xml 파일이 없다면 생성하고 있다면 아래 내용을 추가 한다.

 <?xml version="1.0" encoding="UTF-8"?>

<Context path="/applicationName">

    <WatchedResource>WEB-INF/web.xml</WatchedResource>

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

</Context>



728x90
반응형

'Web Programming > server' 카테고리의 다른 글

톰캣 404  (0) 2018.09.04
A child container failed during start  (0) 2018.09.04
728x90
반응형

HTTP Status 404 - /testjsp/


type Status report

message /testjsp/

description The requested resource (/testjsp/) is not available.


Apache Tomcat/5.5.17

 


server.xml 파일을 확인
server.xml에서 <Context path="/testjps" docBase="절대경로"> 
docBase에 testjsp 디렉토리의 절대경로를 넣어서 해결

728x90
반응형

'Web Programming > server' 카테고리의 다른 글

Tomcat JNDI 설정  (0) 2018.09.04
A child container failed during start  (0) 2018.09.04
728x90
반응형

org.apache.catalina.core.ContainerBase startInternal
심각: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:800)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
... 6 more
Caused by: java.lang.NoClassDefFoundError: Lorg/apache/ibatis/session/SqlSessionFactory;
at java.lang.Class.getDeclaredFields0(Native Method)
at java.lang.Class.privateGetDeclaredFields(Class.java:2436)
at java.lang.Class.getDeclaredFields(Class.java:1806)
at org.apache.catalina.util.Introspection.getDeclaredFields(Introspection.java:106)
at org.apache.catalina.startup.WebAnnotationSet.loadFieldsAnnotation(WebAnnotationSet.java:263)
at org.apache.catalina.startup.WebAnnotationSet.loadApplicationServletAnnotations(WebAnnotationSet.java:142)
at org.apache.catalina.startup.WebAnnotationSet.loadApplicationAnnotations(WebAnnotationSet.java:67)
at org.apache.catalina.startup.ContextConfig.applicationAnnotationsConfig(ContextConfig.java:405)
at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:881)
at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:376)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5322)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more
Caused by: java.lang.ClassNotFoundException: org.apache.ibatis.session.SqlSessionFactory
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1702)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
... 20 more

12월 01, 2014 10:03:28 오전 org.apache.catalina.core.ContainerBase startInternal
심각: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:302)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:732)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.startup.Catalina.start(Catalina.java:691)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:322)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:456)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1131)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:800)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more



tomcat7 lib 폴더에 있는 servlet-api.jar 파일을
사용하고 있는 jdk 설치 폴더(C:\Program Files\Java\jdk1.7.0_65\lib)
에 붙여넣기 해서 해결했습니다.
에러가 나는 원인은 JDK의 lib 폴더에 위치한 servlet-api.jar 파일이 6.0버전에 맞는 구 버전이기 때문이랍니다.

728x90
반응형

'Web Programming > server' 카테고리의 다른 글

Tomcat JNDI 설정  (0) 2018.09.04
톰캣 404  (0) 2018.09.04

+ Recent posts