Echemos un vistazo al código vinculante de propiedad del boot de primavera Tomcat JDBC Pool. El código específico es el siguiente:
spring: datasource: type: org.apache.tomcat.jdbc.pool.DataSource driver-class-name: org.postgresql.Driver url: jdbc:postgresql://192.168.99.100:5432/postgres?connectTimeout=6000&socketTimeout=6000 username: postgres password: postgres JMX-habilitado: Verdadero tamaño inicial: 1 Max-activo: 5 ## Cuando el suéter de la piscina está habilitado, la conexión inactiva adicional se cerrará Max-Idle: 5 ## Cuando la conexión inactiva> Min-Iidle, la piscina comenzará a cerrar Min-Iidle: 1
Usando la configuración anterior, finalmente descubrí que el tamaño inicial, Max-Active, Max-Idle, Min-Iidle y otras configuraciones no son válidas. El TomCat JDBC DataSource generado sigue siendo la configuración predeterminada utilizada.
Configuración correcta
spring: datasource: type: org.apache.tomcat.jdbc.pool.DataSource driver-class-name: org.postgresql.Driver url: jdbc:postgresql://192.168.99.100:5432/postgres?connectTimeout=6000&socketTimeout=6000 username: postgres password: postgres JMX-habilitado: verdadero Tomcat: ## Un solo grupo de conexión de base de datos, y la configuración de la propiedad de Tomcat debe escribirse para entrar en vigencia de tamaño inicial: 1 max-activo: 5 ## Cuando el barredor de la piscina esté habilitado, la conexión inactiva adicional se cerrará máximo: 5 ## cuando la conexión inactiva> mínimo mínimaz
Tenga en cuenta que las propiedades de configuración del grupo específico de conexión de la base de datos Tomcat se colocan bajo la propiedad Spring.dataSource.TomCat para que puedan entrar en vigencia.
Análisis del código fuente
Spring-Boot-Autoconfigure-1.5.9.Release-Sources.Jar!/org/springframework/boot/autoconfigure/jdbc/datasourceautoconfiguration.java@configuration @conditional (piscoleddataSourcondition.class) @condicionalonmissing (dataseurce.class, @ClassourCondition.class) XadataSource.class}) @import ({dataSourCeConfiguration.tomcat.class, dataSourCeConfiguration.hikari.class, dataSourCeConfiguration.dbcp.class, dataSourCeConfiguration.dbcp2.class, dataSourCeciguration.general.class}) @SupessWarnings ("Depreción") La clase estática protegida a PooledDataSourCeconfiguration {}DataSourCeConfiguration.TomCat
Spring-Boot-Autoconfigure-1.5.9.Release-Sources.jar! /org/springframework/boot/autoconfigure/jdbc/datasourceconfiguration.java/*** Configuración de datos de datos de Tomcat Pool. */ @Conditionalonclass (org.apache.tomcat.jdbc.pool.dataSource.class) @conditionalonproperty (name = "spring.datasource.type", teniendoValue = "org.apache.tomcat.jdbc.pool.dataSource", Matchifmissing = true) static classtends. DataSourCeConfiguration {@Bean @ConfigurationProperties (prefix = "Spring.datasource.tomcat") public org.apache.tomcat.jdbc.pool.datasource dataSource (dataSourcePerties Properties) {org.apache.tomcat.jdbc.pool.dataseurce dataSource = Createsource (Properties, org.apache.tomcat.jdbc.pool.dataSource.class); DatabasedRiver dataBasedRiver = dataBasedRiver .FromJDBCurl (Properties.DetermineUrl ()); String ValidationQuery = databasedRiver.getValidationQuery (); if (validationQuery! = null) {dataSource.settestonBorrow (true); DataSource.SetValidationQuery (ValidationQuery); } return dataSource; }}Puede ver que el DataSourceProperties aquí solo tiene la configuración de los atributos directos de Spring.DataSource, como URL, nombre de usuario, contraseña, DriverClassName. Tomcat no tiene propiedades específicas.
creadoatasource
protegido <t> t creatatAsource (dataSourceProperties Propiedades, clase <? extiende DataSource> type) {return (t) propiedades.initializedataSourceBuilder (). type (type) .Build (); }Org.apache.tomcat.jdbc.pool.datasource PoolProperties que creó directamente altaseurce también es la configuración predeterminada.
ConfigurationProperties
La magia específica se encuentra en el código @ConfigurationProperties(prefix = "spring.datasource.tomcat") . Antes de que el contenedor de primavera construya el proxy bean y regrese, establecerá el atributo especificado por spring.datasource.tomcat en org.apache.tomcat.jdbc.pool.datasource
Spring-Boot-1.5.9.Release-Sources.jar! /org/springframework/boot/context/properties/configurationPropertiesbindingpostPostProcessor.javaprivate void postprocessbeforeinitialization (objeto, string beanName, configuración de configuración anotación) {objeto objetivo = bean; PropertiesConfigurationFactory <ject> factory = new PropertySconfigurationFactory <S Object> (Target); factory.setPropertySources (this.propertySources); factory.setValidator (determinar Validator (frijol)); // Si no se proporciona un servicio de conversión explícito, agregamos uno para que (al menos) // las matrices de convertibles separados por comas se puedan unir automáticamente fábrica. if (annotation! = null) {factory.setignoreinvalidfields (annotation.ignoreinValidfields ()); Factory.SetignoreUnknownFields (Annotation.ignoreUnknownFields ()); factory.setExceptionifinValid (annotation.ExceptionifinValid ()); Factory.SetignorenEdedProperties (Annotation.ignorenEndedProperties ()); if (stringUtils.hasLength (annotation.prefix ())) {factory.settargetName (annotation.prefix ()); }} try {factory.bindpropertiestroTarget (); } Catch (Exception Ex) {String TargetClass = classUtils.getShortName (target.getClass ()); Tire nuevo BeanCreationException (BeanName ", no pudo unir las propiedades a" + TargetClass + "(" + getAnnotationDetails (anotación) + ")", ex); }} Tenga en cuenta que la anotación aquí es @ConfigurationProperties(prefix = "spring.datasource.tomcat") , su prefijo es spring.datasource.tomcat PropertiesConfigurationFactory TargetName es 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 not be nulo"); Pruebe {if (logger.istraceEnabled ()) {logger.trace ("fuentes de propiedad:" + this.propertySources); } this.hasbeenBound = true; DOBINDPROPERTOTOTARGET (); } catch (bindException ex) {if (this.ExceptionifinValid) {throw ex; } PropertiesConfigurationFactory.logger .Error ("No se pudo cargar Propiedades de validación Bean." + "Sus propiedades pueden no ser válidas", ex); }}Delegar al método de DoBindProperToToTarget
PropertiesConfigurationFactory.DobindPropertOnToRgetPrivate void DobindProperTiestOTarget () lanza BindException {RELAJEDDATABINDER DATABINDER = (this.TargetName! = NULL? New RelleedDatabinder (this.Target, this.TargetName): New RelajedDatabinder (this.target); if (this.validator! = null && this.validator.supports (databinder.getTarget (). getClass ())) {databinder.setValidator (this.validator); } if (this.conversionService! = null) {databinder.setConversionService (this.ConversionService); } databinder.setAutoGrowCollectionLimit (integer.max_value); databinder.setignorenEdedProperties (this.ignorenesteredProperties); databinder.SetInignoreInValidFields (this.IngnoreInValidFields); databinder.setignoreunknownfields (this.ignoreunknownfields); CustomizeBinder (Databinder); ITerable <String> RELAYTTARGETNAMES = GETRELAXEDTARGETNAMES (); Establecer <String> Names = GetNames (relaxedTargetNames); PropertyValues PropertyValues = getPropertySourcesPropertyValues (nombres, relaxedTargetNames); databinder.bind (PropertyValues); if (this.validator! = null) {databinder.validate (); } checkforbindingErrors (databinder); }Aquí, use el método relajado de la reducción.
getRelaxedTargetNamesPrivate ITerable <String> getRelaxedTargetNames () {return (this.target! = null && stringUtils.haslength (this.targetName)? new RelleedNames (this.targetName): null); }Aquí hay un nuevo nombre relajado que pueden identificar variantes de múltiples variables
Names relajados
Spring-Boot-1.5.9.Release-Sources.jar! /org/springframework/boot/bind/relaxednames.javaprivate void inicialize (name de cadena, establecer <string> valores) {if (valores.contains (name)) {return; } for (variación variación: variation.values ()) {for (manipulación manipulación: manipulación.values ()) {string dultin = name; resultado = manipulación.apply (resultado); resultado = variación.apply (resultado); valores.Add (resultado); inicializar (resultado, valores); }}} /*** Variaciones de nombre. */ enum variación {ninguno {@Override public String aplicar (valor de cadena) {value de retorno; }}, Minúsculas {@Override public String aplicar (valor de cadena) {return value.isEmpty ()? valor: value.tolowercase (); }}, Uppercase {@Override public String aplicar (valor de cadena) {return value.isEmpty ()? valor: value.toupperCase (); }}; Public Abstract String Apply (valor de cadena); }Es decir, el método de escritura de configuración en org.springframework.boot.bind.relaxednames@6ef81f31 [name = spring.datasource.tomcat, valores = [spring.datasource.tomcat, spring_datasource_tomcat, springdatasourcetomcat, springdatasourcetomcat,, Spring.datasource.tomcat, spring_datasource_tomcat, springdatasourcetomcat]] es compatible.
GetPropertySourcesPropertyValuesPropersValues GetPropertySourcesPropertyValues (establecer <String> nombres, Itererable <String> RelatedTargetNames) {PropertyNamePatterNsmatcher include = getPropertynamePatterNsMatcher (nombres, relajado, seglingnames); devolver nuevo PropertySourcesPropertyValues (this. }Este método extraerá la configuración de la propiedad en spring.dataSource.tomact en el objeto PropertyValues
RelatedDatabinder.Bind
Spring-Boot-1.5.9.Release-Sources.jar! /org/springframework/boot/bind/relaxeddatabinder.java's Bind Method llama al método de la clase principal Spring-Context-4.3.13.Release-Sources.jar! /RispringFrameFrameWork/Validation/Databinder.Java/*** BIEN los valores de la propiedad dada. * <P> Esta llamada puede crear errores de campo, representando errores de enlace básico * como un campo requerido (código "requerido") o escribir desajuste * entre el valor y la propiedad de Bean (código "typeMismatch"). * <p> Tenga en cuenta que los valores de propiedad dados deben ser una instancia desechable: * Para la eficiencia, se modificará para contener campos permitidos si * implementa la interfaz MutablePropertyValues; De lo contrario, se creará una copia interna mutable * para este propósito. Pase una copia de PropertyValues* Si desea que su instancia original permanezca sin modificar en ningún caso. * @param Los valores de propiedad de PVS para vincular * @see #doBind (org.springframework.beans.mutablePropertyValues) */ public void bind (PropertyValues PVS) {mutablePropertyvalues mpvs = (instancia de PVS de mutablePrepertyValues)? (MutablePropertyValues) PVS: nuevos valores mutibles (PVS); Dobind (MPVS); } /** * Implementación real del proceso de vinculación, trabajando con la instancia de Values MutablePRopertyValues * aprobados. * @param mpvs Los valores de las propiedades para unir, * como instancia mutablePropertyValues * @see #checkallowedfields * @see #checkRequiredFields * @see #ApplyPropertyValues */ Protected Void Dobind (MutablePropertyValues MPVS) {CheckAllowedFields (MPVS); CheckRquiredFields (MPVS); AplicarPropertyValues (MPVS); } /*** Aplicar valores de propiedad dados al objeto de destino. * <p> La implementación predeterminada aplica todos los valores de propiedad suministrada * como valores de propiedad de Bean. Por defecto, los campos desconocidos serán * ignorados. * @param mpvs Los valores de propiedad se unirán (se pueden modificar) * @see #getTarget * @see #getPropertyAccorsor * @see #isignoreunknownFields * @see #getBindingErrorProcessor * @see bindingerRoRoCossor #processpropertyAcccessException */ protegido aparteretyvalues (MutedLablePrepertyValEl MPVS) {try {// enlace los parámetros de solicitud en el objeto de destino. getPropertyAccessor (). setPropertyValues (MPVS, IsignoreunknownFields (), IsignoreInvalidfields ()); } Catch (PropertyBatchUpdateException ex) {// Use el procesador de error de enlace para crear filderrores. para (PropertyAccessException Pae: Ex.getPropertyAccessExceptions ()) {getBindingErrorProcessor (). ProcessPropertyAccessException (PAE, getInternalBindingResult ()); }}} /*** Devuelve el profesor de propiedad subyacente de BindingResult de este aglutinante. */ Proteged ConfigurablePropertyAccessor getPropertyAccessor () {return getInternalBindingResult (). GetPropertyAccessor (); }Finalmente, está establecido por GetPropertyAccessor (). Este PropertyAccessor es org.springframework.boot.bind.relaxeddatabinder $ relajado
AbstractPropertyAcCessor.SetPropertyValuessPring-Beans-4.3.13.Release-Sources.Jar!/org/springframework/Beans/AbStractPropertyAccessor.java@override public void setPropertyvalues (propiedad de propiedades PVS, boolean ignoreunknow Lista <PropertyAccessException> PropertyAccessExceptions = null; List <SpertityValue> PropertyValues = (PVS Instance de mutablePropertyValues? ((MutablePropertyValues) PVS) .getPropertyValuelist (): arrays.aslist (pvs.getpropertyvalues ()); para (PropertyValue PV: PropertyValues) {try {// Este método puede lanzar cualquier BeanSexception, que no se atrapará // aquí, si hay una falla crítica, como no un campo de correspondencia. // Podemos intentar lidiar solo con excepciones menos serias. setPropertyValue (PV); } Catch (NotwritititablePropertyException ex) {if (! IgnoreUnknown) {lanzar ex; } // de lo contrario, simplemente ignórelo y continúe ...} Catch (NullValueInnestedPathException ex) {if (! IgnoreInValid) {Throw Ex; } // de lo contrario, simplemente ignórelo y continúe ...} Catch (PropertyAccessException ex) {if (PropertyAccessExceptions == null) {PropertyAccessExCeptions = new LinkedList <PropertyAccessException> (); } PropertyAccessExceptions.Add (ex); }} // Si encontramos excepciones individuales, arroje la excepción compuesta. if (PropertyAccessExCeptions! = NULL) {PropertyAccessException [] paearray = PropertyAccessExceptions.ToArray (New PropertyAccessException [PropertyAccessExceptions.size ()]); tirar nueva propiedadBatchUpdateException (paearray); }} @Override public void setPropertyValue (PropertyValue PV) lanza BeanSexception {PropertyTokenHokeLeTer Tokens = (PropertyTokenHolder) PV.ResOlvedTokens; if (tokens == null) {string propertyname = pv.getName (); AbstractSnestablePropertyaccessor NestedPA; intente {nestedPA = getPropertyAcCessorForPropertyPath (PropertyName); } Catch (NotreadablePropertyException ex) {tirar nueva nowritablePropertyException (getRootClass (), this.nestedPath + Propertyname, "Propiedad anidada en la ruta '" + Propertyname + "' no existe", ex); } tokens = getPropertynametokens (getFinalPath (NestedPA, Propertyname)); if (nestedPa == this) {pv.getOriginalPropertyValue (). resueldTokens = tokens; } Nestedpa.setPropertyValue (tokens, PV); } else {setPropertyValue (tokens, pv); }}Aquí NestedPA.SetPropertyValue (fichas, PV); La configuración real de Spring.Datasource.TomCat Value es org.springframework.boot.bind.relaxeddatabinder $ relajado
AbstractSnablePropertyAccessor.ProcessLocalPropertySpring-Beans-4.3.13.Release-Sources.jar! /Org/SpringFramework/Beans/AbStractNestablePropertyAccessor.JavaPrivate Void ProcessLocalPerty (PropertyToWround Hearter tokens, Property Value Pv)) getLocalPropertyHandler (tokens.ActualName); if (ph == null ||! ph.iswritable ()) {if (pv.isOptional ()) {if (logger.isdeBugeNabled ()) {logger.deBug ("ignorando el valor opcional para la propiedad '" + tokens.ActualName + " - Propiedad no encontrada en la clase de bean [" + getRootClass (). getName () ")"] "); } devolver; } else {lanzar createnotwritablePropertyException (tokens.anonicalName); }} Objeto OldValue = null; intente {objeto originalValue = pv.getValue (); Objeto valuetoapply = originalValue; if (! boolean.false.equals (pv.conversionNecessary)) {if (pv.isconverted ()) {valueToAply = pv.getConverTedValue (); } else {if (isExtractOldValueForedIder () && ph.iseadable ()) {try {OldValue = Ph.getValue (); } Catch (Exception Ex) {if (ex instanceOf PrivilegEdActionException) {ex = (((privilegedActionException) ex) .getException (); } if (logger.isdeBugeNabled ()) {logger.debug ("no pudo leer el valor anterior de la propiedad '" + this.nestedPath + tokens.canonicalName + "", ex); }} valuetoapply = convertForProperty (tokens.CanonicalName, OldValue, originalValue, ph.totypedescriptor ()); } pv.getOriginalPropertyValue (). conversionNecessary = (valueToApply! = originalValue); } ph.setValue (this.wrappedObject, valueetoapply); } catch (typemismatchException ex) {tirar ex; } Catch (InvocationTargetException ex) {PropertyChangeEvent PropertyChangeEvent = New PropertyChangeEvent (this.rootObject, this.nestedPath + tokens.CanonicalName, OldValue, pv.getValue ()); if (ex.getTargetException () instancia de classcastException) {Throw New typeMismatchException (PropertyChangeEvent, ph.getPropertyType (), ex.getTargetException ()); } else {shrowable causa = ex.getTargetException (); Si (causa la instancia de UndeclaredThowableException) {// puede ocurrir, por ejemplo, con los métodos generados de Groovy Cause = Cause.getCause (); } lanzar una nueva MethodInVocationException (PropertyChangeEvent, causa); }} Catch (Exception Ex) {PropertyChangeEvent PCE = New PropertyChangeEvent (this.rootobject, this.nestedPath + tokens.CanonicalName, OldValue, pv.getValue ()); tirar nueva MethodInVocationException (PCE, EX); }}Lo hace establecido usando la clase org.springframework.beans.beanwrapperimpl $ beanpropertyhandler
Beanwrapperimpl$BeanPropertyHandler.setValuespring-Beans-4.3.13.Release-Sources.Jar!/org/springframework/Beans/BeanWrapperMpl.Java@Override public void setValue, objeto final, objeto ValuetOpply) lanza excepción {Method final WritEmethod = (esta.pd outor GenericTypeaSePROPERTYDESCRIPTOR? if (! Modifier.ispublic (writeMethod.getDeClaringClass (). getModifiers ()) &&! WriteMethod.IsAccessible ()) {if (System.getSecurityManager ()! = NULL) {AccessController.DoPrivilEded (new PrivilEdaction <epan> () { @ @ @@Override Object () {{) {{{{{{) WriteMethod.SetAccessible (verdadero); } else {writeMethod.setAccessible (true); }} valor del objeto final = valueToAply; if (system.getSecurityManager ()! = NULL) {try {accessController.Doprivileged (new PrivilegEdExceptionAction <SPEt> () {@Override public Object Run () lanza la excepción {WriteMethod.Invoke (objeto, valor); return null;}}, acc); } capt (privilegedActionException ex) {Throw Ex.GetException (); }} else {writeMethod.invoke (getWrappingInstance (), valor); }}}}Aquí usamos reflexión para encontrar el método SetXXX (como SetMaxActive), y luego establecerlo en
Configuración de origen de múltiples datos
La configuración anterior no es problemática para una sola fuente de datos. Para múltiples fuentes de datos, la configuración es la siguiente
@ConfigurationPublic Class MasterDataSourCeconfig {@Bean ("MasterDataSource") @ConfigurationProperties (prefix = "Spring.DataSource.master") Public DataSource MasterDataSource () {return dataSourceBuilder.create (). Build ();; }}Tenga en cuenta que debe agregar configuraciones adicionales para inyectar las ConfigurationProperties en Tomcat JDBC Pool
Primavera: DataSource: Maestro: Tipo: org.apache.tomcat.jdbc.pool.dataSource-class-class-name: org.postgresql.driver url: jdbc: postgresql: //192.168.99.100: 5432/postgres? ConnecttimeOut = 6000 & socketTimeout = 6000 username JMX-habilitado: Verdadero# Tomcat: ## Para múltiples fuentes de datos, necesitamos eliminar Tomcat aquí y colocarlos bajo el prefijo de la fuente de datos de tamaño inicial: 1 Max-Active: 5 ## Cuando la barredora de la piscina está habilitada, la conexión inactiva adicional se cerrará Max-IDLE: 5 ## cuando la conexión inactiva> Min-Idle, la delegación de la piscina comenzará a cerrar Min-Iidle: 1 1
La configuración original de Tomcat debe colocarse bajo el prefijo de fuente de datos, y no puede entrar en vigencia en Spring.datasource.tomcat o Spring.datasource.master.tomcat.