2013-12-09 6 views
12

Die Spring-Dokumentation empfiehlt, keine @Transactional-Annotationen in Interface-Methoden einzufügen, da Interface-Annotationen nicht von Klassen geerbt werden. Mit Java 8 können wir jedoch eine konkrete Standardimplementierung in der Schnittstelle bereitstellen. Wenn eine solche Standardschnittstellenmethode die Transaktionsgrenze sein muss, haben wir keine andere Wahl: Wir müssen die Annotation @Transactional in die Schnittstellenmethode einfügen.Ist es sicher, eine Spring @ Transactional-Annotation für eine Java 8-Standardschnittstellenmethode zu verwenden?

Wird dies funktionieren (d. H. Wird Feder in diesem Fall die Transaktionsgrenze respektieren)? Wenn ja, gibt es versteckte Fallstricke bei diesem Ansatz?

+0

Wenn Sie eine Standardimplementierung einer Methode benötigen, warum erstellen Sie keine abstrakte Klasse anstelle einer Schnittstelle? Die Java 8-API-Dokumente haben mich zu der Annahme verleitet, dass die Standardmethoden der Schnittstelle in erster Linie dem Hinzufügen neuer Methoden zu einer Schnittstelle dienen sollen, ohne ältere Implementierungen dieser Schnittstelle zu unterbrechen. – VGR

+0

Interface-Standardmethoden ermöglichen es Ihnen, [Mixins] (https://en.wikipedia.org/wiki/Mixin) zu erstellen, die ein viel leistungsfähigeres Programmierkonstrukt als herkömmliche Java-Schnittstellen sind. Ob es einen triftigen Grund gibt, ein Mixin in einer Service-Schnittstelle mit Transaktionen zu verwenden, ist ein anderes Problem, aber es ist nicht unvorstellbar. Die Verwendung abstrakter Klassen funktioniert ebenfalls, beschränkt Sie jedoch auf eine lineare Objekthierarchie. Mixins sind viel flexibler. – JMB

Antwort

10

Spring verwendet (unter anderem) BeanFactoryTransactionAttributeSourceAdvisor als Advisor beim Generieren einer Proxy-Bean für Klassen, die mit Methoden kommentiert sind oder Methoden enthalten, die mit @Transactional kommentiert sind.

Wenn die Zeit kommt, um es zu propagieren, verwendet es den Klassen-Typ der Bean (mit CGLIB), um den Proxy zu generieren. Wir wollen also sehen, ob die default-Methode, die mit @Transactional versehen ist, aus der Sicht der implementierenden Klasse sichtbar ist.

Hier ist ein Java 8 SSCCE

public static void main(String[] args) throws Exception{ 
    Class<?> randomImplClass = RandomImpl.class; 
    System.out.println(randomImplClass); 
    Easy annotation = randomImplClass.getAnnotation(Easy.class); 
    System.out.println("Class: " + randomImplClass); 
    System.out.println("Class Annotation: " + annotation); 

    Method method = randomImplClass.getMethod("doRandom"); 
    annotation = method.getAnnotation(Easy.class); 
    System.out.println("Method: " + method); 
    System.out.println("Method Annotation: " + annotation); 
} 

public static class RandomImpl implements Random{} 
@Easy 
interface Random { 
    @Easy 
    default void doRandom() {System.out.println("testing");}; 
} 

@Target(value = {METHOD, TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Easy {} 

die

class TestEnhancer$RandomImpl 
Class: class TestEnhancer$RandomImpl 
Class Annotation: null 
Method: public default void TestEnhancer$Random.doRandom() 
Method Annotation: @TestEnhancer$Easy() 

Anzeige druckt, dass die Anmerkung für die Methode der Schnittstelle geerbt wurde. Es scheint daher, dass Spring in der Lage sein wird, das Verhalten @Transactional hinzuzufügen, wenn die Klasse die Methode default nicht überschrieben hat. Wenn es überschrieben wurde, werden Anmerkungen nicht vererbt.

+0

Sehr schöner Test. Um noch einen Schritt weiter zu gehen, können Sie die Standardimplementierung in RandomImpl überschreiben und demonstrieren, dass Sie die Annotation auf die Overriding-Methode setzen müssen, um sie sehen zu können. Ich glaube nicht, dass dies etwas anderes ist als Vererbung. – JMB

+0

@JMB Richtig, ich habe es lokal gemacht, aber das Beispiel hier nicht gepostet. Der letzte Satz deckt es ab. Ich werde es hinzufügen, wenn ich später nach Hause komme. –

Verwandte Themen