Давайте посмотрим на код привязки Propertion Spring Boot Tomcat JDBC Pool. Конкретный код заключается в следующем:
Весна: DataSource: Тип: org.apache.tomcat.jdbc.pool.datasource Driver-Class-Name: org.postgresql.driver url: jdbc: postgresql: //192.168.99.100: 5432/postgres? jmx с поддержкой: True Piret-Size: 1 Max-Active: 5 ## При включении свитера бассейна, дополнительное соединение холостого хода будет закрыто Max-Idle: 5 ## Когда подключение к нему> Min-Idle, Poolsweper начнет закрывать Min-Idle: 1
Используя приведенную выше конфигурацию, я наконец обнаружил, что начальный, максимальный, максимальный, максимальный IDLE, MIN-IDLE и другие конфигурации недействительны. Сгенерированный DataSource Tomcat JDBC по -прежнему остается используемой конфигурацией по умолчанию.
Правильная конфигурация
Весна: DataSource: Тип: org.apache.tomcat.jdbc.pool.datasource Driver-Class-Name: org.postgresql.driver url: jdbc: postgresql: //192.168.99.100: 5432/postgres? jmx с поддержкой: true tomcat: ## один пул соединений с базой данных, и конфигурация свойства Tomcat должна быть записана, чтобы вступить в силу начального размера: 1 макс-активность: 5 ## При включении пула, дополнительное простоя
Обратите внимание, что свойства конфигурации конкретного пула соединений с базой данных Tomcat расположены под свойством Spring.Datasource.tomCat, чтобы они могли вступить в силу.
Анализ исходного кода
Spring-boot-autoconfigure-1.5.9.release-sources.jar!/org/springframework/boot/autoconfigure/jdbc/datasourceautoconfiguration.java@configuration @conditional (@classyscyscysebeanal (w.closyssyssing (. Xadatasource.class}) @import ({dataSourceConfiguration.tomcat.class, dataSourceConfiguration.hikari.class, dataSourceConfiguration.dbcp.class, dataSourceConfiguration.dbcp2.class, dataSourconfiguration.generic.class.generic.generic.generic.generic.generic.generic.generic.generic.generic. @Suppresswarnings («Упаковка») защищенный статический классDataSourceConfiguration.tomcat
Spring-boot-autoconfigure-1.5.9.release-sources.jar! /org/springframework/boot/autoconfigure/jdbc/datasourceconfiguration.java/*** Конфигурация DataSource DataSource DataSource. */ @Conditionalonclass (org.apache.tomcat.jdbc.pool.datasource.class) @conditionalonproperty (name = "spring.datasource.type", hastvalue = "org.apache.tomcat.jdbc.pool.datasource", matchifmiss statics = statics statics DataSourceConfiguration {@Bean @ConfigurationProperties (prefix = "Spring.Datasource.tomcat") public org.apache.tomcat.jdbc.pool.datasource dataSource (dataSourceProperties Properties) {org.Apache.TomCat.JdAt. censureatasource (свойства, org.apache.tomcat.jdbc.pool.datasource.class); DataBasedRiver DataBasedRiver = DataBasedRiver .FromJDBCURL (Properties.DeterMINEURL ()); String valyationQuery = dataBasedRiver.getValidationQuery (); if (validationQuery! = null) {dataSource.setTestonBorrow (true); dataSource.setValidationQuery (valyationQuery); } return DataSource; }}Вы можете видеть, что DataSourceProperties здесь имеет только конфигурацию Spring.Datasource Direct Attributes, такие как URL, имя пользователя, пароль, DriverClassName. У Tomcat нет определенных свойств.
Созданный
Защищенные <t> t creationatasource (свойства dataSourceProperties, класс <? Extends DataSource> type) {return (t) Properties.initializedatasourcebuilder (). Тип (тип) .build (); }Org.apache.tomcat.jdbc.pool.datasource PoolProperties, которые непосредственно созданы, также является конфигурацией по умолчанию.
ConfigurationProperties
Конкретная магия заключается в коде @ConfigurationProperties(prefix = "spring.datasource.tomcat") . Перед контейнером пружины прокси -компонент и возврат, он установит атрибут, указанный Spring.datasource.tomcat to org.apache.tomcat.jdbc.pool.datasource
Spring-boot-1.5.9.release-sources.jar !-org/springframework/boot/context/properties/configurationpropertiesbindingpostprocessor.javaprivate void posteprocessbeforeinitialization (объектный бон, строковая боннам, конфигурация, аннулирована) {объектно-целевая = Bean; PropertiesConfigurationFactory <object> factory = new PropertiesConfigurationFactory <object> (target); factory.setPropertySources (this.propertySources); Factory.SetValidator (DexitValidator (Bean)); // Если не предоставляется явная служба преобразования, мы добавляем одну, чтобы (по крайней мере) // Comp-Spearted массивы кабриолетов могут быть связаны автоматически заводски. SetConversionservice (this.conversionservice == null? GetDefaultCongersionService (): this.ConversionService); if (annotation! = null) {factory.setignoreInvalidfields (annotation.ignoreInvalidfields ()); Factory.SetIgnOUnkNownfields (Annotation.IgnoreUnknownfields ()); factory.setExceptionifinvalid (annotation.exceptionifinvalid ()); Factory.SetIgnorEntestProperties (Annotation.IgnorEntestProperties ()); if (stringutils.haslength (annotation.prefix ())) {factory.setTargetName (annotation.prefix ()); }} try {factory.bindproperteStoTarget (); } catch (Exception ex) {string targetClass = classutils.getShortName (target.getClass ()); бросить новое beancreationException (beanname », не удалось связать свойства с« + targetClass + »(« + getAnnotationdetails (аннотация) + »)», Ex); }} Обратите внимание, что аннотацией здесь является @ConfigurationProperties(prefix = "spring.datasource.tomcat") , его префикс - spring.datasource.tomcat PropertiesConfigurationFactory TargetName - spring.datasource.tomcat
PropertiesConfigurationFactory.BindProperTiestOtargetSpring-boot-1.5.9.Release-sources.jar! /Org/springframework/boot/bind/propertiesconfigurationfactory.javapublic void bindproperteStoTarget () throwsexception {assert.state (это. Proedsosrty (). нулевой"); try {if (logger.istraceenabled ()) {logger.trace ("Источники свойств:" + this.propertysources); } this.hasbeenbound = true; dobindpropertiestotarget (); } catch (bindException ex) {if (this.exceptionifinvalid) {throw ex; } PropertiesConfigurationFactory.logger .Error («Не удалось загрузить свойства проверки бобов.» + «Ваши свойства могут быть недействительными.», Ex); }}Делегировать метод DobindproperteStoTarget
PropertiesConfigurationFactory.dobindProperTiestOtargetPrivate void doBindProperTiestOtarget () Throws BindException {relextDatabinder databinder = (this.TargetName! = Null? New RelexedDatabinder (this.Target, this.TargetName): новый расслабляемый (это. 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.SetIgnorENTEDPROPERTIES (this.IgnorEntestProperties); DataBinder.SetIgnoreInvalidFields (this.IgnoreInvalidfields); DataBinder.SetIgnOureUnknownfields (this.ignoreunknownfields); CumpizeBinder (DataBinder); Iteerable <string> rextemedTargetNames = getRelaxedTargetNames (); SET <String> names = getNames (RelexedTargetNames); PropertyValues PropertyValues = getPropertySourcesPropertyValues (имена, RelexedTargetNames); DataBinder.Bind (PropertyValues); if (this.validator! = null) {databinder.validate (); } checkforBindingErrors (DataBinder); }Здесь используйте метод RelexedDatabinder.Bind
getRelaxedTargetNamesprivate iterable <string> getRelaxEdTargetNames () {return (this.Target! = null && stringUtils.haslength (this.TargetName)? New RelectedNames (this.TargetName): null); }Вот новые имена RelectDnaMedNAMED, которые могут идентифицировать варианты множества переменных
Расслабленные имена
Spring-boot-1.5.9.release-sources.jar !/org/springframework/boot/bind/relaxednames.javaprivate void initiaze (string name, set <stry> values) {if (values.contains (name)) {return; } для (вариация вариации: variation.values ()) {for (манипуляция по манипуляциям: манипуляции.values ()) {string result = name; result = manipulation.apply (result); result = variation.apply (результат); values.add (result); инициализировать (результат, значения); }}} /*** Вариации имени. */ enum variation {none {@Override public String Apply (String value) {return Value; }}, Нижняя часть {@Override public String Apply (String value) {return value.isempty ()? Значение: value.tolowerCase (); }}, Uppercase {@Override public String Apply (String value) {return value.isempty ()? значение: value.touppercase (); }}; Public Abstract String Apply (String Value); }То есть метод написания конфигурации в org.springframework.boot.bind.relaxednames@6ef81f31 [name = spring.datasource.tomcat, values = [spring.datasource.tomcat, spring_datasource_tomcat, springdatasoumcat, springdatomcatmacat,, springdatomcat, springdatomcatmacat,, Springdatomcat, SpringDatoMcat,, SpringdatoMcat,, SpringDatoMcat,, SpringDataSourcat, SpringdatoMcat Spring.datasource.tomcat, Spring_datasource_tomcat, Springdatasourcetomcat]].
getPropertySourcesPropertyValuesprivate PropertyValues getPropertySourcespropertyValues (SET <String> имена, uterable <string> relexedTargetNames) {PropertynamePatternSmatcher include = GetProperTynaMepatternSmatcher (names, relectgergetNames); вернуть новые недвижимость, которые проводят PropertyValues (This.PropertySources, имена, включает в себя, это то. }Этот метод будет вытащить конфигурацию свойства в Spring.datasource.tomact в объект PropertyValues
RelectedDatabinder.Bind
Spring-boot-1.5.9.Release-sources.jar !/org/springframework/boot/bind/relaxeddatabinder. Метод связывания Java вызывает метод родительского класса Spring-context-4.3.13.Release-sources.jar! /org/springframework/validation/databinder.java/** **- * <p> Этот вызов может создавать ошибки поля, представляя базовые ошибки привязки *, такие как требуемое поле (код «требуется») или несоответствие типа * между значением и свойством бобов (код «typemismatch»). * <p> Обратите внимание, что данное свойства Property Lovales должны быть одноразовым экземпляром: * Для эффективности он будет изменен, чтобы просто содержать допустимые поля, если он * реализует интерфейс mitablepropertyValues; Иначе для этой цели будет создана внутренняя изменчивая * копия. Передайте копию PropertyValues* Если вы хотите, чтобы ваш первоначальный экземпляр оставался в любом случае. * @param значения свойств PVS, чтобы связать * @see #dobind (org.springframework.beans.mutablepropertyvalues) */ public void bind (Propertyvalues pvs) {mitablePropertyValues mpvs = (pvs instanceof mutablepropertyvalues)? (MitablePropertyValues) PVS: New MitablePropertyValues (PVS); Dobind (MPVS); } /** * Фактическая реализация процесса привязки, работая с * переданным экземпляром MitablePropertyValues. * @param mpvs значения свойства для связывания, * как intablepropertyvalues ancement * @see #checkallowedfields * @see #checkrequiredfields * @see #applypropertyvalues */ protected void dobind (mutablepropertyvalues mpvs) {feeklowedfields (mpvs); CheckRequiredFields (MPVS); ApplyPropertyValues (MPVS); } /*** Применить заданные значения свойства к целевому объекту. * <p> Реализация по умолчанию применяет все предоставленные значения свойства * в виде значений свойства бобов. По умолчанию неизвестные поля * будут проигнорированы. * @param mpvs значения свойств, которые должны быть связаны (могут быть изменены) * @see #gettarget * @see #getpropertyaccessor * @see #isignoreunknownfields * @see #getBindingErrorProcessor * @seeb {// Привязка параметров запроса на целевой объект. getPropertyAccessor (). SetPropertyValues (mpvs, isignoreunknownfields (), isignoreinvalidfields ()); } catch (PropertyBatchUpdateException ex) {// Использовать процессор ошибки привязки для создания FielderRors. для (PropertyAccessException pae: ex.getPropertyAccessExceptions ()) {getBindingErrorProcessor (). ProcessPropertyAccessException (pae, getInternalbindingResult ()); }}} /**! */ Защищенная конфигурируемая propertyAccessor getPropertyAccessor () {return getInternalBindingResult (). getPropertyAccessor (); }Наконец, он установлен GetPropertyAccessor (). Это свойство ACCOSORS является org.springframework.boot.bind.relaxeddatabinder $ rexmedbeanwrapper: wrapping obj
AbstractPropertyAccessor.SetPropertyValuessPring-Beans-4.3.13.Release-Sources.jar!/org/springframework/beans/abstractpropertyaccessor.java@override public void setPropertyvalues (Propertyvalues pvs, Boolean ignoreNown, Boolean Ignore-ighrinv x Список <propertyAccessException> PropertyAccessExceptions = null; List <propertyValue> PropertyValues = (PVS ExanceOf MitablePropertyValues? (((MitablePropertyValues) PVS) .getPropertyValist (): Arrays.aslist (pvs.getPropertyValues ())); Для (PropertyValue PV: PropertyValues) {try {// Этот метод может бросить любое BeanSexception, которое не будет пойман // здесь, если существует критический сбой, такой как полевое поле. // Мы можем попытаться справиться только с менее серьезными исключениями. SetPropertyValue (PV); } catch (notWriteRPropertyException ex) {if (! Игнорировать) {throw ex; } // В противном случае просто игнорируйте его и продолжайте ...} Catch (nullvalueinnestestPatexception ex) {if (! IgnoreInvalid) {throw ex; } // В противном случае просто игнорируйте его и продолжайте ...} Catch (PropertyAccessException ex) {if (PropertyAccessExceptions == null) {PropertyAccessExceptions = новый LinkedList <propertyAccessException> (); } PropertyAccessExceptions.add (ex); }} // Если мы столкнулись с индивидуальными исключениями, добавьте составное исключение. if (PropertyAccessExceptions! = null) {PropertyAccessException [] paearray = PropertyAccessExceptions.toarray (новое свойство propertyAccessexception [PropertyAccessExceptions.size ()]); бросить новую собственность batchupdateexception (paearray); }} @Override public void setPropertyValue (PropertyValue PV) бросает BeanSexception {PropertyTokenholder Tokens = (PropertyTokenholder) pv.ResolvedTokens; if (tokens == null) {string propertyname = pv.getName (); AbstractNestablePropertyAccessor nestEdpa; try {nestEdpa = getPropertyAccessorPorPropertyPath (PropertyName); } catch (notReadablePropertyException ex) {throw newWriteblePropertyException (getRootClass (), this.nestedPath + PropertyName, «вложенное свойство в пути» « + PropertyName +» '' не существует », Ex); } tokens = getPropertyMetokens (getFinalPath (nestEdpa, PropertyName)); if (nestedpa == this) {pv.getoriginalpropertyvalue (). ResolvedTokens = tokens; } nestEdpa.setPropertyValue (Tokens, PV); } else {setPropertyValue (tokens, pv); }}Здесь nestedpa.setPropertyValue (Tokens, PV); Реальная настройка Spring.datasource.tomcat значения свойства - это org.springframework.boot.bind.relaxeddatabinder $ rextbeanwrapper: wrapping object [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a], наконец, calmentsablepableproprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocessprocess
AbstractNestablePropertyAccessor.ProcessLocalPropertySpring-beans-4.3.13.Release-sources.jar! /Org/springframework/beans/abstractnestablepropertyaccessor.javaprivate void processlocalproperty (PropertyTockenhondholder Tokens, PropertyValue Pv) getLocalPropertyHandler (tokens.actualName); if (ph == null ||! ph.iswriteble ()) {if (pv.isoptional ()) {if (logger.isdebugenabled ()) {logger.debug («Игнорирование необязательного значения для свойства ' + tokens.actualname +» - свойство не найдено в классе Bean [ + getRootclass () + »() +» (). } возвращаться; } else {throw createNotWritePropertyException (tokens.canonicalName); }} Object OldValue = null; try {Object riginalValue = pv.getValue (); Object valuetoApply = OriginalValue; if (! boolean.false.equals (pv.conversionnecessary)) {if (pv.isconverted ()) {valuetoApply = pv.getConvertedValue (); } else {if (isExtractoldValueForeditor () && ph.IsReadable ()) {try {oldValue = ph.getValue (); } catch (Exception ex) {if (ex exanceOf privieDedActionException) {ex = ((privilegedActionException) ex) .getException (); } if (logger.isdebugenabled ()) {logger.debug («Не удалось прочитать предыдущее значение свойства '" + this.nestedPath + tokens.canonicalName + "'", ex); }} valuetoApply = convertforProperty (tokens.canonicalName, oldValue, OriginalValue, ph.TopyedScriptor ()); } pv.getoriginalpropertyValue (). ConfurtionNecessary = (valuetoApply! = OriginalValue); } ph.SetValue (this.WroadObject, valuetoApply); } catch (typemiscexexception ex) {throw ex; } catch (vocationTargetException ex) {PropertyChangeEvent PropertyChangeEvent = new PropertyChangeEvent (this.Rootobject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue ()); if (ex.getTargetException () exanceOf classcastException) {Throw New TypeMismAchexception (PropertyChangeEvent, ph.getPropertyType (), ex.getTargetException ()); } else {throwable case = ex.getTargetException (); if (причина экземпляра UndeclaredThorwableException) {// может произойти например, с помощью Groovy-генерируемых методов CAUSE = cane.getCause (); } бросить новый MethodInvocationException (PropertyChangeEvent, причина); }} catch (Exception ex) {PropertyChangeEvent pce = new PropertyChangeEvent (this.Rootobject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue ()); бросить новый метод invocationException (pce, ex); }}Это заставляет его устанавливать с использованием класса org.springframework.beans.beanwrapperimpl $ beanpropertyhandler
BeanWrapperimpl $ beanpropertyhandler.setvaluespring-beans-4.3.13.release-sources.jar!/org/springframework/beans/beanwrapperimpl.java@override public void setvalue (final Object, объект ValueToApply) Trows Exception {final Method writemethod = (thise object aluetoApply) trows {final метод. GenericTypeaWarePropertyDescriptor? if (! modifier.ispublic (writemethod.getDeclaringClass (). getModifiers ()) &&! writemethod.isaccessible ()) {if (System.getSecurityManager ()! = null) {Accescontroller.doprileged (new PrisieDaction <bheat> () {@Override publicr Run Run () {) {) {). writemethod.setAccessible (true); } else {writemethod.setAccessible (true); }} окончательное значение объекта = valuetoApply; if (System.getSecurityManager ()! = null) {try {accessController.doprivileged (new PrivilegedExceptionAction <Object> () {@Override public run () бросает исключение {writemethod.invoke (object, value); return null;}}, acc); } catch (privilegedActionException ex) {throw ex.getException (); }} else {writemethod.invoke (getWroadInStance (), value); }}}}Здесь мы используем отражение, чтобы найти метод SetXXX (например, SETMACTACTICE), а затем устанавливаем его в
Конфигурация многоданного источника
Вышеуказанная конфигурация не проблематична для одного источника данных. Для нескольких источников данных конфигурация следующая
@ConfigurationPublic Class MasterDatasourceConfig {@bean ("MasterDatasource") @ConfigurationProperties (prefix = "Spring.Datasource.master") public DataSource MasterDatasource () {return DataSourceBuilder.create (). Build (); }}Обратите внимание, что вам необходимо добавить дополнительные настройки для введения конфигурации Properties в пул Tomcat JDBC
Весна: DataSource: Master: Type: org.apache.tomcat.jdbc.pool.datasource Driver-Class-name: org.postgresql.driver url: jdbc: postgresql: //192.168.99.100: 5432/postgres? jmx с поддержкой: true# tomcat: ## Для нескольких источников данных нам нужно удалить здесь Tomcat и поместить их под префикс источника источника данных Начальный размер: 1 Max-Active: 5 ## Когда включено подметало бассейна, дополнительное простальное соединение будет закрыто.
Оригинальная конфигурация Tomcat должна быть размещена в соответствии с префиксом источника данных, и она не может вступить в силу в соответствии с Spring.datasource.tomcat или Spring.datasource.master.tomcat.