web-dev-qa-db-fra.com

Si Spring peut intercepter avec succès les appels de fonction intra-classe dans une classe @Configuration, pourquoi ne le prend-il pas en charge dans un bean normal?

J'ai récemment remarqué que Spring intercepte avec succès les appels de fonction intra classe dans une classe @Configuration mais pas dans un bean régulier.

Un appel comme celui-ci

@Repository
public class CustomerDAO {  
    @Transactional(value=TxType.REQUIRED)
    public void saveCustomer() {
        // some DB stuff here...
        saveCustomer2();
    }
    @Transactional(value=TxType.REQUIRES_NEW)
    public void saveCustomer2() {
        // more DB stuff here
    }
}

ne parvient pas à démarrer une nouvelle transaction car pendant que le code de saveCustomer () s'exécute dans le proxy CustomerDAO, le code de saveCustomer2 () est exécuté dans la classe CustomerDAO non encapsulée, comme je peux le voir en regardant `` ceci '' dans le débogueur, etc. Spring n'a aucune chance d'intercepter l'appel à saveCustomer2.

Cependant, dans l'exemple suivant, lorsque transactionManager () appelle createDataSource (), il est correctement intercepté et appelle createDataSource () du proxy, pas de la classe non encapsulée, comme en témoigne la recherche de "this" dans le débogueur.

@Configuration
public class PersistenceJPAConfig {
    @Bean
    public DriverManagerDataSource createDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        //dataSource.set ... DB stuff here
        return dataSource;
    }

   @Bean 
       public PlatformTransactionManager transactionManager(   ){
           DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(createDataSource());
           return transactionManager;
       }
}

Ma question est donc de savoir pourquoi Spring peut intercepter correctement les appels de fonction intra-classe dans le deuxième exemple, mais pas dans le premier. Utilise-t-il différents types de proxys dynamiques?

Edit: D'après les réponses ici et d'autres sources, je comprends maintenant ce qui suit: @Transactional est implémenté à l'aide de Spring AOP, où le modèle de proxy est effectué en encapsulant/composition de la classe d'utilisateurs. Le proxy AOP est suffisamment générique pour que de nombreux aspects puissent être enchaînés ensemble, et peut être un proxy CGLib ou un Java Dynamic Proxy.

Dans la classe @Configuration, Spring utilise également CGLib pour créer une classe améliorée qui hérite de la classe @Configuration de l'utilisateur et remplace les fonctions @Bean de l'utilisateur par celles qui effectuent un travail supplémentaire avant d'appeler la fonction/super fonction de l'utilisateur, comme vérifier si cela est la première invocation de la fonction ou non. Cette classe est-elle un proxy? Cela dépend de la définition. Vous pouvez dire que c'est un proxy qui utilise l'héritage de l'objet réel au lieu de l'envelopper en utilisant la composition.

Pour résumer, d'après les réponses données ici, je comprends que ce sont deux mécanismes entièrement différents. Pourquoi ces choix de conception ont été faits est une autre question ouverte.

21
Gonen I

Spring utilise le proxy pour l'invocation de méthodes et lorsque vous l'utilisez ... il contourne ce proxy. Pour les annotations @Bean, Spring utilise la réflexion pour les trouver.

0
Sergiu