WEB/Spring Boot

Spring JDBC 자동 구성 개발

Tony Lim 2023. 2. 14. 11:40
728x90

자동 구성 클래스와 빈 설계

@MyAutoConfiguration
@ConditionalMyOnClass("org.springframework.jdbc.core.JdbcOperations")
@EnableMyConfigurationProperties(MyDataSourceProperties.class)
@EnableTransactionManagement
public class DataSourceConfig {
    @Bean
    @ConditionalMyOnClass("com.zaxxer.hikari.HikariDataSource")
    @ConditionalOnMissingBean
    DataSource hikariDataSource(MyDataSourceProperties properties) {
        HikariDataSource dataSource = new HikariDataSource();

        dataSource.setDriverClassName(properties.getDriverClassName());
        dataSource.setJdbcUrl(properties.getUrl());
        dataSource.setUsername(properties.getUsername());
        dataSource.setPassword(properties.getPassword());

        return dataSource;
    }

    @Bean
    @ConditionalOnMissingBean
    DataSource dataSource(MyDataSourceProperties properties) throws ClassNotFoundException {
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();

        dataSource.setDriverClass((Class<? extends Driver>) Class.forName(properties.getDriverClassName()));
        dataSource.setUrl(properties.getUrl());
        dataSource.setUsername(properties.getUsername());
        dataSource.setPassword(properties.getPassword());

        return dataSource;
    }

    @Bean
    @ConditionalOnSingleCandidate(DataSource.class)
    @ConditionalOnMissingBean
    JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    @ConditionalOnSingleCandidate(DataSource.class)
    @ConditionalOnMissingBean
    JdbcTransactionManager jdbcTransactionManager(DataSource dataSource) {
        return new JdbcTransactionManager(dataSource);
    }
}

@EnableMyConfigurationProperties 를활용해서 저번처럼 인자로 주입받은 클래스를 @Import를 통해 내부적으로 빈으로 등록하게 된다.

@ConditionalOnMissingBean을 통해서 같은 Datasouce 빈이 여러번 생성되는것을 방지한다.

@ConditionalOnSingleCandidate 를 통해서 주입받은 클래스가 한개만 빈으로 존재할떄 실행되게 만든다.

@MyConfigurationProperties(prefix = "data")
public class MyDataSourceProperties {
@MyAutoConfiguration
public class PropertyPostProcessorConfig {
    @Bean BeanPostProcessor propertyPostProcessor(Environment env) {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                MyConfigurationProperties annotation = findAnnotation(bean.getClass(), MyConfigurationProperties.class);
                if (annotation == null) return bean;

                Map<String, Object> attrs = getAnnotationAttributes(annotation);
                String prefix = (String) attrs.get("prefix");

                return Binder.get(env).bindOrCreate(prefix, bean.getClass());
            }
        };
    }
}

그러면 빈으로 등록되고 나서 저번에 등록한 BeanPostProcessor에서 @MyConfigurationProperties annotation을 확인하고 application.properties에 쓰인 정보와 mapping 해서 채워넣어준다.

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = HellobootApplication.class)
@TestPropertySource("classpath:/application.properties")
@Transactional
public @interface HellobootTest {
}
@HellobootTest
public class DataSourceTest {
    @Autowired DataSource dataSource;

    @Test
    void connect() throws SQLException {
        Connection connection = dataSource.getConnection();
        connection.close();
    }
}

@ExtendWith(SpringExtension.class) = spring container를 활용할 수 있게 해준다.

@ContextConfiguration = 인자로 준 HellobootApplication을 통해 모든 빈들을 만들 정보들을 가져오게된다. coponent scan을 통해 다 긁어모은다.

test시 @TestPropertySource를 통해 어떤 properties를 참고하여 MyDatasource 빈을 만들어야하는지 알려줘야한다.

 

 

 

728x90