Spring Beans in onbeheerde objecten injecteren

1. Drijvende krachten

Bij een voorjaarstoepassing is het heel gebruikelijk om een ​​boon in een andere boon te injecteren. Soms echter het is wenselijk om een ​​boon in een gewoon voorwerp te injecteren. We willen bijvoorbeeld mogelijk verwijzingen naar services verkrijgen vanuit een entiteitsobject.

Gelukkig is dat niet zo moeilijk als het lijkt. In de volgende secties wordt uitgelegd hoe u dit doet de ... gebruiken @Configureerbaar annotatie en een AspectJ-wever.

2. Het @Configureerbaar Annotatie

Met deze annotatie kunnen instanties van de gedecoreerde klasse verwijzingen naar Spring beans bevatten.

2.1. Een lenteboon definiëren en registreren

Voordat u de @Configureerbaar annotatie, laten we een Spring bean-definitie instellen:

@Service openbare klasse IdService {privé statische int count; int generationId () {return ++ count; }}

Deze klas is versierd met de @Onderhoud annotatie; vandaar dat het kan worden geregistreerd met een Spring-context via het scannen van componenten.

Hier is een eenvoudige configuratieklasse die dat mechanisme mogelijk maakt:

@ComponentScan openbare klasse AspectJConfig {}

2.2. Gebruik makend van @Configureerbaar

In zijn eenvoudigste vorm, we kunnen gebruiken @Configureerbaar zonder enig element:

@ Configureerbare openbare klasse PersonObject {privé int id; private String naam; openbaar PersonObject (String naam) {this.name = naam; } // getters en andere code getoond in de volgende subsectie}

De @Configureerbaar annotatie, in dit geval, markeert de PersoonObject klasse in aanmerking komen voor een configuratie met veerkracht.

2.3. Een Spring Bean in een onbeheerd object injecteren

We kunnen injecteren IdService in PersoonObject, net zoals we zouden doen in elke Spring bean:

@ Configureerbare openbare klasse PersonObject {@Autowired privé IdService idService; // velden, constructor en getters - getoond in de vorige subsectie void generationId () {this.id = idService.generateId (); }}

Een annotatie is echter alleen nuttig als deze wordt herkend en verwerkt door een handler. Dit is waar AspectJ-wever in het spel komt. Specifiek, de AnnotationBeanConfigurerAspect zal handelen op de aanwezigheid van @Configureerbaar en voert de nodige bewerkingen uit.

3. AspectJ Weaving inschakelen

3.1. Plugin-verklaring

Om AspectJ-weven in te schakelen, hebben we eerst de AspectJ Maven-plug-in nodig:

 org.codehaus.mojo aspectj-maven-plugin 1.11 

En het vereist wat extra configuratie:

 1.8 negeer org.springframework lente-aspecten 

Het eerste vereiste element is complianceLevel. Een waarde van 1.8 stelt zowel de bron- als de doel-JDK-versie in op 1.8. Indien niet expliciet ingesteld, zou de bronversie 1.3 zijn en zou het doel 1.1 zijn. Deze waarden zijn duidelijk verouderd en niet voldoende voor een moderne Java-applicatie.

Om een ​​boon in een onbeheerd object te injecteren, moeten we vertrouwen op de AnnotationBeanConfigurerAspect klasse voorzien in de spring-aspects.jar. Aangezien dit een vooraf samengesteld aspect is, zouden we dat moeten doen voeg het bevattende artefact toe aan de plugin-configuratie.

Merk op dat een dergelijk artefact waarnaar wordt verwezen als een afhankelijkheid in het project moet bestaan:

 org.springframework lente-aspecten 5.2.7.RELEASE 

We kunnen de laatste versie van lente-aspecten op Maven Central.

3.2. Uitvoering van plug-ins

Om de plug-in te instrueren om alle relevante klassen te weven, hebben we dit nodig executies configuratie:

   compileren 

Merk op de plug-in compileren goal bindt standaard aan de compileerlevenscyclusfase.

3.2. Bean-configuratie

De laatste stap om AspectJ-weven mogelijk te maken, is toevoegen @EnableSpringConfigured naar de configuratieklasse:

@ComponentScan @EnableSpringConfigured openbare klasse AspectJConfig {}

De extra annotatie configureert AnnotationBeanConfigurerAspect, die op zijn beurt registreert PersoonObject instanties met een Spring IoC-container.

4. Testen

Laten we nu controleren of het IdService boon is met succes geïnjecteerd in een PersoonObject:

@RunWith (SpringRunner.class) @ContextConfiguration (classes = AspectJConfig.class) openbare klasse PersonUnitTest {@Test openbare leegte gegevenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet () {PersonObject personObung ";" personObject.generateId (); assertEquals (1, personObject.getId ()); assertEquals ("Baeldung", personObject.getName ()); }}

5. Een boon injecteren in een PPV-entiteit

Vanuit het oogpunt van de Spring-container is een entiteit niets anders dan een gewoon object. Als zodanig is er niets speciaals aan het injecteren van een springboon in een PPV-entiteit.

Aangezien injecteren in PPV-entiteiten echter een typische use-case is, laten we dit in meer detail bespreken.

5.1. Entiteitsklasse

Laten we beginnen met het skelet van de entiteitsklasse:

@Entity @Configurable (preConstruction = true) public class PersonEntity {@Id private int id; private String naam; public PersonEntity () {} // andere code - weergegeven in de volgende subsectie}

Let op de voor constructie element in het @Configureerbaar annotatie: het stelt ons in staat om een ​​afhankelijkheid in het object te injecteren voordat het volledig is geconstrueerd.

5.2. Service-injectie

Nu kunnen we injecteren IdService in PersonEntity, vergelijkbaar met waarmee we deden PersoonObject:

// annotaties openbare klasse PersonEntity {@Autowired @Transient privé IdService idService; // velden en no-arg constructor public PersonEntity (String naam) {id = idService.generateId (); this.name = naam; } // getters}

De @Transient annotatie wordt gebruikt om de PPV dat te vertellen idService is een veld dat niet moet worden volgehouden.

5.3. Update van testmethode

Ten slotte kunnen we de testmethode bijwerken om aan te geven dat de service in de entiteit kan worden geïnjecteerd:

@Test openbare ongeldige gegevenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet () {// bestaande verklaringen PersonEntity personEntity = nieuwe PersonEntity ("Baeldung"); assertEquals (2, personEntity.getId ()); assertEquals ("Baeldung", personEntity.getName ()); }

6. Voorbehoud

Hoewel het handig is om toegang te krijgen tot Spring-componenten vanuit een onbeheerd object, is het vaak geen goede gewoonte om dit te doen.

Het probleem is dat onbeheerde objecten, inclusief entiteiten, meestal deel uitmaken van het domeinmodel. Deze objecten mogen alleen gegevens bevatten om herbruikbaar te zijn voor verschillende services.

Het injecteren van bonen in dergelijke objecten kan componenten en objecten aan elkaar binden, waardoor het moeilijker wordt om de toepassing te onderhouden en te verbeteren.

7. Conclusie

Deze tutorial heeft het proces doorlopen van het injecteren van een Spring bean in een onbeheerd object. Het noemde ook een ontwerpprobleem dat verband houdt met het injecteren van afhankelijkheden in objecten.

De implementatiecode is te vinden op GitHub.