Skip to content

Solutions to proceed to "method injection" in Spring Beans

Notifications You must be signed in to change notification settings

FBibonne/spring-method-injection

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 

Repository files navigation

De l'injection de méthodes dans Spring à l'aide de Spring AOP


A propos de

  • Fabrice Bibonne : support aux développeurs sur les technologies java
  • Insee :
    • Produit, analyse et diffuse des informations sur l’économie et la société françaises
    • Diffuse également des métadonnées comme les référentiels géographiques à travers des API

A propos de

  • POC de la refonte de Metadata API avec approche contract first :
    • la spec OAS est une spécification
    • Eviter une génération laborieuse "du swagger"
    • Documentation fidèle au besoin, au code
    • Implémentation contrainte as code

Architecture Metadata API


D'abord la spec OAS


Exemple d'interface générée d'un controlleur


Systématiser l'implémentation des controllers Spring

  • Fonctionnement d'un controlleur (générique) :
    1. Appeler la bonne requête Sparql
    2. Convertir le résultat dans la bonne entité
    3. La retourner
  • Extensions OpenApi Generator
  • Générer l'implémentation au runtime (comme Spring Data)

Génération par "injection de méthode"

  • Avec MethodReplacer ?
    • Définition xml seulement
    • Peu utilisé
    • Pas compatible avec un contrôle d'accès (@PreAuthorize)
  • Autre chose ?

Spring AOP !


Spring AOP : ce n'est pas...


AOP

  • Programmation orientée Aspect
    • Paradigme de programmation
    • On s'intéresse aux aspects transverses de l'application (transactions)
    • La gestion des aspects est centralisée
    • On court-circuite les traitements métier pour y insérer les traitements relatifs aux aspects

Schéma Spring AOP


Implémentation dans Spring avec la proxyfication


Exemple simple dans Spring

code


AOP avec Les contrôleurs de metadata api

schéma


Configuration

public void onApplicationEvent(@NonNull ApplicationContextInitializedEvent event) {
    /* ... */
    new ClassPathScanningCandidateComponentProvider(false){...}.findCandidateComponents(interfaceControllerPackage);
	/* ... */
	controllerMetadatas.forEach( classMetadata -> {
	    /* ... */
	    genericApplicationContext.registerBeanDefinition(advisorName,
            getPointcutBeanDefinition(namesOfMethodsToIntercept));
		genericApplicationContext.registerBean(
            classMetadata.getClassName(), ControllerProxyFactoryBean.class, 
            controllerInterface, advisorName);
		/* ..*/
	});
	/* ... */
}

Configuration

public class ControllerProxyFactoryBean extends ProxyFactoryBean {

    public ControllerProxyFactoryBean(Class<?> controllerClass, String advisorName) {
        setSingleton(true);
        setInterfaces(controllerClass);
        setInterceptorNames(advisorName);
    }
}

Implémentation contrôleur générique

public Optional<?> process(@NonNull Method method, @NonNull Object[] arguments)
    throws ArgumentException{
                                                                                                         
    String methodName=method.getName();                                                                                       
    Optional<QueryTemplate> queryTemplate= queryTemplateSupplier.get(methodName);                        
    if (queryTemplate.isEmpty()) {                                                                       
        throw new UnsupportedOperationException(STR."Method \{methodName} not supported");               
    }                                                                                                    
    String query = queryTemplate.get().format(arguments);                                                
    return ofNullable(unmarshaller.unmarshal(queryExecutor.execute(query), method));                     
}                                                                                                        

Implémentation contrôleur générique

public Optional<QueryTemplate> get(@NonNull String methodName) {              
    return Optional.ofNullable(switch (methodName) {                         
        case "getcogcom" -> queryTemplate().withFindByCode()                 
                .codeAtPosition(0).dateAtPosition(1)                                           
                .forTerritory("Commune");                                    
        case "getcogdep" -> queryTemplate().withFindByCode()                 
                .codeAtPosition(0).dateAtPosition(1)                                           
                .forTerritory("Departement");                                
        case "getTerritoireByTypeAndCode" -> queryTemplate().withFindByCode()
                .codeAtPosition(0).dateAtPosition(2)                                           
                .forUnknownTerritoryType(1);
		/* ... */
		default -> null;
	});
}

Ca fonctionne !


Conclusion

  • Pistes d'amélioration pour le POC
    • simplifier la déclaration des pointcuts
    • Utiliser la réflexion pour associer endpoints et requêtes SPARQL
    • Etre indépendant de Spring Boot
  • Spring AOP :
    • Outil puissant pour gérer des aspects transverses ou génériques dans une application Spring
    • Très bien intégré avec l'écosystème Spring
    • Plutôt pour les implémentations internes de Spring mais bon à connaître

Lien

QR code

MERCI !


Annexe : schema pour AOP avec concepts

flowchart LR
    
    subgraph Code
        I1[Intruction 1]
        I2[Intruction 2]
        subgraph AOP Proxy
            extra[extra behavior]
            method[instruction 3 : Method call]
        end
        I4[Intruction 4]
        I5[...]
    end
    subgraph Aspect
        Advice
        Pointcut["Pointcut : 'call()'"]
    end
    
    Pointcut--"Join Point"--> method
    Advice--"woven aspect"-->extra
    Aspect --"Weaving"--> Code
Loading

About

Solutions to proceed to "method injection" in Spring Beans

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published