캠핑과 개발

java.lang.reflect를 이용하면 우리가 원하는 클래스에 대한 invoke가 가능하다는 것은 알고 있을 것이다.

하지만 classpath에 등록안되어진 클래스들에 대해서는 어떻게 할 것인가? 


일일이 사용자에게 클래스 패스를 설정하게 할수만은 없는 일이다. 


보통의 엔진들을 보게 되면 install되어진 디렉토리의 위치만을 세팅하도록 하고 있다. 

set JAVA_HOME이라던지 

set ANT_HOME이라던지.. 


쉘스크립트에 의하여 그러한 것들을 정의하여 java process를 띄우곤 하는데 그러면 

내가 ant.jar등을 등록하지 않았음에도 불구하고 해당 애플리케이션들이 잘 작동하는 이유는 무엇일까? 

그것은 바로 ClassLoader에 숨겨져 있다. 

아래에서 보여지는 샘플코드는 classpath 프로퍼티에 등록이 되어지지 않은 클래스들에 대한 조작을 할 것이다. 


그렇게 함으로서 이 글을 읽는 당신이 만든 애플리케이션이 별다른 클래스로딩 정책 없이도 작동이 될수 있겠다. 

그러려면 또한 잘 알아야 하는것이 reflection API이거늘... 

이부분에서는 그러한 것을 생략하고 URLClassLoader를 이용하여 디렉토리나 jar파일을 등록하여 가져오는 

방법을 설명하도록 하겠다. 


ClassLoader클래스는 이미 1.0API부터 존재해왔으면 URLClassLoader는 1.2에 새롭게 추가된 클래스이다. 

우리가 사용하는 파일시스템이 URL이란 이름하에 조작이 될 수 있다는 것을 우선 명심하기 바란다. 

왜냐면 file:/// 이란 URI를 사용하기 때문이다. 


아래에서는 특정한 디렉토리 안의 jar파일에 대한 class loading샘플을 보여준다.. 

  1. import java.io.*;
  2. import java.net.*;
  3. public class ClassLoading {
  4.   public static void main(String [] args) throws Exception {
  5.     // Create a File object on the root of the directory containing the class file
  6.     File file = new File("D:/_Develop/jmxSamples/customMBean/log4j-1.2.8.jar");    
  7.     try {
  8.       // Convert File to a URL
  9.       URL url = file.toURL();          // file:/D:/_Develop/jmxSamples/customMBean/log4j-1.2.8.jar
  10.       URL[] urls = new URL[]{ url };
  11.       System.out.println(urls);
  12.        
  13.       // Create a new class loader with the directory
  14.       ClassLoader cl = new URLClassLoader(urls);
  15.       System.out.println(cl);
  16.        
  17.       // Load in the class; Logger.class should be located in
  18.       // the directory file:/D:/_Develop/jmxSamples/customMBean/log4j-1.2.8.jar
  19.       Class cls = cl.loadClass("org.apache.log4j.Logger");
  20.       System.out.println(cls);    
  21.     } catch (MalformedURLException e) {
  22.       e.printStackTrace();
  23.     } catch (ClassNotFoundException e2) {
  24.       e2.printStackTrace();
  25.     }  
  26.   }
  27. }




위에서 보는 것처럼 디렉토리를 설정하거나 특정 jar파일을 사용할 수 있도록 작성한다. 

특정파일이 가르키지 않으면 해당 디렉토리의 class파일들을 package형태로 참조하도록 할 수 있는데 

해당 디렉토리에 대한 클래스 로딩 샘플을 아래와 같다. 

  1. import java.io.*;
  2. import java.net.*;
  3. public class ClassLoading {
  4.   public static void main(String [] args) throws Exception {
  5.     // Create a File object on the root of the directory containing the class file
  6.     File file = new File("D:/_CVSDevelop/jca_hello_adapter/build/classes");
  7.      
  8.     try {
  9.       // Convert File to a URL
  10.       URL url = file.toURL();          // file:/D:/_CVSDevelop/jca_hello_adapter/build
  11.       URL[] urls = new URL[]{ url };
  12.       System.out.println(urls);
  13.        
  14.       // Create a new class loader with the directory
  15.       ClassLoader cl = new URLClassLoader(urls);
  16.       System.out.println(cl);
  17.        
  18.       // Load in the class; Test.class should be located in
  19.       // the directory file:/D:/_CVSDevelop/jca_hello_adapter/build/classes/com/bea/jca/test/Test
  20.       Class cls = cl.loadClass("com.bea.jca.test.Test");
  21.       System.out.println(cls);
  22.      
  23.     } catch (MalformedURLException e) {
  24.       e.printStackTrace();
  25.     } catch (ClassNotFoundException e2) {
  26.       e2.printStackTrace();
  27.     }  
  28.   }
  29. }
  30.  

위 예제는 classpath의 루트로 잡은 디렉토리를 기준의 package형태로 설정되 파일을 로딩하여 사용할수 있도록 한다. 


이 이후의 코딩에는 class가 newInstance를 취한 후 method를 invoking해야 하는 과정을 거치게 되는데

한 가지 주의할 점은 해당 클래스를 반드시 reflection API를 이용하여 호출해야 한다는 점이다. 


대략 아래의 코드정도를 이용하여 main 메소드등을 호출하는 클래스를 작성할 수 있을 것이다. 

  1. public void invokeClass(String name, String[] args)
  2.     throws ClassNotFoundException,
  3.           NoSuchMethodException,
  4. {
  5.     Class c = loadClass(name);
  6.     Method m = c.getMethod("main"new Class[] { args.getClass() });
  7.     m.setAccessible(true);
  8.     int mods = m.getModifiers();
  9.     if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
  10.         !Modifier.isPublic(mods)) {
  11.         throw new NoSuchMethodException("main");
  12.     }
  13.     try {
  14.         m.invoke(nullnew Object[] { args });
  15.     } catch (IllegalAccessException e) {
  16.         // This should not happen, as we have disabled access checks
  17.     }
  18. }


[출처]http://www.yunsobi.com/blog/136