You can use @Named
together with @Inject
to specify which bean to inject.
A simple example with an injected service:
public class ServiceTest {
@Inject
@Named("transactionDecorator")
private Service service;
}
And the corresponding transaction decorator class:
@org.springframework.stereotype.Service("transactionDecorator")
public class ServiceDecoratorTransactionSupport extends ServiceDecorator {
@Inject
@Named("serviceBean")
public ServiceDecoratorTransactionSupport(Service service) {
super(service);
}
}
This exposes your configuration into your code, so I would recommend doing the decorating logic in a @Configuration
class and annotate for example the logging service with @Primary
. With this approach your test class can look something like this:
public class ServiceTest {
@Inject
private Service service;
And the configuration class:
@Configuration
public class DecoratorConfig {
@Bean
@Primary
public ServiceDecorator serviceDecoratorSecurity() {
return new ServiceDecoratorSecuritySupport(
serviceDecoratorTransactionSupport());
}
@Bean
public ServiceDecorator serviceDecoratorTransactionSupport() {
return new ServiceDecoratorTransactionSupport(serviceBean());
}
@Bean
public Service serviceBean() {
return new ServiceImpl(serviceRepositoryEverythingOkayStub());
}
@Bean
public ServiceRepository serviceRepositoryEverythingOkayStub() {
return new ServiceRepositoryEverythingOkStub();
}
}
My second example doesn't expose any details about which implementation that will be returned, but it depends on several Spring specific classes.
You can also combine the two solutions. For example use Spring's @Primary
annotation on a decorator and let Spring inject this decorator into the instance of the given type.
@Service
@Primary
public class ServiceDecoratorSecuritySupport extends ServiceDecorator {
}