-
스프링 부트 자동 구성스프링/스프링부트 2023. 9. 29. 14:34
스프링 부트는 자동 구성이라는 기능을 제공하는데, 일반적으로 자주 사용하는 많은 빈들을 자동으로 구성해주는 기능이다.
물론 개발자가 직접 빈을 등록하면 개발자가 등록한 빈을 사용하고, 자동 구성은 동작하지 않는다.
@Slf4j @Configuration public class DbConfig { @Bean public DataSource dataSource() { log.info("dataSource 빈 등록"); HikariDataSource dataSource = new HikariDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setJdbcUrl("jdbc:h2:mem:test"); dataSource.setUsername("sa"); dataSource.setPassword(""); return dataSource; } @Bean public TransactionManager transactionManager() { log.info("transactionManager 빈 등록"); return new JdbcTransactionManager(dataSource()); } @Bean public JdbcTemplate jdbcTemplate() { log.info("jdbcTemplate 빈 등록"); return new JdbcTemplate(dataSource()); } }
예를 들어 JdbcTemplate을 사용할 때에는 이렇게 스프링 빈들을 Configuration에 등록해줘야 하는데, 이렇게 따로 등록해주지 않더라도 자동 구성 기능으로 사용할 수 있다는 것이다.
공식 라이브러리는 build.gradle에서 spinrg-boot-starter-web 등을 implementation 해주면 자동으로 위에처럼 JdbcTemplate이랑 dataSource 등을 사용할 수 있다.
아래는 사용자가 만든 라이브러리를 사용하는 방법이다.
공부를 위한 예제 코드들 - jar 파일로 build해서 라이브러리로 사용할 예정
Memory.class
public class Memory { private long used; private long max; public Memory(long used, long max) { this.used = used; this.max = max; } public long getUsed() { return used; } public long getMax() { return max; } @Override public String toString() { return "Memory{" + "used=" + used + ", max=" + max + '}'; } }
MemoryFinder
@Slf4j public class MemoryFinder { public Memory get() { long max = Runtime.getRuntime().maxMemory(); long total = Runtime.getRuntime().totalMemory(); long free = Runtime.getRuntime().freeMemory(); // total 중에 사용하지 않은 메모리 long used = total - free; return new Memory(used, max); } @PostConstruct public void init() { log.info("init memoryFinder"); } }
MemoryController
@Slf4j @RestController @RequiredArgsConstructor public class MemoryController { private final MemoryFinder memoryFinder; @GetMapping("/memory") public Memory system() { Memory memory = memoryFinder.get(); log.info("memory={}", memory); return memory; } }
순수 라이브러리의 사용
위에서 memory 기능을 구현했는데 이것이 좋은 기능이라 라이브러리로 만들어서 다른 사람들이 사용할 수도 있다. 스프링 자동 구성을 사용하지 않고 그냥 라이브러리를 사용할 때에는 memory jar파일을 implementation 해주면 된다.
1) jar 파일을 프로젝트의 libs에 넣는다.
2) build.gradle에 implementation으로 jar 파일을 추가해준다.
dependencies { implementation files('libs/memory-v1.jar') // 추가 .... }
3) jar 파일의 클래스들을 스프링 빈으로 추가해준다.
@Configuration public class MemoryConfig { @Bean public MemoryFinder memoryFinder() { return new MemoryFinder(); } @Bean public MemoryController memoryController() { return new MemoryController(memoryFinder()); } }
하지만 이러한 방식은 라이브러리를 사용하는 클라이언트 개발자 입장에서 내부에 있는 클래스들을 하나하나 빈으로 등록해야하고, 어떤 빈을 등록해야하는지도 알아야 한다. 위의 예제는 간단한 라이브러리를 사용하지만 복잡한 설정이 필요하다면 오류가 발생할 수도 있고 개발자가 힘들 것이다.
이러한 단점들을 자동으로 처리해주는 것이 바로 스프링 부트 자동 구성이다.
스프링 부트의 자동 구성 라이브러리
@AutoConfiguration @ConditionalOnProperty(name = "memory", havingValue = "on") public class MemoryAutoConfig { @Bean public MemoryController memoryController() { return new MemoryController(memoryFinder()); } @Bean public MemoryFinder memoryFinder() { return new MemoryFinder(); } }
@AutoConfiguration이라는 어노테이션을 넣어서 자동 구성을 설정해준다. 이후에 @ConditionalOnProperty라는 어노테이션으로 특정 조건에서만 빈이 주입되도록 설정한다.
resuources 파일에 META-INF-spring 경로에 파일을 만들어준다.
이 때의 파일 이름은 org.springframework.boot.autoconfigure.AutoConfiguration.imports로 해야한다. 파일의 내용은 memory.MemoryAutoConfig를 넣어주는데, java 이후에 있는 파일과 메서드명의 최종 경로를 넣어줘야 한다.
이후에 jar 파일을 생성하고 위와 같은 방법처럼 libs에 jar파일을 복사한 다음 build.gradle에 implementation을 해준다.
이런 방식으로 스프링 부트 자동 구성이 적용되어 있어서 따로 빈을 등록하지 않아도 라이브러리에 있는 파일들을 사용할 수 있다. localhost:8080/memory로 들어가면 페이지가 나오겠지만, @Conditional 어노테이션으로 인한 추가 설정도 필요하다.
memory=on 옵션을 해주고 나면 최종적으로 localhost:8080/memory에 접근할 수 있다.
결론
사용자 입장에서 생각해보면 라이브러리가 뭔지도 모르고 build.gradle에 implementation을 추가해줬을 뿐인데 라이브러리의 기능을 사용할 수 있게 된 것이다.
(memory=on 같은 거는 특이사항이기 때문에 라이브러리를 갖다 쓰는 사람에게 별도로 알려주면 된다.)
별도로 빈을 주입하거나 따로 해야할 것이 없이 스프링 부트가 자동 구성을 잘 해놔서 가능한 기능이다.
'스프링 > 스프링부트' 카테고리의 다른 글
외부 설정 3 - 커맨드 라인 인수 (0) 2023.09.30 외부 설정 2 - 자바 시스템 속성 (0) 2023.09.30 외부 설정 1 - OS 환경 변수 (0) 2023.09.30 외부 설정이란? (0) 2023.09.30 WAR(Web Application Archive) (0) 2023.09.27