Spring: делегировать пользовательской оболочке прокси для инъекции интерфейса
в очень большом устаревшем приложении у меня есть интерфейсы и классы, которые делают не реализующие эти интерфейсы.
интерфейсы генерируются на основе класса, поэтому подписи одинаковы (за исключением того, что интерфейс добавляет еще одно исключение сверху), а имена похожи (поэтому легко найти имя класса из имени интерфейса).
чтобы получить реализацию интерфейса, мы делаем кучу вызовов обработки и регистрации, но в основном используем java.lang.reflect.Proxy
делегировать класс. Упрощенно это выглядит так:
// This will create a proxy and invoke handler that calls HelloWorld.doSomething
HelloWorldInterface i = MyProxyUtil.getInstance(HelloWorldInterface.class);
i.doSomething();
public interface HelloWorldInterface {
public void doSomething() throws Exception;
}
public class HelloWorld {
public void doSomething() {
//something
}
}
возможно ли с обработкой аннотаций Spring, чтобы в целом @Autowire
все поля типа *Interface
и весной использовать MyProxyUtil.getInstance(*Interface.class)
ввести реализацию?
такое, что
@Autowire HelloWorldInterface a;
HelloWorldInterface b = MyProxyUtil.getInstance(HelloWorldInterface.class);
@Autowire AnotherInterface c;
AnotherInterface d = MyProxyUtil.getInstance(AnotherInterface.class);
a == b
c == d
2 ответов
да, вам нужно реализовать AutowireCandidateResolver
.
например:
public class ProxyAutowiredCandidateResolver extends SimpleAutowireCandidateResolver {
@Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
String dependencyClassName = descriptor.getDependencyType().getSimpleName();
if (dependencyClassName.endsWith("Interface")) {
return MyProxyUtil.getInstance(descriptor.getDependencyType());
}
return super.getSuggestedValue(descriptor);
}
}
вы могли бы использовать BeanFactoryPostProcessor
чтобы настроить его в контексте приложения:
public class AutowireCandidateResolverConfigurer implements BeanFactoryPostProcessor {
private AutowireCandidateResolver autowireCandidateResolver;
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory bf = (DefaultListableBeanFactory) beanFactory;
bf.setAutowireCandidateResolver(autowireCandidateResolver);
}
public AutowireCandidateResolver getAutowireCandidateResolver() {
return autowireCandidateResolver;
}
public void setAutowireCandidateResolver(
AutowireCandidateResolver autowireCandidateResolver) {
this.autowireCandidateResolver = autowireCandidateResolver;
}
}
<bean id="autowireCandidateResolverConfigurer" class="AutowireCandidateResolverConfigurer">
<property name="autowireCandidateResolver">
<bean class="ProxyAutowiredCandidateResolver" />
</property>
</bean>
Если я читаю это правильно, вы должны иметь возможность определить их в аннотированном классе JavaConfig @Configuration, а затем использовать их в другом месте.
документы (Весна):
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
вы могли бы сделать нечто подобное:
@Configuration
public class InterfaceConfig {
@Bean
public HelloWorldInterface helloWorldInterface() {
return MyProxyUtil.getInstance(HelloWorldInterface.class);
}
}
в этот момент весна будет использовать это определение всякий раз, когда этот Боб был необходим.
вам нужно будет как-то связать в классе @Configuration (сканирование пути к классу, программно и т. д.), Но это зависит от того, как вы настраиваете контекст приложения.
Я думаю, что это должно работать. Я использовал JavaConfig совсем немного, но никогда не совсем так. Но это кажется разумным.