저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의

'ImportSelector'에 해당되는 글 1건

  1. 2016.05.30 스프링 @Enable 설정 세 가지 구현 방식

스프링 3.0 버전까지만 해도 스프링 자바 설정이 상대적으로 인기가 없었는데, 주된 이유는 XML의 네임스페이스 기반 설정 편의 기능을 대체하지 못했기 때문이었다. 스프링 3.1 버전부터 자바 설정도 편의 기능을 제공하기 시작했는데 그것이 바로 @Enable로 시작하는 애노테이션 설정이다. @Enable 설정 편의 애노테이션은 사용자를 대신해서 많은 설정을 대신 해준다. 예를 들어, @EnableWebMvc의 경우 100여 줄에 가까운 설정 코드륻 대신 한다. 


스프링이 제공하는 @Enable 설정 편의 기능뿐만 아니라 직접 @Enable 설정 편의 애노테이션을 만들 수도 있는데, 크게 세 가지 방법이 존재한다.


1. 설정을 임포트하는 @Enable 애노테이션


첫 번째 방법은 @Configuration 설정을 임포트하는 @Enable 애노테이션을 작성하는 것이다. 예를 들어, 다음 @Configuration 설정을 보자.


@Configuration

public class MyCompanyConfig {

    

    @Bean

    public Authenticator authenticator() {

        Authenticator authenticator = new Authenticator();

        ...

        return authenticator;

    }


}


이 설정을 자동으로 처리하는 @Enable 애노테이션은 다음과 같이 구현할 수 있다.


@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Import(MyCompanyConfig.class)

@interface EnableMyCompany {}


@Import 속성은 설정으로 사용할 클래스를 지정한다.


이제 @EnableMyCompany 애노테이션을 설정에 추가하면 MyCompanyConfig에 포함된 설정을 자동으로 포함시킨다.


@Configuration

@EnableMyCompany

public class AppConfig {


    @Autowired

    private Authenticator authenticator;


    ...

}



2. ImportSelector 사용하기


두 번째 방법은 ImportSelector를 사용하는 것이다. 애노테이션 애트리뷰트 값에 따라 다른 설정 클래스를 사용하고 싶을 때 이 방식을 사용한다. 예를 들어, 다음 @Enable 애노테이션을 보자.


@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Import(CompanyConfigSelector.class)

public @interface EnableAuthConfig {

    ClientType type() default ClientType.HTTP;

}


이 애노테이션은 type 애트리뷰트를 갖고 있다.


@Import에 지정한 CompanyConfigSelector는 ImportSelector 인터페이스를 구현한 클래스로서 다음 코드처럼 @EnableAuthConfig 애노테이션의 type 애트리뷰트 값에 따라 사용할 설정 클래스 이름을 리턴하도록 구현한다. ImportSelector 자체는 설정 클래스가 아니므로 @Configuration이 붙지 않는다.


public class CompanyConfigSelector implements ImportSelector {

    @Override

    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

        Map<String, Object> attributesMap = 

                 importingClassMetadata.getAnnotationAttributes(

                         EnableAuthConfig.class.getName(), false);

        AnnotationAttributes attributes = AnnotationAttributes.fromMap(attributesMap);

        ClientType typeValue = attributes.<ClientType>getEnum("type");

        if (typeValue == ClientType.HTTP) {

            return new String[]{HttpAuthClientConfiig.class.getName()};

        } else if (typeValue == ClientType.PROTOBUFF) {

            return new String[]{ProtobuffAuthClientConfig.class.getName()};

        }

        return new String[0];

    }

}



ImportSelector의 selectImport() 메서드는 String 배열을 리턴하는데, 이 배열은 설정으로 사용할 클래스 이름을 값으로 갖는다. 위 코드의 경우 @EnableAuthConfig 애노테이션의 type 애트리뷰트 값에 따라 HttpAuthClientConfig나 ProtobuffAuthClient를 설정으로 사용하도록 구현하고 있다. 이 두 클래스는 다음과 같이 @Configuration을 이용한 설정 클래스이다.


@Configuration

public class HttpAuthClientConfiig {

    @Bean

    public HttpAuthClient authClient() {

        return new HttpAuthClient();

    }

}


이제 @EnableAuthConfig 애노테이션을 사용하면 type 애트리뷰트 값에 따라 알맞은 설정을 사용하게 된다. 예를 들어, 아래 코드는 ProtobuffAuthClientConfig를 설정으로 사용하게 된다.


@Configuration

@EnableAuthConfig(type = ClientType.PROTOBUFF)

public class AppConfig {}



3. ImportBeanDefinitionRegistrar 사용하기


세 번째 방법은 ImportBeanDefinitionRegistrar을 사용하는 것이다. ImportSelector가 설정으로 사용할 클래스 이름을 리턴하는 방식이라면 ImportBeanDefinitionRegistrar는 빈 설정을 직접 등록하는 방식이다. 이 방식은 기존에 XML 스키마 확장 방식을 자바 설정으로 마이그레이션하고자 할 때 사용할 때 좋다.


Enable 애노테이션은 동일하다. 다음과 같이 @Import로 ImportBeanDefinitionRegistrar 인터페이스를 구현한 클래스를 지정하면 된다.


@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Import(CompanyConfigRegistrar.class)

public @interface EnableCompSecConfig {

    ClientType type() default ClientType.HTTP;

}


ImportBeanDefinitionRegistrar 인터페이스를 구현한 클래스는 애노테이션 애트리뷰트 정보를 이용해서 알맞은 빈 설정을 등록하면 된다. 다음은 간단한 구현 예이다.


public class CompanyConfigRegistrar implements ImportBeanDefinitionRegistrar {

    @Override

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,

            BeanDefinitionRegistry registry) {

        Map<String, Object> attributesMap = 

                importingClassMetadata.getAnnotationAttributes(

                        EnableCompSecConfig.class.getName(), false);

        AnnotationAttributes attributes = AnnotationAttributes.fromMap(attributesMap);

        ClientType typeValue = attributes.<ClientType>getEnum("type");

        if (typeValue == ClientType.HTTP) {

            BeanDefinition beanDef = new RootBeanDefinition("comp.config.HttpAuthClient");

            registry.registerBeanDefinition("authClient", beanDef);

        } else if (typeValue == ClientType.PROTOBUFF) {

            BeanDefinition beanDef = 

                    new RootBeanDefinition("comp.config.ProtobuffAuthClientConfiig");

            registry.registerBeanDefinition("authClient", beanDef);

        }

    }

}



이제 @EnableCompSecConfig를 사용하면 CompanyConfigRegistrar에서 등록한 빈 설정이 자등으로 추가된다.


@Configuration

@EnableCompSecConfig(type = ClientType.HTTP)

public class AppConfig {



Posted by 최범균 madvirus

댓글을 달아 주세요