dimanche 17 septembre 2023

[Spring] Existe-t-il des limitations liées aux proxies dans Spring AOP?

La réponse courte : Oui, il y'a des limitations liées aux proxies dans Spring AOP 

Plus en détaille :

La nécessité d'annoter des méthodes avec @Transactional et de ne le faire que pour les méthodes publiques dans Spring découle principalement des limitations de Spring AOP et de la manière dont Spring gère la gestion des transactions.


Voici pourquoi :


Spring AOP et Proxies : Spring utilise la programmation orientée aspect (AOP) pour gérer la gestion des transactions. Lorsque vous ajoutez l'annotation @Transactional à une méthode, Spring crée un proxy autour de cette méthode. Ce proxy intercepte les appels à la méthode et gère la logique de transaction avant et après l'exécution de la méthode réelle. Cela permet à Spring de fournir une gestion déclarative des transactions sans exiger que vous codiez manuellement tout le code de gestion des transactions.


Limitation des Proxies : Les proxies créés par Spring AOP ont certaines limitations. L'une de ces limitations concerne les méthodes non publiques (telles que les méthodes privées, protégées ou package-private). Les proxies Spring ne peuvent pas intercepter les appels aux méthodes non publiques, car ils sont générés à partir de classes d'interface ou d'objets sous-jacents, et seuls les appels aux méthodes publiques peuvent être interceptés.


Visibilité des Méthodes Transactionnelles : Pour que Spring puisse intercepter les appels à une méthode annotée @Transactional, cette méthode doit être publique. Cela signifie que vous ne pouvez pas utiliser @Transactional sur des méthodes non publiques, car les transactions ne seront pas correctement gérées par Spring.

Ils peuvent également avoir un impact sur l'utilisation du cache dans une application Spring. Tout comme la gestion des transactions, le mécanisme de mise en cache de Spring AOP repose sur l'utilisation de proxies pour intercepter les appels aux méthodes et gérer la logique de mise en cache. Par conséquent, les mêmes limitations s'appliquent en ce qui concerne les méthodes que vous pouvez annoter pour utiliser le cache.


Voici comment cela fonctionne :


Mise en Cache avec Spring : Spring offre un support intégré pour la mise en cache en utilisant des annotations telles que @Cacheable, @CacheEvict, et @CachePut. Lorsqu'une méthode annotée avec @Cacheable est appelée, Spring intercepte cet appel à l'aide d'un proxy, vérifie si les résultats de la méthode sont déjà mis en cache, et si tel est le cas, renvoie la valeur mise en cache au lieu d'exécuter réellement la méthode. Cela améliore les performances en évitant des calculs coûteux pour les mêmes entrées.


Limitations de Proxies : Comme mentionné précédemment, les proxies Spring AOP ont des limitations, notamment la nécessité que les méthodes annotées soient publiques. De plus, les méthodes de mise en cache doivent être exécutées sur l'objet proxy généré par Spring pour que la logique de mise en cache fonctionne. Cela signifie que si vous avez une méthode non publique et que vous tentez d'annoter cette méthode avec @Cacheable, la mise en cache ne fonctionnera pas correctement, car Spring ne pourra pas intercepter les appels à cette méthode non publique via le proxy.


Méthodes Publiques pour la Mise en Cache : Pour que la mise en cache fonctionne correctement, vous devez annoter des méthodes publiques que vous souhaitez mettre en cache. Ces méthodes doivent être appelées à travers l'objet proxy Spring pour que la logique de mise en cache puisse être appliquée.


En résumé, tout comme pour la gestion des transactions, les méthodes que vous souhaitez mettre en cache avec Spring doivent être publiques et appelées via l'objet proxy Spring pour bénéficier de la mise en cache. Les limitations liées aux proxies s'appliquent à la mise en cache, ce qui signifie que les méthodes non publiques ne seront pas correctement gérées par le mécanisme de mise en cache de Spring.

jeudi 14 septembre 2023

[Spring] Comprendre le fonctionnement de l'attribut d'isolation des transactions

 Introduction


Lorsque plusieurs transactions d'une même application ou de différentes applications fonctionnent simultanément sur le même jeu de données, cela peut entraîner de nombreux problèmes inattendus. Pour résoudre ces problèmes, il est essentiel de spécifier comment vous souhaitez que vos transactions soient isolées les unes des autres. C'est là qu'intervient l'attribut d'isolation des transactions. Dans cet article, nous allons explorer comment cet attribut fonctionne et comment il peut résoudre les problèmes courants liés aux transactions concurrentes.

https://www.baeldung.com/spring-transactional-propagation-isolation#transactional-isolations 


Problème


Les transactions concurrentes peuvent provoquer quatre types de problèmes :


Lecture sale (Dirty read) : Dans ce scénario, deux transactions, T1 et T2, sont en cours. T1 lit un champ qui a été mis à jour par T2 mais qui n'a pas encore été validé. Si T2 est annulée ultérieurement, la valeur lue par T1 deviendra temporaire et invalide.


Lecture non répétable (Nonrepeatable read) : Ici, T1 lit un champ, puis T2 met à jour ce champ. Si T1 lit à nouveau ce champ, la valeur sera différente de ce qu'elle était précédemment.


Lecture fantôme (Phantom read) : Dans ce cas, T1 lit certaines lignes d'une table, puis T2 insère de nouvelles lignes dans cette table. Lorsque T1 lit à nouveau la même table, il y aura des lignes supplémentaires auxquelles il n'avait pas accès précédemment.


Pertes de mises à jour (Lost updates) : T1 et T2 sélectionnent tous deux une ligne à mettre à jour et, en fonction de l'état de cette ligne, effectuent une mise à jour. Ainsi, l'une écrase l'autre alors que la deuxième transaction aurait dû attendre que la première soit validée avant de procéder à sa sélection.


Solution


En théorie, les transactions devraient être complètement isolées les unes des autres (c'est-à-dire sérialisables) pour éviter tous les problèmes mentionnés ci-dessus. Cependant, ce niveau d'isolation aurait un impact considérable sur les performances, car les transactions devraient s'exécuter dans un ordre séquentiel strict. Dans la pratique, il est possible de faire fonctionner les transactions à des niveaux d'isolation inférieurs afin d'améliorer les performances.


L'attribut d'isolation des transactions permet de définir le niveau d'isolation souhaité pour une transaction donnée. Les niveaux d'isolation couramment utilisés incluent :


Isolation de lecture non répétable (Read Uncommitted) : Dans ce niveau, aucune isolation n'est garantie. Les transactions peuvent lire des données non validées par d'autres transactions en cours, ce qui peut entraîner des problèmes de lecture sale, de lecture non répétable et de pertes de mises à jour.


Isolation de lecture répétable (Read Committed) : Ce niveau permet d'éviter les lectures sales, mais les problèmes de lecture non répétable et de pertes de mises à jour peuvent toujours survenir.


Isolation de répétition de lecture (Repeatable Read) : Ce niveau résout les problèmes de lecture non répétable en garantissant que toutes les données lues par une transaction restent constantes jusqu'à la fin de cette transaction. Cependant, les lectures fantômes peuvent toujours se produire.


Isolation sérialisable (Serializable) : C'est le niveau le plus strict, garantissant une isolation totale. Cependant, cela peut avoir un impact significatif sur les performances, car les transactions doivent s'exécuter de manière séquentielle.


Conclusion


L'attribut d'isolation des transactions est un outil essentiel pour gérer les problèmes liés aux transactions concurrentes. En comprenant les différents niveaux d'isolation disponibles et en choisissant celui qui convient le mieux à vos besoins, vous pouvez garantir que vos transactions fonctionnent de manière fiable tout en optimisant les performances de votre système. Il est important de peser soigneusement les avantages et les inconvénients de chaque niveau d'isolation pour prendre la décision la plus appropriée en fonction de votre application et de vos exigences.

NB :
La gestion de l'isolation des transactions dépend de la capacité du moteur de base de données sous-jacent à prendre en charge différents niveaux d'isolation. Les applications et les frameworks n'ont généralement pas un contrôle direct sur la gestion de l'isolation des transactions, mais ils peuvent interagir avec le moteur de base de données pour spécifier le niveau d'isolation souhaité.

mardi 12 septembre 2023

[Spring boot] @SpringBootConfiguration vs @Configuration?

SpringBootConfiguration


Introduction :


L'annotation @SpringBootConfiguration est un élément essentiel de Spring Boot, un framework de développement d'applications Java. Elle indique qu'une classe fournit une configuration spécifique à une application Spring Boot. Cette annotation peut être utilisée comme une alternative à l'annotation @Configuration standard de Spring, permettant ainsi à la configuration d'être trouvée automatiquement, notamment dans le cadre de tests unitaires. Dans cet article, nous explorerons en détail l'utilisation de l'annotation @SpringBootConfiguration, ses implications dans le développement d'applications Spring Boot, et la différence entre @SpringBootConfiguration et @Configuration.


Utilisation de @SpringBootConfiguration :


Pour comprendre l'utilisation de l'annotation @SpringBootConfiguration, examinons un exemple concret. Supposons que vous développiez une application Spring Boot qui nécessite une configuration personnalisée, telle que la configuration d'une source de données ou de certaines propriétés spécifiques. Vous pouvez créer une classe de configuration annotée avec @SpringBootConfiguration pour définir cette configuration.

@SpringBootConfiguration 
public class MyAppConfig {
// définir des beans de configuration et des propriétés spécifiques à votre application.
}

Dans cet exemple, MyAppConfig est une classe de configuration spécifique à Spring Boot. Vous pouvez y définir des beans de configuration et des propriétés spécifiques à votre application.


Utilisation de @SpringBootConfiguration dans les tests unitaires :


Une utilisation courante de @SpringBootConfiguration est dans le contexte des tests unitaires. Lorsque vous écrivez des tests pour votre application Spring Boot, vous pouvez l'utiliser pour charger la configuration de l'application.


Supposons que vous ayez une classe de service que vous souhaitez tester :


@Service

public class MyService {

    // Service logic

}

Vous pouvez écrire un test unitaire pour cette classe en utilisant @SpringBootTest avec @SpringBootConfiguration :


@SpringBootTest(classes = MyAppConfig.class)

public class MyServiceTest {

    

    @Autowired

    private MyService myService;

    

    @Test

    public void testMyService() {

        // Test logic using myService

    }

}

Dans cet exemple, @SpringBootTest charge la configuration de l'application, y compris MyAppConfig, ce qui vous permet d'accéder à MyService pour effectuer des tests unitaires.


Différence avec @Configuration :


La principale différence entre @SpringBootConfiguration et @Configuration réside dans leur utilisation au sein d'applications Spring Boot. Alors que @Configuration est l'annotation standard de Spring pour déclarer une classe de configuration, @SpringBootConfiguration est spécifique à Spring Boot et offre des fonctionnalités supplémentaires liées au contexte d'application spécifique à Spring Boot.


Conclusion :


L'annotation @SpringBootConfiguration est un élément essentiel de Spring Boot, permettant de définir la configuration spécifique à une application. Elle est particulièrement utile dans le contexte des tests unitaires, où elle permet de charger la configuration de l'application pour effectuer des tests précis. En général, la plupart des développeurs préfèrent utiliser l'annotation @SpringBootApplication, qui inclut implicitement @SpringBootConfiguration, simplifiant ainsi la configuration de l'application tout en tirant parti des fonctionnalités de Spring Boot.

[Spring Boot] la propriété spring.main.web-application-type

En Spring Boot, la propriété spring.main.web-application-type est utilisée pour définir le type d'application web que vous souhaitez créer. Cette propriété peut avoir l'une des trois valeurs suivantes :


none : Cela signifie qu'aucune application web n'est activée. Cela convient aux applications Spring Boot qui ne sont pas destinées à être des applications web, par exemple, les applications de ligne de commande ou les applications de traitement de fond.


servlet : Cela indique que vous souhaitez créer une application web basée sur le Servlet. Cette option est appropriée pour la création d'applications web traditionnelles qui utilisent le conteneur de servlets Java pour gérer les requêtes HTTP. Vous pouvez utiliser des annotations comme @Controller et @RequestMapping pour créer des contrôleurs web dans ce mode.


reactive : Cela indique que vous souhaitez créer une application web réactive. Lorsque vous choisissez cette option, Spring Boot utilise le paradigme de programmation réactive pour gérer les requêtes HTTP. Cela convient aux applications qui doivent gérer un grand nombre de requêtes simultanées et qui souhaitent bénéficier de la réactivité pour une meilleure évolutivité.


Par exemple, si vous définissez spring.main.web-application-type dans votre fichier application.yml comme suit :

application.yml
spring:    
    main: 
        web-application-type: servlet

Cela signifie que vous créez une application web basée sur le Servlet.


En résumé, la propriété spring.main.web-application-type permet de définir le type d'application web que vous souhaitez créer avec Spring Boot, que ce soit une application non web, une application basée sur Servlet ou une application réactive. 

Source : https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html 

lundi 11 septembre 2023

[JAVA 17] Simplifiez la Manipulation de Données en Java avec le Pattern Matching

Introduction :

Le pattern matching est une fonctionnalité puissante introduite dans Java à partir de la version 14. Faisant partie du projet Amber, son objectif est d'améliorer la productivité des développeurs Java en introduisant de nouvelles fonctionnalités de langage. Dans cet article, nous allons explorer le pattern matching et ses différentes formes, tout en fournissant des exemples concrets pour illustrer son utilisation.


Le Pattern Matching pour instanceof :

Le pattern matching pour instanceof est la première forme de pattern matching introduite dans Java. Il simplifie la vérification de types pour les objets. Avant cela, pour vérifier si un objet était d'un certain type, il fallait utiliser l'opérateur instanceof et ensuite effectuer un cast de l'objet pour accéder à ses propriétés. Voici un exemple de code pour illustrer cette simplification :


Avant le pattern matching :

if (obj instanceof String) { String str = (String) obj; // Utilisation de str }

Après le pattern matching :

if (obj instanceof String str) { // Utilisation de str }

Le Pattern Matching pour switch :

Le pattern matching pour switch est une autre forme de pattern matching introduite dans Java. Il simplifie la vérification de plusieurs conditions pour une variable donnée. Voici un exemple comparant l'utilisation traditionnelle du switch avec le pattern matching :

Utilisation traditionnelle du switch :

switch (dayOfWeek) { case MONDAY: case TUESDAY: case WEDNESDAY: System.out.println("C'est un jour de travail !"); break; default: System.out.println("C'est le week-end !"); break; }

Utilisation du pattern matching pour switch :


switch (dayOfWeek) { case MONDAY, TUESDAY, WEDNESDAY -> System.out.println("C'est un jour de travail !"); default -> System.out.println("C'est le week-end !"); }

Le Pattern Matching avec les Records :

Les records, introduits à partir de Java 16, simplifient la définition de classes en fournissant une syntaxe concise et des méthodes générées automatiquement pour accéder aux propriétés de l'objet. Les record patterns permettent d'utiliser les records avec le pattern matching. Voici un exemple de record et son utilisation avec le pattern matching :


Définition d'un record :


record Person(String name, int age) {}

Utilisation du record avec le pattern matching :


if (obj instanceof Person person) { System.out.println("Nom : " + person.name() + ", Age : " + person.age()); }

Résumé :

En résumé, le pattern matching est une fonctionnalité importante introduite dans Java pour simplifier la manipulation de données complexes et rendre le code plus lisible et compréhensible. Il offre une approche plus simple et plus efficace pour la vérification des types, la simplification des switch, l'utilisation des records, et bien plus encore. En utilisant des exemples concrets, nous avons exploré comment cette fonctionnalité améliore la productivité des développeurs Java. N'hésitez pas à l'adopter pour rendre votre code plus élégant et maintenable.


dimanche 10 septembre 2023

[Spring ] Quelle est la différence entre bean factory et application contexte?

Le contenueur IoC Spring, founri le BeanFactory et l'ApplicationContext qui sont deux interfaces clés pour la gestion et l'accès aux beans. Voici les différences entre les deux :


BeanFactory :


Lazy Initialization : Le BeanFactory est le conteneur de base pour la gestion des beans. Il offre une gestion paresseuse (lazy) des beans, ce qui signifie que les beans ne sont instanciés qu'au moment de leur première utilisation. Cela peut être plus efficace en termes de ressources, car les beans ne sont créés qu'en cas de nécessité.


Plus Léger : Le BeanFactory est plus léger en termes de ressources car il ne charge pas tous les beans immédiatement lors du démarrage de l'application.


Fonctionnalité Limitée : Le BeanFactory offre les fonctionnalités de base de la gestion des beans, telles que la création, la configuration et la fourniture de beans, mais il ne prend en charge que les fonctionnalités essentielles.


Utilisation Explicit : Pour utiliser un BeanFactory, vous devez le configurer explicitement dans votre application.


ApplicationContext :


Eager Initialization : L'ApplicationContext est une surcouche du BeanFactory et offre toutes ses fonctionnalités. Cependant, il initialise les beans de manière anticipée (eagerly) lors du démarrage de l'application, à moins que vous ne configuriez explicitement le contexte pour une initialisation paresseuse.


Riche en Fonctionnalités : L'ApplicationContext est plus riche en fonctionnalités que le BeanFactory. Il prend en charge des fonctionnalités avancées telles que l'injection de dépendances automatique, la gestion des transactions, l'internationalisation, la gestion des événements, etc.


Utilisation Courante : L'ApplicationContext est largement utilisé dans la plupart des applications Spring en raison de sa richesse en fonctionnalités et de sa commodité.


Utilisation Facilitée : Vous pouvez obtenir un ApplicationContext en utilisant une variété de classes de configuration, telles que AnnotationConfigApplicationContext, ClassPathXmlApplicationContext, etc., ce qui rend son utilisation plus facile.

Exemple :

var context = new AnnotationConfigApplicationContext(ClasseConfiguration.class);


Pour récupérer un bean géré par le conteneur IoC (Inversion of Control) de Spring, vous pouvez utiliser l'application du contexte (application context) de Spring :


var classe= (Classe) context.getBean("classe");


En résumé, l'ApplicationContext est une extension plus puissante du BeanFactory et est largement utilisé dans les applications Spring modernes en raison de ses fonctionnalités étendues et de sa facilité d'utilisation. Cependant, si vous avez besoin d'une gestion paresseuse des beans et que vous souhaitez économiser des ressources en initialisant les beans uniquement lorsque cela est nécessaire, vous pouvez opter pour le BeanFactory.