Concise Proxy Definitions

2023. 5. 3. 15:11Spring Framework/Spring AOP APIs

특히 트랜잭션 프록시를 정의할 때, 유사한 프록시 정의가 많이 생길 수 있습니다. 부모-자식 빈 정의와 내부 빈 정의를 사용하면 훨씬 깔끔하고 간결한 프록시 정의를 만들 수 있습니다.

먼저, 다음과 같이 프록시를 위한 부모(템플릿) 빈 정의를 생성합니다:

XML 기반 구성:

<bean id="txProxyTemplate" abstract="true"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

자바 기반 구성:

@Configuration
public class AppConfig {

    @Bean
    public TransactionProxyFactoryBean txProxyTemplate(TransactionManager transactionManager) {
        TransactionProxyFactoryBean proxyFactoryBean = new TransactionProxyFactoryBean();
        proxyFactoryBean.setTransactionManager(transactionManager);

        Properties transactionAttributes = new Properties();
        transactionAttributes.setProperty("*", "PROPAGATION_REQUIRED");
        proxyFactoryBean.setTransactionAttributes(transactionAttributes);

        // 이 Bean은 템플릿이므로 추상적으로 처리됩니다.
        proxyFactoryBean.setProxyTargetClass(true);

        return proxyFactoryBean;
    }
}

이 빈은 실제로 인스턴스화되지 않으므로 불완전할 수도 있습니다. 그런 다음, 생성해야 하는 각 프록시는 자식 빈 정의로 생성되며, 프록시의 대상은 어차피 독립적으로 사용되지 않으므로 내부 빈 정의로 감쌉니다.

XML 기반 구성:

<bean id="myService" parent="txProxyTemplate">
    <property name="target">
        <bean class="org.springframework.samples.MyServiceImpl">
        </bean>
    </property>
</bean>

자바 기반 구성:

@Bean
public TransactionProxyFactoryBean myService(TransactionManager transactionManager) {
    TransactionProxyFactoryBean proxyFactoryBean = new TransactionProxyFactoryBean();
    proxyFactoryBean.setTransactionManager(transactionManager);

    // 대상 설정
    MyServiceImpl target = new MyServiceImpl();
    proxyFactoryBean.setTarget(target);

    // 부모 템플릿 설정 사용
    Properties transactionAttributes = new Properties();
    transactionAttributes.setProperty("*", "PROPAGATION_REQUIRED");
    proxyFactoryBean.setTransactionAttributes(transactionAttributes);

    return proxyFactoryBean;
}

부모 템플릿의 속성을 재정의할 수도 있습니다. 다음 예제에서는 트랜잭션 전파 설정을 재정의합니다:

XML 기반 구성:

<bean id="mySpecialService" parent="txProxyTemplate">
    <property name="target">
        <bean class="org.springframework.samples.MySpecialServiceImpl">
        </bean>
    </property>
    <property name="transactionAttributes">
        <props>
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="store*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

자바 기반 구성:

@Bean
public TransactionProxyFactoryBean mySpecialService(TransactionManager transactionManager) {
    TransactionProxyFactoryBean proxyFactoryBean = new TransactionProxyFactoryBean();
    proxyFactoryBean.setTransactionManager(transactionManager);

    // 대상 설정
    MySpecialServiceImpl target = new MySpecialServiceImpl();
    proxyFactoryBean.setTarget(target);

    // 트랜잭션 속성 재정의
    Properties transactionAttributes = new Properties();
    transactionAttributes.setProperty("get*", "PROPAGATION_REQUIRED,readOnly");
    transactionAttributes.setProperty("find*", "PROPAGATION_REQUIRED,readOnly");
    transactionAttributes.setProperty("load*", "PROPAGATION_REQUIRED,readOnly");
    transactionAttributes.setProperty("store*", "PROPAGATION_REQUIRED");
    proxyFactoryBean.setTransactionAttributes(transactionAttributes);

    return proxyFactoryBean;
}

부모 빈 예제에서 abstract 속성을 true로 설정하여 부모 빈 정의를 명시적으로 추상적으로 표시한 것에 주목하세요. 이는 이 빈이 실제로 인스턴스화되지 않도록 하기 위함입니다. 자바 기반 구성에서는 이 부분을 코드로 직접 처리하며, 특정 클래스를 템플릿으로만 사용하려는 경우에도 마찬가지로 설정할 수 있습니다.