@Data
public class Member {
private String memberId;
private String name;
public Member() {
}
public Member(String memberId, String name) {
this.memberId = memberId;
this.name = name;
}
}
@Repository
public class MemberRepository {
private final JdbcTemplate template;
public MemberRepository(JdbcTemplate template) {
this.template = template;
}
public void initTable() {
template.execute("create table member(member_id varchar primary key, name varchar)");
}
public void save(Member member) {
template.update("insert into member(member_id, name) values (?,?)",
member.getMemberId(),
member.getName());
}
public Member find(String memberId) {
return template.queryForObject("select member_id, name from member where member_id=?",
BeanPropertyRowMapper.newInstance(Member.class),
memberId);
}
public List<Member> findAll() {
return template.query("select member_id, name from member",
BeanPropertyRowMapper.newInstance(Member.class));
}
}
@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());
}
}
@Slf4j
@SpringBootTest
class DbConfigTest {
@Autowired
DataSource dataSource;
@Autowired
TransactionManager transactionManager;
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void checkBean() {
log.info("dataSource = {}", dataSource);
log.info("transactionManager = {}", transactionManager);
log.info("jdbcTemplate = {}", jdbcTemplate);
assertThat(dataSource).isNotNull();
assertThat(transactionManager).isNotNull();
assertThat(jdbcTemplate).isNotNull();
}
}
- @Configuration을 주석 처리해 DataSource, TransactionManager, JdbcTemplate을 빈 등록하지 않았지만 테스트 코드에서는 정상 작동이 된다. 왜냐하면 스프링부트가 자동으로 이 3개를 등록해주기 때문이다.
package memory;
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 +
'}';
}
}
package memory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@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;
}
}
package memory;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MemoryFinder {
public Memory get() {
long max = Runtime.getRuntime().maxMemory();
long total = Runtime.getRuntime().totalMemory();
long free = Runtime.getRuntime().freeMemory();
long used = total - free;
return new Memory(used, max);
}
@PostConstruct
public void init() {
log.info("init memoryFinder");
}
}
package memory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
@Slf4j
public class MemoryCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//-Dmemory=on
String memory = context.getEnvironment().getProperty("memory");
log.info("memory={}", memory);
return "on".equals(memory);
}
}
- MemoryCondition을 직접 구현했다.
package hello.config;
import memory.MemoryCondition;
import memory.MemoryController;
import memory.MemoryFinder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
//@Conditional(MemoryCondition.class)
@ConditionalOnProperty(name = "memory", havingValue = "on")
public class MemoryConfig {
@Bean
public MemoryController memoryController() {
return new MemoryController(memoryFinder());
}
@Bean
public MemoryFinder memoryFinder() {
return new MemoryFinder();
}
}
@Configuration
@Conditional(MemoryCondition.class)
public class MemoryConfig {
@Bean
public MemoryController memoryController() {
return new MemoryController(memoryFinder());
}
@Bean
public MemoryFinder memoryFinder() {
return new MemoryFinder();
}
}
- @Conditional(MemoryCondition.class) 으로 MemoryConfig로 설정할 수 있게 해준다.
@Configuration
@ConditionalOnProperty(name = "memory", havingValue = "on")
public class MemoryConfig {
@Bean
public MemoryController memoryController() {
return new MemoryController(memoryFinder());
}
@Bean
public MemoryFinder memoryFinder() {
return new MemoryFinder();
}
}
- 직접 구현했지만 스프링부트는 이미 많은 conditional이 내재되어 있다. @ConditionalOnProperty(name = "memory", havingValue = "on")으로 MemoryConfig를 설정할 수 있게 해준다.
@ConditionalXxx
- @ConditionalOnClass , @ConditionalOnMissingClass - 클래스가 있는 경우 동작한다. 나머지는 그 반대
- @ConditionalOnBean , @ConditionalOnMissingBean - 빈이 등록되어 있는 경우 동작한다. 나머지는 그 반대
- @ConditionalOnProperty - 환경 정보가 있는 경우 동작한다.
- @ConditionalOnResource - 리소스가 있는 경우 동작한다.
- @ConditionalOnWebApplication , @ConditionalOnNotWebApplication - 웹 애플리케이션인 경우 동작한다.
- @ConditionalOnExpression - SpEL 표현식에 만족하는 경우 동작한다.
'개발이 좋아서 > Spring이 좋아서' 카테고리의 다른 글
Spring boot - 외부설정(yml) (0) | 2025.01.06 |
---|---|
Spring boot - 외부 설정(Environment, @Value, @ConfigurationProperties) (1) | 2025.01.03 |
Springboot - 핵심 기능 5가지 (0) | 2025.01.02 |
AOP - 실무 주의사항(프록시와 내부 호출) (0) | 2025.01.02 |
AOP - 실전 예제 (0) | 2025.01.02 |