본문 바로가기

취미/코딩

[JAVA] How to use class instance setting and method when loading Library Runtime

[JAVA] Library Runtime Load할 때 Class instance 설정 및 method 사용 방법



when? Library 값이 가변적일 때 사용

평소에는 JVM 기동 시에 이미 Library 다 load 해놓고 편안하게 Class 호출하면서 썼는데 하나하나 호출하면서 사용하려니 불편하다.

그래도 동일한 interface로 구현된 Library를 Optional하게 설정해서 사용할 경우 요긴하지 않을까...


순서

1) Library load

2) Class 명으로 Class 호출

3) Constructor 호출해서 instance를 설정

4) 필요한 method를 실행


여기서 3번 Constructor가 private이라서 헤맸다.

하지만 결론은 static method 사용법을 몰라서 문제였다는 거..


1) Library load

Library 위치 설정 후에 ClassLoader 생성

try { 

     // 1. Library Runtime Load 

      File lib = new File("test.jar"); 

URLClassLoader classLoader = new URLClassLoader(new URL[] { lib.toURL() },     System.class.getClassLoader()); // 현재 classLoader

} catch (MalformedURLException e) { 

// 1. URL Exception             

e.printStackTrace();            

try {

classLoader.close();         // classLoader 종료

} catch (IOException e) {

e.printStackTrace();

}


2) Library 내부 Class 명으로 Class 호출

try {

// 2. Class 확인

Class<?> loadClass = Class.forName("TestClass", true, classLoader);

} catch (ClassNotFoundException e) {
// 2. 해당 "TestClass"가 존재하지 않을 경우 발생
e.printStackTrace();
}


3) Constructor 호출해서 instance를 설정

Constructor를 실행해서 instance가 존재해야 method를 선언해서 실행시킬 수 있다.


instance 받는 방법

3.1) 생성자가 public이라 바로 newInstance method로 실행

3.2) 생성자가 private일 경우 강제로 accessible 정보를 true로 설정해준 후 실행

3.3) static으로 따로 생성된 getInstance method를 실행


3.1) 생성자가 public이라 바로 newInstance method로 실행

Default method이지만 Constructor가 없거나 private일 경우 Exception 발생한다.

Exception이 발생하면 3.2)나 3.3)으로 해결한다.

try { 

Object instance1 = loadClass.newInstance();


} catch (InstantiationException | IllegalAccessException e) 

// Constructor가 없거나 private일 경우 등 발생 

e.printStackTrace(); 

}


3.2) 생성자가 private일 경우 강제로 accessible 정보를 true로 설정해준 후 실행

생성자가 private으로 설정되어 있을 경우 강제로 설정을 바꿔서 Constructor 생성

보안 이슈가 있어서 추천하지 않는 형태라고 한다.

try { 

// Constructor안의 parameter 클래스 정보 설정                                

Constructor<?> constructor = loadClass.getConstructor(String.class);


// 강제로 접근 가능하도록 설정 

constructor.setAccessible(true); 


// parameter 설정하여 instance return 

Object instance2 = constructor.newInstance("stringParameter");      


// 설정 원복

constructor.setAccessible(false); 


} catch (NoSuchMethodException | SecurityException e3) {

// method 가져올 때 Exception 

e3.printStackTrace();

} catch (IllegalArgumentException | InvocationTargetException e2) {     

// method 호출할 때 Exception 

e2.printStackTrace();  

}  


3.3) static으로 따로 생성된 initial method를 실행 (ex. getInstance) 

Constructor가 private이면 접근할 수 있는 다른 method가 존재하는데 static 형태로 제공된다. 

(Constructor 실행을 포함하고 있으므로...)

static 형태 method 실행하는 방법이 잘 안나와서;; 쓸데없이 헤맸다.

방법은 method.invoke 시에 instance 위치에 null 설정;;;

제대로 공부 안하고 급하게 써먹으려다가 시간 뺏김ㅠ

try { 

// method 설정 

Method method = loadClass.getDeclaredMethod("getInstance", String.class);


// static method는 instance 위치를 null로 설정 

Object instance3 = method.invoke(null, "stringParameter"); 


} catch (NoSuchMethodException | SecurityException e1) { 

// method 가져올 때 Exception 

e1.printStackTrace(); 

} catch (IllegalArgumentException | InvocationTargetException e) {

// method 호출할 때 Exception 

e.printStackTrace();

}


4) 필요한 method를 실행

일반 method 실행 시에는 메소드 가져온 후 instance와 parameter 값 넣고 결과 값을 return받는다.

try {

Method runMethod = loadClass.getDeclaredMethod("run", Integer.class);


Object result = runMethod.invoke(instance1, 3);


} catch (NoSuchMethodException | SecurityException e1) {

// method 가져올 때 Exception 

e1.printStackTrace();

} catch (IllegalArgumentException | InvocationTargetException e) {

// method 호출할 때 Exception 

e.printStackTrace();

}


까먹기 전에 정리하기