มาดูรหัสการเชื่อมโยงคุณสมบัติของสปริงบูต 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-enabled: TRUE ขนาดเริ่มต้น: 1 MAX-ACTIVE: 5 ## เมื่อเปิดใช้งานเสื้อสเวตเตอร์พูลการเชื่อมต่อที่ไม่ได้ใช้งานพิเศษจะปิด MAX-IDLE: 5 ## เมื่อไม่ได้ใช้งาน
เมื่อใช้การกำหนดค่าข้างต้นในที่สุดฉันก็พบว่าขนาดเริ่มต้น, max-active, max-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: TOMCAT จริง: ## พูลการเชื่อมต่อฐานข้อมูลเดียวและการกำหนดค่าคุณสมบัติ TOMCAT จะต้องเขียนเพื่อให้ได้ผลเริ่มต้นขนาดเริ่มต้น: 1 MAX-ACTIVE: 5 ## เมื่อเปิดใช้งานพูลตัวกวาด
โปรดทราบว่าคุณสมบัติการกำหนดค่าของพูลการเชื่อมต่อฐานข้อมูล TOMCAT ที่เฉพาะเจาะจงนั้นอยู่ภายใต้คุณสมบัติ Spring.datasource.tomcat เพื่อให้สามารถมีผลได้
การวิเคราะห์ซอร์สโค้ด
Spring-boot-autoconfigure-1.5.9.5.release-sources.jar!/org/springframework/boot/autoconfigure/jdbc/datasourceautoconfiguration.java@configuration @conditional xadatasource.class}) @Import ({dataSourceConfiguration.tomcat.class, dataSourceConfiguration.hikari.class, dataSourceConfiguration.dbcp.class @suppresswarnings ("deprecation") การป้องกันคลาสคงที่ pooledDataSourceConfiguration {}dataSourceConfiguration.tomcat
Spring-boot-autoconfigure-1.5.9.9.release-sources.jar! /org/springframework/boot/autoconfigure/jdbc/datasourceConfiguration.java/*** การกำหนดค่าแหล่งข้อมูลพูล Tomcat */ @conditionalonclass (org.apache.tomcat.jdbc.pool.datasource.class) @conditionalonproperty (name = "spring.datasource.type", มีค่า = "org.apache.tomcat.jdbc.pool.datasource" DataSourceConfiguration {@bean @configurationProperties (คำนำหน้า = "spring.datasource.tomcat") สาธารณะ org.apache.tomcat.jdbc.pool.datasource dataSource (dataSourceProperties) CreateDataSource (Properties, org.apache.tomcat.jdbc.pool.datasource.class); DataBasedRiver DataBasedRiver = DataBasedRiver .FromJdBcurl (Properties.determineUrl ()); String ValidationQuery = dataBasedRiver.getValidationQuery (); if (validationQuery! = null) {dataSource.SettestonBorrow (จริง); DataSource.SetValidationQuery (ValidationQuery); } ส่งคืนแหล่งข้อมูล; -คุณจะเห็นได้ว่า DataSourceProperties ที่นี่มีการกำหนดค่าของสปริงแอตทริบิวต์โดยตรง Datasource เช่น URL ชื่อผู้ใช้รหัสผ่าน DriverClassName Tomcat ไม่มีคุณสมบัติเฉพาะ
CreateDataSource
ได้รับการป้องกัน <t> t createdAtAsource (คุณสมบัติ DataSourceProperties, class <? ขยายข้อมูลแหล่งข้อมูล> ประเภท) {return (t) properties.initializedataSourceBuilder (). ประเภท (ประเภท) .build (); -org.apache.tomcat.jdbc.pool.datasource poolproperties ที่สร้างขึ้นโดยตรงกับการกำหนดค่าเริ่มต้นด้วย
การกำหนดค่า properties
เวทมนตร์เฉพาะอยู่ในรหัส @ConfigurationProperties(prefix = "spring.datasource.tomcat") ก่อนที่คอนเทนเนอร์สปริงจะสร้างถั่วพร็อกซีและส่งคืนมันจะตั้งค่าแอตทริบิวต์ที่ระบุโดย spring.datasource.tomcat เป็น org.apache.tomcat.jdbc.pool.datasource
Spring-boot-1.5.9.release-sources.jar! /org/springframework/boot/context/properties/configurationPropertiesbindingPostProcessor.javaprivate void postprocessbeforeinitialization PropertiesConfigurationFactory <Object> Factory = PropertiesConfigurationFactory <Object> (เป้าหมาย); Factory.SetPropertySources (this.PropertySources); Factory.SetValidator (deconinevalidator (ถั่ว)); // หากไม่มีบริการแปลงที่ชัดเจนเราจะเพิ่มหนึ่งเพื่อให้ (อย่างน้อย) // อาร์เรย์ที่คั่นด้วยเครื่องหมายจุลภาคของ Convertibles สามารถผูกมัดโดยอัตโนมัติจากโรงงาน SetConversionservice (this.ConversionService == null? if (คำอธิบายประกอบ! = null) {Factory.SetIgnoreInvalidfields (คำอธิบายประกอบ. EignoreInvalidfields ()); Factory.eStignOreunkNownfields (Annotation.ignoreunknownfields ()); Factory.SeteXceptionIfinValid (Annotation.ExceptionIfinValid ()); Factory.SetignorenestedProperties (Annotation.ignorenestedProperties ()); if (stringutils.haslength (Annotation.prefix ())) {Factory.settargetName (Annotation.prefix ()); }} ลอง {Factory.BindProperTiesTarget (); } catch (Exception Ex) {String targetClass = classUtils.getShortName (target.getClass ()); โยน beancreationexception ใหม่ (Beanname, "ไม่สามารถผูกคุณสมบัติกับ" + targetClass + "(" + getannotationDetails (คำอธิบายประกอบ) + ")", อดีต); - โปรดทราบว่าคำอธิบายประกอบที่นี่คือ @ConfigurationProperties(prefix = "spring.datasource.tomcat") คำนำหน้าคือ spring.datasource.tomcat PropertiesConfigurationFactory ชื่อเป้าหมายคือ Spring.datasource.tomcat
PropertiesConfigurationFactory.bindpropertiestotargetspring-boot-1.5.9.release-sources.jar!/org/springframework/boot/bind/propertiesconfigurationfactory.javapublic void bindpropertiestotarget () bindexception ไม่เป็นโมฆะ "); ลอง {ถ้า (logger.istraceenabled ()) {logger.trace ("แหล่งที่มาของคุณสมบัติ:" + this.propertysources); } this.hasbeenbound = true; dobindpropertiestotarget (); } catch (bindexception ex) {ถ้า (this.exceptionifinvalid) {โยน ex; } propertiesConfigurationFactory.logger .Error ("ไม่สามารถโหลดคุณสมบัติการตรวจสอบคุณสมบัติถั่ว" + "คุณสมบัติของคุณอาจไม่ถูกต้อง", อดีต); -มอบหมายวิธี DobindProperTiesTarget
PropertiesConfigurationFactory.DobindProperTiesTiesTargetPrivate เป็นโมฆะ dobindPropertiestotarget () พ่น bindexception {relaxedDatabinder databinder = (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.setignorenestedProperties (this.ignorenestedProperties); databinder.etignoreinvalidfields (this.ignoreinvalidfields); Databinder.eStignOreunkNownfields (this.ignoreunknownfields); CustomizeBinder (Databinder); iterable <string> relaxedTargetNames = getRelaxedTargetNames (); ตั้งค่า <string> names = getNames (relaxedTargetNames); PropertyValues PropertyValues = GetPropertySourcesPropertyValues (ชื่อ, RelaxedTargetNames); databinder.bind (PropertyValues); if (this.validator! = null) {databinder.validate (); } checkForBindingErrors (databinder); -ที่นี่ใช้วิธีการ relaxedDatabinder.bind
getRelaxedTargetNamesPrivate iterable <string> getRelaxedTargetNames () {return (this.target! = null && stringutils.haslength (this.targetName)? -นี่คือชื่อผ่อนคลายใหม่ที่สามารถระบุตัวแปรของตัวแปรหลายตัว
ชื่อผ่อนคลาย
Spring-boot-1.5.9.release-sources.jar! /org/springframework/boot/bind/relaxednames.javaprivate เป็นโมฆะเริ่มต้น (ชื่อสตริง, ตั้งค่า <string> ค่า) {ถ้า (value.contains (ชื่อ)) {return; } สำหรับ (การแปรผันของความแปรปรวน: dariation.values ()) {สำหรับ (การจัดการการจัดการ: manipulation.values ()) {string result = name; ผลลัพธ์ = การจัดการ apply (ผลลัพธ์); ผลลัพธ์ = การแปรผัน apply (ผลลัพธ์); Values.add (ผลลัพธ์); เริ่มต้น (ผลลัพธ์, ค่า); }}} /*** รูปแบบชื่อ */ enum variation {none {@Override public String ใช้ (ค่าสตริง) {ค่าส่งคืน; }}, ตัวพิมพ์เล็ก {@Override สาธารณะสตริงใช้ (ค่าสตริง) {return value.isEmpty ()? ค่า: value.toLowerCase (); }}, uppercase {@Override Public String ใช้ (ค่าสตริง) {return value.isEmpty ()? ค่า: value.touppercase (); - ใช้สตริงนามธรรมสาธารณะ (ค่าสตริง); -นั่นคือวิธีการเขียนการกำหนดค่าใน org.springframework.boot.bind.relaxednames@6ef81f31 [name = spring.datasource.tomcat, ค่า = [spring.datasource.tomcat, Spring_datasource_tomcat spring.datasource.tomcat, spring_datasource_tomcat, springdatasourcetomcat]] ได้รับการสนับสนุน
GetPropertySourcesPropertyValuesPrivate PropertyValues getPropertySourcesPropertyValues (ตั้งค่า <Tring> ชื่อ, iterable <String> RelaxedTargetNames) {PropertyNamePatternSmatcher รวม = getPropertyNamePatternSmatcher ส่งคืนทรัพย์สินใหม่ SourcesPropertyValues (this.PropertySources ชื่อรวมถึงสิ่งนี้ resolveplaceholders); -วิธีนี้จะดึงการกำหนดค่าคุณสมบัติภายใต้ Spring.datasource.tomact ลงในวัตถุ PropertyValues
relaxedDatabinder.bind
Spring-boot-1.5.9.release-sources.jar! /org/springframework/boot/bind/relaxeddatabinder.java's วิธีการผูกมัดวิธีการของคลาสแม่ Spring-context-4.3.13.release-sources.jar! /org/springframework * <p> การโทรนี้สามารถสร้างข้อผิดพลาดของฟิลด์ซึ่งแสดงถึงข้อผิดพลาดพื้นฐาน * ข้อผิดพลาดเช่นฟิลด์ที่ต้องการ (รหัส "จำเป็น") หรือพิมพ์ไม่ตรงกัน * ระหว่างค่าและคุณสมบัติถั่ว (รหัส "typemismatch") * <p> โปรดทราบว่าอสังหาริมทรัพย์ที่กำหนดควรเป็นอินสแตนซ์ของการโยน: * เพื่อประสิทธิภาพมันจะถูกแก้ไขเพื่อให้มีฟิลด์ที่อนุญาตหากมันใช้อินเตอร์เฟส MutablePropertyValues; อื่น ๆ จะมีการสร้างสำเนาที่ไม่แน่นอนภายในเพื่อจุดประสงค์นี้ ส่งสำเนาของ PropertyValues* หากคุณต้องการให้อินสแตนซ์ดั้งเดิมของคุณไม่ได้แก้ไขในทุกกรณี * @param pvs ค่าคุณสมบัติในการผูก * @see #dobind (org.springframework.beans.mutablePropertyValues) */ โมฆะสาธารณะผูก (PropertyValues PVS) {MutablePropertyValues mpvs = (pvs อินสแตนซ์ (MutablePropertyValues) PVS: ใหม่ MutablePropertyValues (PVS); Dobind (MPVs); } /** * การใช้งานจริงของกระบวนการเชื่อมโยงการทำงานกับอินสแตนซ์ * ที่ผ่านการ MutablePropertyValues * ส่งผ่าน * @param mpvs ค่าคุณสมบัติที่จะผูก * เป็นอินสแตนซ์ mutablePropertyValues * @See #CheckallowedFields * @See #CheckRequiredFields * @See #applyPropertyValues */ void dobind (MutablePropertyValues mpvs) CheckRequiredfields (MPVs); ApplyPropertyValues (MPVs); } /*** ใช้ค่าคุณสมบัติที่กำหนดกับวัตถุเป้าหมาย * <p> การใช้งานเริ่มต้นใช้คุณสมบัติทั้งหมดที่ให้ไว้ * ค่าเป็นค่าคุณสมบัติถั่ว โดยค่าเริ่มต้นฟิลด์ที่ไม่รู้จักจะถูกละเว้น * @param mpvs ค่าคุณสมบัติที่จะถูกผูกไว้ (สามารถแก้ไขได้) * @see #getTarget * @See #GetPropertyAccessor * @See #ISIGNORENKNOWNFIELDS * @SEE #GETBINDINGERRORPROCOSSOR * mpvs) {ลอง {// ผูกพารามิเตอร์คำขอไปยังวัตถุเป้าหมาย GetPropertyAccessor (). SetPropertyValues (MPVS, Isignoreunknownfields (), Isignoreinvalidfields ()); } catch (PropertyBatchUpDateException ex) {// ใช้ตัวประมวลผลข้อผิดพลาดการผูกเพื่อสร้าง fielderRors สำหรับ (PropertyAccessException PAE: Ex.GetPropertyAccessExceptions ()) {getBindingERRORPROCESSOR (). ProcessPropertyAccessException (PAE, GetInternalBindingResult ()); }}} /*** ส่งคืนทรัพย์สินที่เป็นพื้นฐานของ BindingResult ของสารยึดเกาะนี้ */ ป้องกันการกำหนดค่า propropertyaccessor getPropertyAccessor () {return getInternalBindingResult (). getPropertyAccessor (); -ในที่สุดมันถูกตั้งค่าโดย getPropertyAccessor () PropertyAccessor นี้คือ org.springframework.boot.bind.relaxeddatabinder $ relaxedbeanwrapper: การห่อวัตถุ [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a]
AbstractPropertyAccessor.SetPropertyValuesspring-beans-4.3.13.release-sources.jar!/org/springframework/beans/abstractpropertyaccessor.java@override {list <propertyAccessException> PropertyAccessExceptions = null; รายการ <propertyValue> PropertyValues = (PVS Instanceof MutablePropertyValues? ((MutablePropertyValues) PVS) .getPropertyValueluSist (): array.aslist (pvs.getPropertyValues ()); สำหรับ (PropertyValue PV: PropertyValues) {ลอง {// วิธีนี้อาจโยน beansexception ใด ๆ ซึ่งจะไม่ถูกจับ // ที่นี่หากมีความล้มเหลวที่สำคัญเช่นไม่มีฟิลด์ที่ตรงกัน // เราสามารถพยายามจัดการกับข้อยกเว้นที่ร้ายแรงน้อยกว่าเท่านั้น SetPropertyValue (PV); } catch (notwablePropertyException ex) {if (! isliunknown) {โยน ex; } // มิฉะนั้นเพียงแค่เพิกเฉยต่อมันและดำเนินการต่อ ... } catch (nullValueInnestatedPathException ex) {ถ้า (! ไม่สนใจ inoreinvalid) {โยน ex; } // มิฉะนั้นเพียงแค่เพิกเฉยและดำเนินการต่อ ... } catch (PropertyAccessException ex) {ถ้า (PropertyAccessExceptions == null) {PropertyAccessExceptions = ใหม่ LinkedList <PoreportAccessException> (); } PropertyAccessExceptions.add (ex); }} // ถ้าเราพบข้อยกเว้นแต่ละข้อให้โยนข้อยกเว้นคอมโพสิต if (PropertyAccessExceptions! = null) {PropertyAccessException [] paeArray = PropertyAccessExceptions.toArray (ใหม่ PropertyAccessException [PropertyAccessExceptions.size ()]); โยน PropertyBatchupDateException ใหม่ (PaeArray); }} @Override โมฆะสาธารณะ setPropertyValue (PropertyValue PV) พ่น beansexception {PropertyTokenolder Tokens = (PropertyTokenolder) PV.ResolvedTokens; if (tokens == null) {String propertyName = pv.getName (); AbstractnestablePropertyAccessor Nestedpa; ลอง {nestedpa = getPropertyAccessorForPropertyPath (PropertyName); } catch (notreadablePropertyException ex) {โยน notwablePropertyException ใหม่ (getRootClass (), this.nestedPath + PropertyName, "คุณสมบัติที่ซ้อนกันใน Path '" + PropertyName + "' ไม่มีอยู่", Ex); } tokens = getPropertyNametokens (getFinalPath (nestedpa, propertyName)); if (nestedpa == สิ่งนี้) {pv.getoriginalPropertyValue (). ResolvedTokens = โทเค็น; } nestedpa.setPropertyValue (โทเค็น, PV); } else {setPropertyValue (โทเค็น, pv); -ที่นี่ nestedpa.setPropertyValue (โทเค็น, PV); การตั้งค่าที่แท้จริงของ Spring.datasource.tomcat ค่าคุณสมบัติคือ org.springframework.boot.bind.relaxeddatabinder $ relaxedbeanwrapper: การห่อวัตถุ [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a] ในที่สุด
AbstractnestablePropertyAccessor.processlocalpropertyspring-beans-4.3.13.lelease-sources.jar! /org/springframework/beans/abstractnestablepropertyaccessor.javaprivate Void Processlocalperty getLocalPropertyHandler (tokens.actualName); if (pH == null ||! pH.iswitable ()) {ถ้า (pv.isoptional ()) {ถ้า (logger.isdebugenabled ()) {logger.debug ("ละเว้นค่าเสริมสำหรับคุณสมบัติ '" tokens.actualname + " } กลับ; } else {โยน createnotwablePropertyException (tokens.canonicalName); }} Object OldValue = null; ลอง {Object OriginalValue = pv.getValue (); ValuetOapply วัตถุ = OriginalValue; if (! boolean.false.equals (pv.conversionNeuseary)) {ถ้า (pv.isconverted ()) {valuetoapply = pv.getConvertedValue (); } else {if (isExtractOldValueForEditor () && ph.isreadable ()) {ลอง {oldValue = pH.getValue (); } catch (Exception Ex) {ถ้า (ตัวอย่างของ PrivilegedActionException) {ex = ((privilegedActionException) ex) .getException (); } if (logger.isdebugenabled ()) {logger.debug ("ไม่สามารถอ่านค่าก่อนหน้าของคุณสมบัติ '" + this.nestedpath + tokens.canonicalName + "" ", ex); }} valuetOapply = convertForProperty (tokens.canonicalName, oldValue, OriginalValue, pH.Totypedescriptor ()); } pv.getOriginalPropertyValue (). ConversionNeentAry = (ValuetOapply! = OriginalValue); } Ph.SetValue (this.wrappedObject, valuetoapply); } catch (typemismatchexception ex) {โยน ex; } catch (InvocationTargetException ex) {PropertyChangeEvent PropertyChangeEvent = ใหม่ PropertyChangeEvent (this.rootObject, this.nestedPath + tokens.canonicalName, oldValue, pv.getValue ()); if (ex.getTargetException () instanceof classcastexception) {โยน typemismatchexception ใหม่ (PropertyChangeEvent, ph.getPropertype (), ex.getTargetException ()); } else {สาเหตุที่โยนได้ = ex.getTargetException (); ถ้า (สาเหตุของอินสแตนซ์ของ undeclaredthrowableException) {// อาจเกิดขึ้นเช่นด้วยวิธีการที่สร้างขึ้น groovy สาเหตุ = cause.getCause (); } โยน methodInvocationException ใหม่ (PropertyChangeEvent, สาเหตุ); }} catch (Exception Ex) {PropertyChangeEvent PCE = ใหม่ PropertyChangeEvent (this.rootObject, this.nestedpath + tokens.canonicalName, oldValue, pv.getValue ()); โยน methodInvocationException ใหม่ (PCE, EX); -มันทำให้มันตั้งค่าโดยใช้คลาส org.springframework.beans.beanwrapperimpl $ beanpropertyhandler
beanwrapperimpl$beanpropertyhandler.setvaluespring-beans-4.3.13.release-sources.jar!/org/springframework/beans/beanwrapperimpl.java@override void setValue (วัตถุสุดท้าย generictypeawarepropertydescriptor? if (! modifier.ispublic (writemethod.getDeclaringClass (). getModifiers ()) &&! writemethod.iscascessible ()) {ถ้า (system.getSecurityManager ()! = null) writemethod.setAccessible (จริง); } else {writemethod.setAccessible (จริง); }} ค่าวัตถุสุดท้ายค่า = valuetOapply; if (system.getSecurityManager ()! = null) {ลอง {accessController.doprivileged (PrivilegedExceptionAction ใหม่ <Object> () {@Override วัตถุสาธารณะรัน () โยนข้อยกเว้น {writemethod.invoke (วัตถุค่า); } catch (privilegedActionException ex) {โยน ex.getException (); }} else {writemethod.invoke (getWrappedInstance (), ค่า); -ที่นี่เราใช้การสะท้อนกลับเพื่อค้นหาวิธี setxxx (เช่น setMaxactive) จากนั้นตั้งค่าใน
การกำหนดค่าแหล่งข้อมูลหลายข้อมูล
การกำหนดค่าข้างต้นไม่เป็นปัญหาสำหรับแหล่งข้อมูลเดียว สำหรับแหล่งข้อมูลหลายแหล่งการกำหนดค่ามีดังนี้
@ConfigurationPublic คลาส MasterDataSourceConfig {@Bean ("MasterDataSource") @configurationProperties (คำนำหน้า = "Spring.datasource.master") DataSource MasterDataSource () -โปรดทราบว่าคุณต้องเพิ่มการตั้งค่าเพิ่มเติมเพื่อฉีด configurationProperties ลงในพูล Tomcat JDBC
Spring: 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-active: 5 ## เมื่อเปิดใช้งานการกวาดแบบพูล
การกำหนดค่า Tomcat ดั้งเดิมจะต้องอยู่ภายใต้คำนำหน้าแหล่งข้อมูลและไม่สามารถมีผลภายใต้ spring.datasource.tomcat หรือ spring.datasource.master.tomcat