티스토리 뷰
스프링 프레임워크 사용하다가 궁금한 것이 생겼습니다.
다 같은 어노테이션인데 굳이 왜 나누어 놓았을까? 분명 이유가 있겠죠?
모르는 것은 바로 궁금증을 해결해보아야 되죠!!
이번 글에서는 @Bean과 @Component의 차이에 대해 살펴보려고 합니다.
@Bean
외부 라이브러리지만 개발자가 컨트롤이 불가능한 경우 사용한다고 합니다.
예를 들어, Redis를 사용하는 경우가 있습니다.
@Configuration
public class RedisConfig {
private @Value("${spring.redis.host}") String redisHost;
private @Value("${spring.redis.port}") int redisPort;
@Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(redisHost);
jedisConnectionFactory.setPort(redisPort);
jedisConnectionFactory.setUsePool(true);
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory());
return redisTemplate;
}
}
Redis의 경우 application.yml에서 제공받은 변수를 할당받아 적용해야 하는데, 이때 사용합니다.
다른 경우도 한 번 보겠습니다.
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("customExecutor")
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(30);
executor.setThreadNamePrefix("Async-");
executor.setKeepAliveSeconds(5);
executor.initialize();
return executor;
}
}
이번에는 비동기 서비스에서 사용하는 AsynConfig 파일을 가져와보았습니다. 딱 정해진 값에만 세팅을 해서 return 하고 있네요.
@Configuration
@MapperScan(basePackages = "kr.abbo.app.api", annotationClass = abboDB.class, sqlSessionFactoryRef = "abboSqlSessionFactory")
public class MybatisDatasourceConfig {
@Bean("abboSqlSessionFactory")
public SqlSessionFactory abboSqlSessionFactory(@Qualifier("abboDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
PathMatchingResourcePatternResolver pathResolver = new PathMatchingResourcePatternResolver();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setTypeAliasesPackage("kr.abbo.app.api.model");
sessionFactoryBean.setConfigLocation(pathResolver.getResource("classpath:mybatis/MybatisConfiguration.xml"));
sessionFactoryBean.setMapperLocations(pathResolver.getResources("classpath:**/*Mapper.xml"));
sessionFactoryBean.setVfs(SpringBootVFS.class);
return sessionFactoryBean.getObject();
}
}
마지막으로 지정된 곳은 데이터 소스 부분인데요, 이 부분은 Database에 연결시키기 위해 스키마와 다른 부가 옵션을 설정하는 곳입니다. 위의 설정 파일들을 모두 확인해보니 @Configuration이 설정된 클래스 내에 모두 선언이 되어있고, 각 클래스마다 설정값이 다르게 매겨져 있는 것을 확인할 수 있습니다.
@ComponentScan의 경우는 Spring Boot가 기동 되면서 Bean에 파일을 연결시켜줄 수 있는 어노테이션입니다.
@Component
이번에는 컴포넌트 어노테이션에 대해 정리해볼 텐데요, @Component는 검색해보니 개발자가 컨트롤이 가능한 클래스의 경우 사용한다고 합니다. 예시를 바로 보겠습니다.
@Slf4j
@Component
public class FileUploadUtil {
// 추후에 application.yml에 value로 불러오도록 수정
private String ACCESS_KEY = "...";
private String SECRET_KEY = "......";
private String BUCKET_NAME = "cdn-s3.abbo.kr";
private static String DOMAIN = "http://images-cdn.abbo.kr";
private static String ROOT = "/app/user";
private static String PATH_FORMAT = "/yyyy/MM/dd";
public String imageUpload(MultipartFile file) {
try {
byte[] fileData = IOUtils.toByteArray(file.getInputStream());
String sourceFileName = file.getOriginalFilename();
String fileExt = FilenameUtils.getExtension(sourceFileName).toLowerCase();
String path = new SimpleDateFormat(PATH_FORMAT).format(new Date());
String contentType = file.getContentType();
String fileName = System.currentTimeMillis() + "." + fileExt;
s3Upload(ROOT + path, fileName, contentType, fileData);
return DOMAIN + ROOT + path + "/" + fileName;
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
return null;
}
}
}
파일 업로드를 하는 유틸리티 클래스를 가져와 보았습니다. 오, 이번에는 내부에 로직이 정해져 있네요.
하나 더 샘플을 봐야 감이 올 것 같습니다.
@Slf4j
@Component
@Profile("prd")
public class MemoryHealth {
@Autowired ElasticsearchConfig logConfig;
@PostConstruct
public void init(){
ManagementFactory.getMemoryPoolMXBeans().parallelStream().forEach(memoryPoolMXBean -> log.info("memoryPoolMXBean.getName() --- " + memoryPoolMXBean.getName()));
}
@Scheduled(initialDelay = 1000, fixedDelay = 60000)
public void check(){
Map<String, Object> memInfo = new HashMap<>();
try {
memInfo.put("server", InetAddress.getLocalHost().getCanonicalHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
ManagementFactory.getMemoryPoolMXBeans().parallelStream().forEach(memoryPoolMXBean -> {
switch (memoryPoolMXBean.getName()){
case "Code Cache":
memInfo.put("codeCache", memoryPoolMXBean.getUsage().getUsed());
break;
case "Metaspace":
memInfo.put("metaSpace", memoryPoolMXBean.getUsage().getUsed());
break;
case "Compressed Class Space":
memInfo.put("compressedClassSpace", memoryPoolMXBean.getUsage().getUsed());
break;
case "Eden Space":
case "PS Eden Space":
memInfo.put("psEdenSpace", memoryPoolMXBean.getUsage().getUsed());
break;
case "Survivor Space":
case "PS Survivor Space":
memInfo.put("psSurvivorSpace", memoryPoolMXBean.getUsage().getUsed());
break;
case "Tenured Gen":
case "PS Old Gen":
memInfo.put("psOldGen", memoryPoolMXBean.getUsage().getUsed());
break;
}
memInfo.put("createdDatetime", System.currentTimeMillis());
});
}
}
이번에 작성된 유틸리티는 운영 중인 서버의 메모리 적재량을 확인하기 위해 구현된 소스입니다. 관리하고 있는 포인트가 꽤나 많기에 이러한 소스가 있다고만 짚고 넘어가 보겠습니다.
아무래도 @Bean과 @Component의 두 가지 어노테이션을 확인해 보았을 때 꽤나 차이가 있는 것을 확인하실 수 있을 거예요.
정리
@Bean: 이전에 제공된 라이브러리를 Setter, Builder를 통해 사용자가 Properties를 변경하여 생성한 instance
@Component: 개발자가 생성한 클래스를 Spring Boot에 등록하기 위해 instance를 생성하고 Bean에 등록하는 과정
'Server' 카테고리의 다른 글
Kotlin의 Any와 Nullable (1) (0) | 2020.06.29 |
---|---|
Kotlin의 Control Flow (0) | 2020.06.26 |
Kotlin의 함수(Function) (0) | 2020.06.26 |
Kotlin 변수의 Wrapper Type (0) | 2020.06.25 |
Kotlin 설치법 (0) | 2020.06.24 |
Kotlin이 뭐에요? (1) | 2020.06.22 |