2013-07-16 5 views
5

In einer sehr großen Legacy-Anwendung habe ich Schnittstellen und Klassen, die nicht diese Schnittstellen implementieren.Spring: Delegate zu benutzerdefinierten Proxy-Wrapper für die Schnittstelle Injektion

Die Schnittstellen werden basierend auf der Klasse generiert, so dass die Signaturen identisch sind (außer dass die Schnittstelle oben eine weitere Ausnahme hinzufügt) und die Namen ähnlich sind (daher ist es einfach, den Klassennamen aus dem Schnittstellennamen zu finden).

Um eine Implementierung der Schnittstelle zu erhalten, führen wir eine Reihe von Verarbeitungs- und Protokollierungsaufrufen durch, verwenden aber grundsätzlich java.lang.reflect.Proxy, um an die Klasse zu delegieren. Vereinfachtes sieht es wie folgt aus:

// 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 
    } 
} 

Ist es möglich, mit Federanmerkungsverarbeitung, um allgemein @Autowire alle Felder vom Typ *Interface und Feder Verwendung MyProxyUtil.getInstance(*Interface.class) die Umsetzung zu injizieren?

Derart, dass

@Autowire HelloWorldInterface a; 

HelloWorldInterface b = MyProxyUtil.getInstance(HelloWorldInterface.class); 

@Autowire AnotherInterface c; 

AnotherInterface d = MyProxyUtil.getInstance(AnotherInterface.class); 


a == b 
c == d 

Antwort

9

Ja, Sie müssen eine AutowireCandidateResolver implementieren.

Zum Beispiel:

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); 
    } 

} 

Sie könnten ein BeanFactoryPostProcessor verwenden Sie es im Anwendungskontext zu konfigurieren:

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> 
+0

Entschuldigung, ich habe Schwierigkeiten herauszufinden, wie Sie das tatsächlich konfigurieren, um verwendet zu werden? Was würde ich meiner applicationContext.xml hinzufügen? –

+0

@caselnelson Sie können einen 'BeanFactoryPostprocessor' verwenden, um den 'AutowireCandidateResolver' zu konfigurieren –

+0

Es gibt ein Problem beim Einbinden der Umgebung in Ihre Lösung -> https: // github.com/mariuszs/env-is-null – MariuszS

1

Wenn ich das richtig bin lesen, sollten Sie in der Lage sein, sie in einer JavaConfig @Configuration kommentierte Klasse zu definieren und sie dann an anderer Stelle verwenden.

Aus der Dokumentation (Spring):

@Configuration 
public class AppConfig { 
    @Bean 
    public MyService myService() { 
     return new MyServiceImpl(); 
    } 
} 

Sie könnten etwas Ähnliches tun:

@Configuration 
public class InterfaceConfig { 
    @Bean 
    public HelloWorldInterface helloWorldInterface() { 
     return MyProxyUtil.getInstance(HelloWorldInterface.class); 
    } 
} 

An diesem Punkt würde Frühling diese Definition verwenden, wenn die Bohne benötigt wurde.

Sie müssten irgendwie in der @Configuration-Klasse verknüpfen (Klassenpfad-Überprüfung, programmgesteuert, usw.), aber das hängt davon ab, wie Sie Ihren Anwendungskontext einrichten.

Ich denke, das sollte funktionieren. Ich habe JavaConfig ziemlich oft benutzt, aber nie so. Aber es scheint vernünftig.

+0

Es ist nicht wirklich praktisch für mich jede dieser Bohnen in der Config zu definieren (Es gibt hunderte). Stattdessen suche ich nach einer Möglichkeit, alle Schnittstellen aufzulösen, deren Name mit Interface durch MyProxyUtil endet. –

+0

Ich habe diesen Teil nicht verstanden. Wenn alles veraltet ist, wäre es nicht schwer, ein Skript zu schreiben, um den Code ein einziges Mal zu generieren. Joses Antwort klingt interessant, ich kannte das nicht. Sind die Proxies bereits im Frühling geführt? Versuchst du etwas mit ihnen zu machen, das erfordert, dass sie im Frühling verwaltet werden, wenn nicht? – Jafoy

Verwandte Themen