Schauen wir uns den Eigenschaftsbindungscode des Spring -Boot -Tomcat -JDBC -Pools an. Der spezifische Code lautet wie folgt:
Frühling: DataSource: Typ: org.apache.tomcat.jdbc.pool.datasource Treiberklassenname: org.postgresql.driver URL: JDBC: postgresql: //192.168.99.100: 5432/Postgres? JMX-fähig: TRUE INITIAL-SIZE: 1 MAX-Active: 5 ## Wenn der Poolpullover aktiviert ist, wird zusätzliche Leerlaufverbindung max.
Unter Verwendung der obigen Konfiguration fand ich schließlich, dass initiale, max-aktive, max-idle, min-idle und andere Konfigurationen ungültig sind. Die generierte Tomcat -JDBC -DataSource ist weiterhin die verwendete Standardkonfiguration.
Richtige Konfiguration
Frühling: DataSource: Typ: org.apache.tomcat.jdbc.pool.datasource Treiberklassenname: org.postgresql.driver URL: JDBC: postgresql: //192.168.99.100: 5432/Postgres? JMX-EINFEHLER: TRUE TOMCAT: ## Ein einzelner Datenbankverbindungspool, und die Tomcat-Eigenschaftskonfiguration muss geschrieben werden, um die Initialgröße zu ergreifen: 1 Max-Active: 5 ## Wenn der Pool-Kehrer aktiviert ist, wird zusätzliche Leerlaufverbindung geschlossen.
Beachten Sie, dass die Konfigurationseigenschaften des spezifischen Tomcat -Datenbankverbindungspools unter der Feder.DataSource.Tomcat -Eigenschaft platziert werden, damit sie wirksam werden können.
Quellcodeanalyse
Spring-Boot-autoconfigure-1.5.9.Release-sources.jar!/org/springframework/boot/autoconfigure/jdbc/datasourceAutoconfiguration.java@configuration @conditional ({dataCondition.condition.condition.condition.condition.condition.condition.condition.condition.condition.condition) @conditionalonmingBean ({{{claders.condition) @conditionalonmingBean (| XadataSource.class}) @import ({dataSourceConfiguration.tomcat.class, dataSourceConfiguration.hikari.class, dataSourceConfiguration.dbcp.class, DataSourceConfiguration.dbcp2.Classe, DataSourceConfiguration.Class} -Classe, DataSourceConfiguration.Class} -Classe, DataSourceConfiguration.GASCONIGURATION.CLASS.CLASS, DATASOURCECONCONIGURATION.GASEC.CLASS. @Suppresswarnings ("Abschaltung") geschützte statische Klasse PooledDatasourceConfiguration {}DataSourceConfiguration.tomcat
Spring-Boot-Autoconfigure-1.5.9.Release-sources.jar! /org/springframework/boot/autoconfigure/jdbc/datasourceConfiguration.java/*** Tomcat Pool DataSource-Konfiguration. */ @ConditionalonClass (org.apache.tomcat.jdbc.pool.datasource.class) @ConditionalonProperty (name = "Spring.datasource.type", mit Value = "org. DataSourceConfiguration {@Bean @ConfigurationProperties (Präfix = "Spring.datasource.tomcat") public org.apache.tomcat.jdbc.pool.datasource dataSource (dataSourceProperties) {org.APAPache.Tomat.jdbc.poolce.tomat.tomat.jdbc.poolce.tomat. createdataSource (Eigenschaften, org.apache.tomcat.jdbc.pool.datasource.class); Databasedriver databasedriver = databasedriver .fromjdbcurl (Properties.Determiturl ()); String validationQuery = databasedriver.getValidationQuery (); if (validationQuery! DataSource.setValidationQuery (ValidationQuery); } return DataSource; }}Sie können sehen, dass die DataSourceProperties hier nur die Konfiguration von Spring.DataSource -Direktattributen wie URL, Benutzername, Kennwort, DriverClassName haben. Tomcat hat keine spezifischen Eigenschaften.
CreatedataSource
Protected <T> t CreateDataSource (DataSourceProperties -Eigenschaften, Klasse <? Erweitert DataSource> Typ) {return (t) Eigenschaften.initialisierteatasourcebuilder (). Typ (Typ) .build (); }Die org.apache.tomcat.jdbc.pool.datasource Poolproperties, die direkt erstellt wurde, ist auch die Standardkonfiguration.
Konfigurationsproperties
Die spezifische Magie liegt im Code @ConfigurationProperties(prefix = "spring.datasource.tomcat") . Bevor der Federcontainer die Proxy -Bean erstellt und zurückgibt
Spring-Boot-1.5.9.Release-sources.jar! /org/springframework/boot/context/properties/configurationPropertiesBindingPostProcessor.javaprivate void postRocessBeforeialization (Objektbean, String BeanName, ConfigurationProperties Annotation) {Objektzielziele-Ziel = Objektziel-Ziel = Anname-Anname, Annotion) {Object = Object = Objektziel; PropertiesConfigurationFactory <Object> factory = new PropertiesConfigurationFactory <Object> (Ziel); factory.setPropertySources (this.PropertySources); factory.setValidator (bestimmenValidator (bean)); // Wenn kein explizite Konvertierungsdienst angeboten wird, fügen wir einen hinzu, damit (zumindest) // Comma-getrennte Arrays von Cabriles automatisch fabrisch gebunden werden können. if (Annotation! factory.setignoreUnnownFields (Annotation.InnoreUnuNNOWNFields ()); factory.setExceptionIFinValid (Annotation.ExceptionInvalid ()); factory.setignorenEstProperties (Annotation.IignorenestProperties ()); if (Stringutils.hasLength (Annotation.prefix ()) {factory.settargetName (Annotation.prefix ()); }} try {factory.bindpropertiestotarget (); } catch (Ausnahme ex) {String targetClass = clasutils.getShortName (target.getClass ()); Neue BeancreationException werfen (Beanname, "konnte die Eigenschaften nicht an" + targetClass + "(" + getAnnotationDetails (Annotation) + ")"), Ex) binden; }} Beachten Sie, dass die Annotation hier @ConfigurationProperties(prefix = "spring.datasource.tomcat") lautet, sein Präfix ist spring.datasource.tomcat PropertiesConfigurationFactory Targetname ist Spring.Datasource.tomcat
PropertiesConfigurationFactory.bindPropertiesToTargetspring-boot-1.5.9.RELEASE-sources.jar!/org/springframework/boot/bind/PropertiesConfigurationFactory.javapublic void bindPropertiesToTarget() throws BindException { Assert.state(this.propertySources != null, "PropertySources should nicht null sein "); try {if (logger.istaceEnabled ()) {logger.trace ("Eigenschaftsquellen:" + this.PropertySources); } this.hasbeenbound = true; dobindpropertiestotarget (); } catch (bindException ex) {if (this.ExceptionInvalid) {throw ex; } PropertiesConfigurationFactory.logger .Error ("Die Validierungsbean der Eigenschaften nicht laden." + "Ihre Eigenschaften können ungültig sein.", Ex); }}Delegieren Sie die Methode DobindPropertiestotarget
PropertiesConfigurationFactory. if (this.validator! } if (this.conversionService! = null) {Databinder.setConversionService (this.conversionService); } databinder.setAutogrowCollectionLimit (Integer.max_value); Databinder.SetignorenestProperties (this.ignorenestProperties); Databinder.SetignoreinValidfields (this.ignoreinvalidfields); Databinder.SetignoreUnnownFields (this.ignoreUnNOnnownfields); CustomizeBinder (Databinder); Iterable <string> relaxedTargetNames = getRelaxedTargetNames (); Set <string> names = getNames (entspannteTargetNames); PropertyValues PropertyValues = getPropertySourcesPropertyValues (Namen, entspannte Targetnamen); Databinder.bind (PropertyValues); if (this.validator! = null) {databinder.validate (); } CheckForbindingErrors (Datenbankpolster); }Verwenden Sie hier die Methode RelaxedDatabinder.bind
GetRelaXedTargetNamePrivate iterable <string> GetRelaxedTargetNames () {return (this.target! }Hier finden Sie neue Entspannungsnamen, die Varianten mehrerer Variablen identifizieren können
Entspannte Names
Spring-boot-1.5.9.Release-sources.jar! /org/springframework/boot/bind/relaxednames.javaprivate void initialize (String-Name, Set <string> Werte) {if (values.contains (name)) {return; } für (Variationsvariation: Variation.Values ()) {für (Manipulation Manipulation: Manipulation.Values ()) {String result = name; result = Manipulation.Apply (Ergebnis); result = variation.Apply (Ergebnis); Werte.Add (Ergebnis); initialisieren (Ergebnis, Werte); }}} /*** Name Variationen. */ Enum -Variation {Keine {@Override public String anwenden (String -Wert) {Rückgabewert; }}, Kleinbuchstaben {@Override public String anwenden (String -Wert) {return value.isempty ()? Wert: value.tolowerCase (); }}, Großbuchstaben {@Override public String anwenden (String -Wert) {return value.isempty ()? Wert: value.toUppercase (); }}; öffentliche abstrakte Zeichenfolge anwenden (String -Wert); }Das heißt Spring.DataSource.tomcat, Spring_DataSource_Tomcat, SpringDatasourcetomcat]] wird unterstützt.
GetPropertySourcesPropertyValueSPrivate PropertyValues GetPropertySourcesPropertyValues (set <string> Namen, iterable <string> relaxedTargetNames) {PropertyNamePattersMatcher include = GetPropertynApatternSmatcher (Namen, RelaxedTargetNames); Neue PropertySourcesPropertyValues zurückgeben (this.PropertySources, Namen, dies. }Diese Methode zieht die Eigenschaftskonfiguration unter feder
Entspanntedatabinder.bind
Spring-Boot-1.5.9.Release-sources.jar! /org/springframework/boot/bind/relaxedDatabinder.java's Bind-Methode nennt die Methode der Elternklasse Spring-Context-4.3.13.Release-Sources.jar! /org/springFrameWork/validation/databinder. * <P> Dieser Aufruf kann Feldfehler erstellen, die grundlegende Bindung * Fehler wie ein erforderliches Feld (Code "erforderlich") oder ein Mismatch * zwischen Wert und Beaneigenschaft (Code "Typemismispatch") darstellen. * <P> Beachten Sie, dass die angegebenen Eigenschaften eine Wegwerfinstanz sein sollten: * Für die Effizienz wird sie so geändert, dass sie nur erlaubte Felder enthalten, wenn sie die Schnittstelle für MutablePropertyValues implementiert. Andernfalls wird zu diesem Zweck eine interne Veränderung * Kopie erstellt. Geben Sie eine Kopie der PropertyValues* Geben Sie in jedem Fall nicht modifiziert. * @param PVS -Eigenschaftswerte zu binden * @see #dobind (org.springframework.beans.mutablepropertyValues) */ public void bind (PropertyValues pvs) {MutablePropertyValues mpvs = (PVS Instance von MustablePropertyValues)? (MutablePropertyValues) PVS: neue MutablePropertyValues (PVS); Dobind (MPVs); } /** * Tatsächliche Implementierung des Bindungsprozesses, Arbeit mit der Instanz von * Passing-In-In-In-In-In-PropertyValues. * @param mpvs Die Eigenschaftenwerte zu binden, * als mummbarePropertyValues -Instanz * @see #Checkallowedfields * @see #CheckRequiredfields * @see #ApplyPropertyValues */ Protected void dobind (mutablePropertyValues mpvs) {{achaLaLaDedfields (mpvvs); checkRequiredfields (MPVs); applyPropertyValues (MPVs); } /*** Die angegebene Eigenschaftswerte auf das Zielobjekt anwenden. * <P> Standardimplementierung wendet alle mitgelieferten Eigenschaften * Werte als Bean -Eigenschaftswerte an. Standardmäßig werden unbekannte Felder * ignoriert. * @param mpvs the property values to be bound (can be modified) * @see #getTarget * @see #getPropertyAccessor * @see #isIgnoreUnknownFields * @see #getBindingErrorProcessor * @see BindingErrorProcessor#processPropertyAccessException */ protected void applyPropertyValues(MutablePropertyValues mpvs) {try {// Anforderungsparameter an das Zielobjekt bin. GetPropertyAccessor (). setPropertyValues (MPVs, IssignoreunnoUnnownfields (), IssignoreinValidfields ()); } catch (PropertyBatchUpDateException ex) {// Verwenden Sie Bindfehlerprozessor, um Fielderrors zu erstellen. für (PropertyAccessException PAE: Ex.GetPropertyAccessexceptions ()) {getBindingErrorProcessor (). ProcessPropertyAccessException (pae, GetInternalbindingResult ()); }}} /*** Geben Sie den zugrunde liegenden PropertyAccessor der BindingResult dieses Bindemittels zurück. */ Protected ConfigurablePropertyAccessor getPropertyAccessor () {return GetInternalbindingResult (). getPropertyAccessor (); }Schließlich wird es von getPropertyAccessor () festgelegt. Dieser PropertyAccessor ist org.springframework.boot.bind.RelaxedDatabinder $ relaxedBeanWrapper: Wraping -Objekt [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a], der verpackte org.
AbstractPropertyAccessor.setPropertyValuesspring-beans-4.3.13.Release-sources.jar!/org/springframework/beans/abstractPropertyaccessor Liste <SperticAccessexception> PropertyAccessexceptions = NULL; Liste <Sperticalue> propertyValues = (PVS -Instanz von MutablePropertyValues? ((MutablePropertyValues) PVS) .getPropertyValuelist (): Arrays.aslist (Pvs.getPropertyValues ())); Für (PropertyValue PV: PropertyValues) {try {// Diese Methode kann eine Beansexception werfen, die hier nicht erwischt wird //, wenn ein kritischer Fehler wie kein Matching -Feld vorliegt. // Wir können versuchen, nur mit weniger ernsthaften Ausnahmen umzugehen. setPropertyValue (PV); } catch (NotwritablePropertyException ex) {if (! IgnoreUnnown) {throw ex; } // ansonsten ignorieren Sie es einfach und fahren Sie weiter ...} catch (nullValueInnestpathexception ex) {ignororInvalid) {throw ex; } // Ansonsten ignorieren Sie es einfach und setzen Sie es weiter ...} catch (PropertyAccessException ex) {if (propertyAccessexceptions == null) {PropertyAccessexceptions = new LinkedList <Spertive AccessException> (); } PropertyAccessexceptions.add (Ex); }} // Wenn wir auf individuelle Ausnahmen gestoßen sind, werfen Sie die zusammengesetzte Ausnahme aus. if (PropertyAccessexceptions! Neue PropertyBatchupdateException (Paearray) werfen; }} @Override public void setPropertyValue (PropertyValue PV) löscht Beansexception {PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens; if (tokens == null) {String propertyName = pv.getName (); AbstractNestablePropertyAccessor nestedPA; try {nestedpa = getPropertyAccessorforPropertyPath (PropertyName); } catch (notReadablePropertyException ex) {Neue NotwritablePropertyException (getrootClass (), this.NestedPath + PropertyName, "verschachtelte Eigenschaft in Pfad" " + PropertyName +" 'nicht existiert ", Ex); } tokens = getPropertynametokens (GetFinalPath (nestedPA, EigentumName)); if (nestedpa == this) {pv.getoriginalPropertyValue (). Auflösungen = Tokens; } nestedpa.setPropertyValue (Tokens, PV); } else {setPropertyValue (Tokens, PV); }}Hier nestedpa.setPropertyValue (Tokens, PV); Die tatsächliche Einstellung von Spring.DataSource.tomcat -Eigenschaftswert ist org.springframework.boot.bind.relaxedDatabinder $ relaxedBeanWrapper: Wraping -Objekt [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a] schließlich aufzeigen, abtraktnestable, abtraktnestable, abtraktnestable, abtraktnestable, abtraktnestable, abtraktnestable, letztendlich, AbstractnestableStable.
AbstractNestablePropertyAccessor. getLocalPropertyHandler (tokens.acualName); if (ph == null ||! ph.iswritable ()) {if (pv.isoptional ()) {if (logger.isdebugenabled ()) {logger.debug ("Ignorieren optionaler Wert für Eigenschaften" + tokens.acualname + "' - Eigenschaft, die auf Bean Class [" + + + + + + + Getrootclass ("). } zurückkehren; } else {throw CreateNotRabitablePropertyException (tokens.canonicalName); }} Objekt oldValue = null; try {Object OriginalValue = pv.getValue (); Object ValuetoApply = originalValue; if (! boolean.false.equals (pv.conversionnegary)) {if (pv.isconverted ()) {ValuetoApply = pv.getConvertedValue (); } else {if (isextractractOrteValueForeditor () && ph.isreadable ()) {try {oldValue = ph.getValue (); } catch (Ausnahme ex) {if (ex instanceOf privilEgedActionException) {ex = ((privilegedActionException) ex) .GetException (); } if (logger.isdebugenabled ()) {logger.debug ("konnte den vorherigen Wert der Eigenschaft nicht lesen" + this.nestedPath + tokens.canonicalName + "'", Ex); }} ValuetoApply = convertforProperty (tokens.canonicalName, OldValue, OriginalValue, Ph.Totypedescriptor ()); } pv.getoriginalPropertyValue (). ConversionNeory = (ValuEToApply! = OriginalValue); } ph.setValue (this.wradedObject, ValuetoApply); } catch (typemismatchException ex) {throw ex; } catch (invocationTargetException ex) {PropertyChangeEvent PropertyChangeEvent = new PropertyChangeEvent (this.rootObject, this.nestedPath + tokens.canonicalName, OldValue, pv.getValue ()); if (ex.gettargetException () InstanceOf classCastException) {neue TypemismatchatchException (PropertyChangeEvent, Ph.getPropertyType (), ex.gettargetException ()); } else {throwable cause = ex.gettargetException (); if (Ursache Instanz von nicht deklarierter DrüsebüßerException) {// kann mit groovy-erzeugten Methoden auftreten cours = cause.getCause (); } Neue MethodeInvocationException (PropertyChangeEvent, Ursache); }} catch (Exception ex) {PropertyChangeEvent pce = new PropertyChangeEvent (this.rootObject, this.nestedPath + tokens.canonicalName, OldValue, pv.getValue ()); Neue MethodInvocationException (PCE, Ex) werfen; }}Es wird mit der Klasse org.springframework.beans.beanwrapperimpl $ beanpropertyHandler festgelegt
BeanWrapperImpl$BeanPropertyHandler.setValuespring-beans-4.3.13.RELEASE-sources.jar!/org/springframework/beans/BeanWrapperImpl.java@Override public void setValue(final Object object, Object valueToApply) throws Exception { final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor? if (! modifier.ispublic (writeemethod.getDeclaringClass (). getModifiers ()) &&! Writemethod.isaccessible ()) {if (System.getSecurityManager ()! writeMethod.setAccessible (true); } else {WriteMethod.setAccessible (true); }} Final Object Value = ValueToApply; if (system.getSecurityManager ()! } catch (privilegedActionException ex) {throw ex.GetException (); }} else {WriteMethod.invoke (getWrapTInstance (), Wert); }}}}Hier verwenden wir Reflection, um die setxxx
Multi-Daten-Quellkonfiguration
Die obige Konfiguration ist für eine einzelne Datenquelle nicht problematisch. Für mehrere Datenquellen ist die Konfiguration wie folgt
@ConfigurationPublic Class MasterDataSourceConfig {@bean ("masterdataSource") @ConfigurationProperties (Präfix = "Spring.DataSource.master") public dataSource masterdataSource () {return DataSourceBuilder.crereate (). Build (); }}Beachten Sie, dass Sie zusätzliche Einstellungen hinzufügen müssen, um die Konfigurationsproperties in den Tomcat -JDBC -Pool zu injizieren
Frühling: DataSource: Master: Typ: org.apache.tomcat.jdbc.pool.dataSource Dreiber-Klasse-Name: org.postgresql.driver URL: JDBC: postgresql: //192.168.99.100: 5432/postgressql = 6000 & Socettimesout = 6000 username? JMX-fähig: TRUE# TOMCAT: ## Für mehrere Datenquellen müssen wir Tomcat hier entfernen und unter das Präfix der Datenquelle initiale Größe: 1 Max-Active: 5 ## Wenn Pool-Kehrmaschine aktiviert ist, wird die zusätzliche Leerlaufverbindung Max-Idle geschlossen: 5 ## Wenn müdeverbindung> Mini-IDLE, Poolsweeper geschlossen wird: 1####.
Die ursprüngliche Tomcat -Konfiguration muss unter das Präfix der Datenquelle platziert werden, und sie kann nicht unter Spring.datasource.tomcat oder Spring.DataSource.master.tomcat wirksam werden.