Search

reflection-api-spring-ioc-container

reflection api 이용하여 spring ioc container 만들기

{% hint style=“info” %} 인프런 백기선님의 강의 <더 자바, 코드를 조작하는 다양한 방법> 을 수강하면서 공부한 내용을 정리합니다. {% endhint %}

1. 이해하기

1-1. project : container-flash

1.
@Inject annotation 을 만들고
2.
FlashContainer 를 만든다.
a.
getObject() 에서는
i.
리플렉션 API 를 이용하여 생성자 및 인스턴스를 만들고
ii.
@Inject annotation 이 붙은 인스턴스 필드가 있다면, 생성된 인스턴스에 주입시켜주는 역할을 수행한다.
3.
gradle clean build 하여 외부 프로젝트에서 의존성 추가하여 사용할 수 있도록 한다.

1-2. project : container-apply

1.
신규 프로젝트를 생성하고, libs 폴더를 만들어 1-1 에서 생성한 jar 파일을 옮겨준다.
2.
build.gradle 에서 설정을 통해 의존성 설정을 해준다.
3.
Main 클래스에서 FlashConainer 를 통해 의존성 주입이 된 것을 확인한다.

2. 코드

2-1. project : container-flash

source tree 참고
@Retention(RetentionPolicy.RUNTIME)public @interface Inject {}
Java
복사
public class FlashContainer { public static <T> T getObject(Class<T> classType) { T instance = createInstance(classType); //생성자 방식으로 클래스 타입에 대한 객체 생성 Arrays.stream(classType.getDeclaredFields()).forEach(field -> { //클래스에 정의된 필드들 중, Inject type 어노테이션이 붙어있는 필드 조회 if (field.getAnnotation(Inject.class) != null) { Object injectedInstance = createInstance(field.getType()); //해당 필드에 대해서 객체를 만들고 field.setAccessible(true); //접근 제어자를 해제해준 뒤, try { field.set(instance, injectedInstance); //인스턴스에 해당 필드 타입의 인스턴스를 주입시켜준다. } catch (IllegalAccessException e) { e.printStackTrace(); } } }); return instance; } private static <T> T createInstance(Class<T> classType) { try { return classType.getConstructor(null).newInstance(); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException(e); } }}
Java
복사
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertNotNull;class FlashContainerTest { @Test void getObject_userRepository() { UserRepository userRepository = FlashContainer.getObject(UserRepository.class); //reflection 을 반환 assertNotNull(userRepository); } @Test void getObject_userService() { UserService userService = FlashContainer.getObject(UserService.class); assertNotNull(userService); assertNotNull(userService.userRepository); }}public class UserRepository {}public class UserService { @Inject UserRepository userRepository;}
Java
복사
//terminal gradle clean build
Plain Text
복사

2-2. project : container-apply

public class Main { public static void main(String[] args) { CustomerService customerService = FlashContainer.getObject(CustomerService.class); customerService.join(); //customerService:join //customerRepository:save } }
Java
복사
public class CustomerService { @Inject CustomerRepository customerRepository; public void join() { System.out.println("customerService:join"); customerRepository.save(); }}
Java
복사
public class CustomerRepository { void save() { System.out.println("customerRepository:save"); }}
Java
복사

3. 참고