Maak een aangepaste automatische configuratie met Spring Boot

1. Overzicht

Simpel gezegd, de autoconfiguratie van Spring Boot vertegenwoordigt een manier om automatisch een Spring-applicatie te configureren op basis van de afhankelijkheden die aanwezig zijn op het klassenpad.

Dit kan de ontwikkeling sneller en gemakkelijker maken door de noodzaak te elimineren om bepaalde bonen te definiëren die zijn opgenomen in de autoconfiguratieklassen.

In de volgende sectie gaan we kijken naar het maken van onze aangepaste automatische configuratie van Spring Boot.

2. Maven afhankelijkheden

Laten we beginnen met de afhankelijkheden die we nodig hebben:

 org.springframework.boot spring-boot-starter-data-jpa 2.2.2.RELEASE mysql mysql-connector-java 8.0.19 

De nieuwste versies van spring-boot-starter-data-jpa en mysql-connector-java kunnen worden gedownload vanaf Maven Central.

3. Een aangepaste autoconfiguratie maken

Om een ‚Äč‚Äčaangepaste automatische configuratie te maken, moeten we een klasse maken met de annotatie @Configuratie en registreer het.

Laten we een aangepaste configuratie maken voor een MySQL databron:

@Configuration openbare klasse MySQLAutoconfiguration {// ...}

De volgende verplichte stap is het registreren van de klas als kandidaat voor automatische configuratie door de naam van de klas onder de sleutel toe te voegen org.springframework.boot.autoconfigure.EnableAutoConfiguration in het standaardbestand resources / META-INF / spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ com.baeldung.autoconfiguration.MySQLAutoconfiguration

Als we willen dat onze autoconfiguratieklasse voorrang heeft op andere autoconfiguratiekandidaten, kunnen we het @AutoConfigureOrder (Besteld.HIGHEST_PRECEDENCE) annotatie.

Automatische configuratie is ontworpen met behulp van klassen en bonen die zijn gemarkeerd met @Voorwaardelijk annotaties zodat de autoconfiguratie of specifieke onderdelen ervan kunnen worden vervangen.

Merk op dat de automatische configuratie alleen van kracht is als de automatisch geconfigureerde bonen niet zijn gedefinieerd in de toepassing. Als u uw boon definieert, wordt de standaardboon overschreven.

3.1. Klasse voorwaarden

De klassevoorwaarden laten ons toe specificeer dat een configuratiebean wordt opgenomen als een gespecificeerde klasse aanwezig is de ... gebruiken @ConditionalOnClass annotatie, of als een klas afwezig is de ... gebruiken @ConditionalOnMissingClass annotatie.

Laten we specificeren dat onze MySQLConfiguration wordt alleen geladen als de class Databron aanwezig is, in welk geval we kunnen aannemen dat de applicatie een database gebruikt:

@Configuration @ConditionalOnClass (DataSource.class) openbare klasse MySQLAutoconfiguration {// ...}

3.2. Bean voorwaarden

Als we willen neem alleen een boon op als een gespecificeerde boon aanwezig is of niet, kunnen we de @ConditionalOnBean en @ConditionalOnMissingBean annotaties.

Om dit te illustreren, voegen we een entiteitManagerFactory bean toe aan onze configuratieklasse, en specificeer dat we deze bean alleen willen maken als een bean wordt aangeroepen databron aanwezig is en als er een boon wordt geroepen entiteitManagerFactory is nog niet gedefinieerd:

@Bean @ConditionalOnBean (naam = "dataSource") @ConditionalOnMissingBean openbaar LocalContainerEntityManagerFactoryBean entityManagerFactory () {LocalContainerEntityManagerFactoryBean em = nieuwe LocalContainerEntityManagerFactoryBean (); em.setDataSource (dataSource ()); em.setPackagesToScan ("com.baeldung.autoconfiguration.example"); em.setJpaVendorAdapter (nieuwe HibernateJpaVendorAdapter ()); if (additionalProperties ()! = null) {em.setJpaProperties (additionalProperties ()); } geef ze terug; }

Laten we ook een transactionManager boon die alleen wordt geladen als een boon van het type JpaTransactionManager is nog niet gedefinieerd:

@Bean @ConditionalOnMissingBean (type = "JpaTransactionManager") JpaTransactionManager transactionManager (EntityManagerFactory entityManagerFactory) {JpaTransactionManager transactionManager = nieuwe JpaTransactionManager (); transactionManager.setEntityManagerFactory (entityManagerFactory); return transactionManager; }

3.3. Eigendomsvoorwaarden

De @ConditionalOnProperty annotatie wordt gebruikt specificeer of een configuratie wordt geladen op basis van de aanwezigheid en waarde van een Spring Environment-eigenschap.

Laten we eerst een eigenschappenbronbestand voor onze configuratie toevoegen dat zal bepalen waar de eigenschappen van zullen worden gelezen:

@PropertySource ("classpath: mysql.properties") openbare klasse MySQLAutoconfiguration {// ...}

We kunnen het main Databron bean die zal worden gebruikt om verbindingen met de database te maken op een zodanige manier dat deze alleen wordt geladen als een eigenschap wordt aangeroepen usemysql is aanwezig.

We kunnen het attribuut gebruiken HavingValue om bepaalde waarden van de usemysql eigenschap die moeten worden gematcht.

Laten we de databron bean met standaardwaarden die verbinding maken met een lokale database met de naam myDb als het usemysql eigenschap is ingesteld op lokaal:

@Bean @ConditionalOnProperty (naam = "usemysql", havingValue = "lokaal") @ConditionalOnMissingBean openbare gegevensbron dataSource () {DriverManagerDataSource dataSource = nieuwe DriverManagerDataSource (); dataSource.setDriverClassName ("com.mysql.cj.jdbc.Driver"); dataSource.setUrl ("jdbc: mysql: // localhost: 3306 / myDb? createDatabaseIfNotExist = true"); dataSource.setUsername ("mysqluser"); dataSource.setPassword ("mysqlpass"); retourneer dataSource; }

Als het usemysql eigenschap is ingesteld op Op maat, de databron bean wordt geconfigureerd met behulp van aangepaste eigenschapswaarden voor de database-URL, gebruiker en wachtwoord:

@Bean (name = "dataSource") @ConditionalOnProperty (name = "usemysql", havingValue = "custom") @ConditionalOnMissingBean openbare DataSource dataSource2 () {DriverManagerDataSource dataSource = nieuwe DriverManagerDataSource (); dataSource.setDriverClassName ("com.mysql.cj.jdbc.Driver"); dataSource.setUrl (env.getProperty ("mysql.url")); dataSource.setUsername (env.getProperty ("mysql.user")! = null? env.getProperty ("mysql.user"): ""); dataSource.setPassword (env.getProperty ("mysql.pass")! = null? env.getProperty ("mysql.pass"): ""); retourneer dataSource; }

De mysql.properties bestand bevat de usemysql eigendom:

usemysql = lokaal

Als een applicatie de MySQLAutoconfiguration de standaardeigenschappen wil overschrijven, hoeft het alleen maar verschillende waarden toe te voegen voor de mysql.url, mysql.user en mysql.pass eigenschappen en de usemysql = aangepast regel in de mysql.properties het dossier.

3.4. Voorwaarden voor hulpbronnen

Het toevoegen van de @ConditionalOnResource annotatie betekent dat de configuratie wordt alleen geladen als een opgegeven bron aanwezig is.

Laten we een methode definiëren met de naam aanvullendeEigenschappen () dat zal een Eigendommen object met Hibernate-specifieke eigenschappen die moeten worden gebruikt door de entiteitManagerFactory bean, alleen als het resourcebestand mysql.properties is aanwezig:

@ConditionalOnResource (resources = "classpath: mysql.properties") @Conditional (HibernateCondition.class) Eigenschappen additionalProperties () {Eigenschappen hibernateProperties = nieuwe Eigenschappen (); hibernateProperties.setProperty ("hibernate.hbm2ddl.auto", env.getProperty ("mysql-hibernate.hbm2ddl.auto")); hibernateProperties.setProperty ("hibernate.dialect", env.getProperty ("mysql-hibernate.dialect")); hibernateProperties.setProperty ("hibernate.show_sql", env.getProperty ("mysql-hibernate.show_sql")! = null? env.getProperty ("mysql-hibernate.show_sql"): "false"); terugkeer hibernateProperties; }

We kunnen de Hibernate-specifieke eigenschappen toevoegen aan het mysql.properties het dossier:

mysql-hibernate.dialect = org.hibernate.dialect.MySQLDialect mysql-hibernate.show_sql = true mysql-hibernate.hbm2ddl.auto = create-drop

3.5. Aangepaste voorwaarden

Als we geen van de voorwaarden van Spring Boot willen gebruiken, kunnen we dat ook definieer aangepaste voorwaarden door de extensie SpringBootCondition class en het overschrijven van de getMatchOutcome () methode.

Laten we een voorwaarde maken met de naam Slaapstandtoestand voor onze aanvullendeEigenschappen () methode die zal verifiëren of een HibernateEntityManager klasse is aanwezig op het klassenpad:

statische klasse HibernateCondition breidt SpringBootCondition uit {privé statische String [] CLASS_NAMES = {"org.hibernate.ejb.HibernateEntityManager", "org.hibernate.jpa.HibernateEntityManager"}; @Override openbare ConditionOutcome getMatchOutcome (ConditionContext-context, AnnotatedTypeMetadata-metagegevens) {ConditionMessage.Builder message = ConditionMessage.forCondition ("Slaapstand"); return Arrays.stream (CLASS_NAMES) .filter (className -> ClassUtils.isPresent (className, context.getClassLoader ())) .map (className -> ConditionOutcome .match (message.found ("class") .items (Style.NORMAL , className))) .findAny () .orElseGet (() -> ConditionOutcome .noMatch (message.didNotFind ("class", "classes") .items (Style.NORMAL, Arrays.asList (CLASS_NAMES)))); }}

Dan kunnen we de voorwaarde toevoegen aan de aanvullendeEigenschappen () methode:

@Conditional (HibernateCondition.class) Eigenschappen additionalProperties () {// ...}

3.6. Toepassingsvoorwaarden

We kunnen ook specificeer dat de configuratie alleen binnen / buiten een webcontext kan worden geladen, door de @ConditionalOnWebApplication of @ConditionalOnNotWebApplication annotatie.

4. Testen van de autoconfiguratie

Laten we een heel eenvoudig voorbeeld maken om onze automatische configuratie te testen. We zullen een entiteitsklasse maken met de naam Mijngebruiker, en een MyUserRepository interface met Spring Data:

@Entity openbare klasse MyUser {@Id private String e-mail; // standard constructor, getters, setters}
openbare interface MyUserRepository breidt JpaRepository {} uit

Om automatische configuratie in te schakelen, kunnen we een van de @SpringBootApplication of @EnableAutoConfiguration annotaties:

@SpringBootApplication openbare klasse AutoconfigurationApplication {openbare statische leegte hoofd (String [] args) {SpringApplication.run (AutoconfigurationApplication.class, args); }}

Laten we vervolgens een JUnit test die een Mijngebruiker entiteit:

@RunWith (SpringJUnit4ClassRunner.class) @SpringBootTest (classes = AutoconfigurationApplication.class) @EnableJpaRepositories (basePackages = {"com.baeldung.autoconfiguration.example"}) openbare klasse AutoconfigurationTest {@Autowired private My My @Test public void whenSaveUser_thenOk () {MyUser user = new MyUser ("[email protected]"); userRepository.save (gebruiker); }}

Omdat we onze Databron configuratie, gebruikt de applicatie de auto-configuratie die we hebben gemaakt om verbinding te maken met een MySQL database genaamd myDb.

De verbindingsreeks bevat de createDatabaseIfNotExist = true eigenschap, dus de database hoeft niet te bestaan. De gebruiker mysqluser of degene die is gespecificeerd via de mysql.user eigenschap als deze aanwezig is, moet worden aangemaakt.

We kunnen het toepassingslogboek controleren om te zien dat het MySQL gegevensbron wordt gebruikt:

web - 2017-04-12 00: 01: 33,956 [main] INFO o.s.j.d.DriverManagerDataSource - Geladen JDBC-stuurprogramma: com.mysql.cj.jdbc.Driver

5. Automatische configuratieklassen uitschakelen

Als we dat wilden sluit de autoconfiguratie uit van het laden, kunnen we de @EnableAutoConfiguration annotatie met uitsluiten of excludeName attribuut aan een configuratieklasse:

@Configuration @EnableAutoConfiguration (exclude = {MySQLAutoconfiguration.class}) openbare klasse AutoconfigurationApplication {// ...}

Een andere optie om specifieke automatische configuraties uit te schakelen, is door de spring.autoconfigure.exclude eigendom:

spring.autoconfigure.exclude = com.baeldung.autoconfiguration.MySQLAutoconfiguration

6. Conclusies

In deze zelfstudie hebben we laten zien hoe u een aangepaste automatische configuratie van Spring Boot maakt. De volledige broncode van het voorbeeld is te vinden op GitHub.

De JUnit-test kan worden uitgevoerd met de autoconfiguratie profiel: mvn schone installatie -Pautoconfiguration.