دعنا نلقي نظرة على رمز ربط الخاصية لتجمع SPRING BOOT TOMCAT JDBC. الرمز المحدد كما يلي:
الربيع: DataSource: النوع: org.apache.tomcat.jdbc.pool.datasource-class-class-name: org.postgresql.driver url: jdbc: postgresql: //192.168.99.100: 5432/postgres؟ تمكين JMX: الحجم الأولي الحقيقي: 1 الحد الأقصى النشط: 5 ## عند تمكين سترة البلياردو ، سيتم إغلاق اتصال الخمول الإضافي بحد أقصى: 5 ## عندما يكون الاتصال الخمول> min-idle ، سيبدأ البلياردوز في إغلاق الطرز: 1
باستخدام التكوين أعلاه ، وجدت أخيرًا أن الحجم الأولي ، النشط الحد الأقصى ، الحد الأقصى للتكوينات ، الوضعية وغيرها من التكوينات غير صالحة. لا يزال مصدر بيانات TOMCAT JDBC الذي تم إنشاؤه هو التكوين الافتراضي المستخدم.
التكوين الصحيح
الربيع: DataSource: النوع: org.apache.tomcat.jdbc.pool.datasource-class-class-name: org.postgresql.driver url: jdbc: postgresql: //192.168.99.100: 5432/postgres؟ JMX-endability: True Tomcat: ## مجموعة اتصال قاعدة بيانات واحدة ، ويجب كتابة تكوين خاصية Tomcat ليصبح حيز التنفيذ الحجم الأولي: 1 Max-Active: 5 ## عندما يتم تمكين كاسحة البلياردو ، سيتم إغلاق اتصال الخمول الإضافي.
لاحظ أن خصائص التكوين الخاصة بتجمع اتصال قاعدة بيانات Tomcat محدد يتم وضعها تحت Spring.Datasource.tomcat الخاصية بحيث يمكن أن تدخل مفعولها.
تحليل رمز المصدر
Spring-Boot-AutoconFigure-1.5.9.Release-Sources.jar! xadatasource.class}) iimport ({dataSourCeConfiguration.tomcat.class ، datasourceConfiguration.hikari.class ، datasourceConfiguration.dbcp.class ، datasourceConfiguration.dbcp2.class ، datasourceconfiguration.generic.clas. suppresswarnings ("الإهمال") محمية pooledDatasourCeConfiguration {}datasourceConfiguration.tomcat
Spring-Boot-AutoconFigure -1.5.9.Release-Sources.jar! */ conditionalonclass (org.apache.tomcat.jdbc.pool.datasource.class) conditionalonproperty (name = "spring.datasource.type" ، assvalue = "org.apache.tomcat.jdbc.pool.dataSource datasourCeConfiguration {bean @configurationProperties (prefix = "spring.datasource.tomcat") public org.apache.tomcat.jdbc.pool.datasource dataSource (datasourceProperties properties) CreateAtAsource (الخصائص ، org.apache.tomcat.jdbc.pool.datasource.class) ؛ databasedRiver databasedRiver = databasedRiver .fromjdbcurl (properties.determineurl ()) ؛ String ValidentQuery = databasedRiver.getValidationQuery () ؛ if (ValideDquery! = null) {datasource.settestonborrow (true) ؛ datasource.setValidationQuery (ValideDquery) ؛ } إرجاع مصدر البيانات ؛ }}يمكنك أن ترى أن DataSourceProperties هنا تحتوي فقط على تكوين سمات spring.datasource المباشرة ، مثل عنوان URL ، اسم المستخدم ، كلمة المرور ، اسم DriverClassName. Tomcat ليس له خصائص محددة.
CreatedAtaSource
محمية <T> t createataSource (خصائص DataSourceProperties ، الفئة <؟ تمديد dataSource> type) {return (t) properties.InitializedataSourceBuilder (). type (type) .build () ؛ }The org.apache.tomcat.jdbc.pool.datasource poolproperties التي تم إنشاؤها مباشرة هي أيضًا التكوين الافتراضي.
configurationProperties
يكمن السحر المحدد في CodeConfigurationProperties @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/ConfigurationPropertiesBindingPostProssor.javapRivate void postprocessbeinitializializialization (الكائن الفاصوليا ، stringproperties PROPERTIESCONFIGURITYFACTORY <Object> Factory = New PROPERTIESCONFIGURINTFACTORY <Object> (Target) ؛ مصنع. المصنع. // إذا لم يتم توفير خدمة تحويل صريحة ، فإننا نضيف واحدة بحيث (على الأقل) // يمكن ربط المصفوفات المفصولة بالفاصلة من المواد المكشوفة المصنع تلقائيًا. if (التعليقات التوضيحية! = null) {factory.setignoreinvalidfields (annotation.ignoreinvalidfields ()) ؛ مصنع. مصنع. مصنع. if (stringUtils.hasLength (enrotation.prefix ())) {factory.SetTargetName (enrotation.prefix ()) ؛ }} حاول {factory.bindPropertoestOtArget () ؛ } catch (استثناء ex) {String TargetClass = classUtils.getShortName (target.getClass ()) ؛ رمي BeancreationException (Beanname ، "لا يمكن ربط الخصائص بـ" + TargetClass + "(" + getAnnotationDetails (التعليق التوضيحي) + ") ،" ex) ؛ }} لاحظ أن التعليق التوضيحي هنا هو @ConfigurationProperties(prefix = "spring.datasource.tomcat") ، بادئة هو spring.datasource.tomcat spring.datasource.tomcat PropertiesConfigurationFactory target
propertiesConfigurationFactory.BindPropertOrgetSpring-Boot-1.5.9.Release-Sources.jar! لا تكون لاغية ") ؛ حاول {if (logger.istraceenabled ()) {logger.trace ("مصادر الخصائص:" + this.propertysources) ؛ } this.hasbeenBound = true ؛ DobindPropertiestOtarget () ؛ } catch (bindException ex) {if (this.exceptionIfinValid) {throw ex ؛ } propertiesConfigurationFactory.logger .error ("فشل في تحميل خصائص التحقق من الصحة." + "قد تكون خصائصك غير صالحة." ، ex) ؛ }}مندوب إلى DoBindPropertiestOtarget طريقة
PropertiesConfigurationFactory.DobindProperTiestOtArgetPrivate void dobindpropertiestOtOrget () يلقي BindException {RelaxedDatabinder Databinder = (this.targetName! = null؟ New RelaxedDatabinder (this.targetget ، this.targetName): new Relaftabinder (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.setIngReNSTERPROPERTIES (this.ignorEntedProperties) ؛ databinder.setignoreinvalidfields (this.ignoreinvalidfields) ؛ databinder.setignoreunknownfields (this.ignoreunknownfields) ؛ CustomIzeBinder (Databinder) ؛ Iterable <String> RelaxedTargetNames = getRelaxEdTargetNames () ؛ تعيين <String> names = getNames (RelaxedTargetNames) ؛ PropertyValues PropertyValues = GetPropertySourcesPropertyValues (أسماء ، أسماء الاسترخاء) ؛ 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)؟ new RelaxedNames (this.targetName): null) ؛ }فيما يلي أسماء استرخاء جديدة يمكنها تحديد متغيرات متغيرات متعددة
أسماء الاسترخاء
Spring-Boot-1.5.9.Release-Sources.jar! /org/springframework/boot/bind/relaxednames.javapRivate void تهيئة (اسم السلسلة ، تعيين <string> القيم) {if (dorme.contains (name)) {return ؛ } لـ (التباين التباين: variation.values ()) {for (معالجة المعالجة: manipulation.values ()) {string result = name ؛ النتيجة = التلاعب. apply (النتيجة) ؛ النتيجة = variation.apply (النتيجة) ؛ القيم. add (النتيجة) ؛ تهيئة (النتيجة ، القيم) ؛ }}} /*** الاختلافات الاسم. */ enum variation {none {Override public string (string value) {return value ؛ }} ، {Override public string تطبيق (قيمة السلسلة) {return value.isempty ()؟ القيمة: value.toLowerCase () ؛ }} ، acpercase {Override public string تطبيق (قيمة السلسلة) {return value.isempty ()؟ القيمة: value.toupperCase () ؛ }} ؛ سلسلة التجريد العامة تنطبق (قيمة السلسلة) ؛ }وهذا هو ، طريقة الكتابة للتكوين في org.springframework.boot.bind.relaxednames@6ef81f31 spring.datasource.tomcat ، spring_datasource_tomcat ، springdatasourcetomcat]] مدعوم.
GetPropertySourcesPropertyValuesPrivate PropertyValues GetPropertySourCespropertyValues (Set <String> أسماء ، Itabl <String> RelaftArgetNames) {propertynamepatternsmatcher تشمل = getProperTynamePatternsmatcher (الأسماء ، الاسترخاء ، إرجاع PropertySourcesPropertyValues (this.propertysources ، الأسماء ، تشمل ، this.resroving place) ؛ }ستقوم هذه الطريقة بسحب تكوين الخصائص تحت spring.datasource.tomact إلى كائن PropertyValues
RelaxedDatabinder.bind
spring-boot-1.5.9.Release-Sources.jar! /org/springframework/boot/bind/relaxedDatabinder.java's method intips the method form presk context-4.3.13.release-sources.jar! * <p> يمكن لهذه المكالمة إنشاء أخطاء في الحقل ، أو تمثل أخطاء الربط الأساسي مثل الحقل المطلوب (الرمز "مطلوب") ، أو اكتب عدم تطابق * بين خاصية القيمة والفاصوليا (رمز "TypeMismatch"). * <p> لاحظ أن PropertyValues المعطى يجب أن تكون مثيلًا رائعًا: * للكفاءة ، سيتم تعديله ليحتوي فقط على الحقول المسموح بها إذا كان * ينفذ واجهة قابلة للتبديل. آخر ، سيتم إنشاء نسخة داخلية قابلة للتغيير * لهذا الغرض. تمرير نسخة من PropertyValues* إذا كنت تريد أن تظل مثيلك الأصلي غير معدل في أي حال. * param pvs property stable to bind * see #dobind (org.springframework.beans.mutablePropertyValues) */ public void bind (propertyValues pvs) {mutablePropertyValues mpvs = (pvs extirentof mutablePropertyValues)؟ (قابلية matablePropertyValues) PVS: New MutablePropertyValues (PVS) ؛ Dobind (MPVS) ؛ } /** * التنفيذ الفعلي لعملية الربط ، والعمل مع مثيل * تم تمريره في intablepropertyvalues. * param mpvs قيم الخصائص للربط ، * كمثيل قابلة للتفتيش على سبيل المثال * seee #checkallydfields * seee #CheckRequiredFields * seee #applypropertyvalues */ proted void dobind (ageablepropertyvalues mpvs) CheckRequiredFields (MPVS) ؛ ApplyPropertyValues (MPVS) ؛ } /*** قم بتطبيق قيم الخصائص المعطاة على الكائن الهدف. * <p> ينطبق التنفيذ الافتراضي على جميع القيم الخاصة بالممتلكات * كقيم خاصية الفول. بشكل افتراضي ، سيتم تجاهل حقول غير معروفة. * param mpvs قيم الخصائص المراد ربطها (يمكن تعديلها) * see #gettarget * seee #getPropertyAccessor * seee #isignoreunknownfields * seee #getBindErrorProrPrororprocessor * @inbideRrorProcessor #processPropertyAccection */ protectivePropertyVs. // ربط المعلمات طلب على الكائن الهدف. getPropertyAccessor (). } catch (propertyBatchUpDateException ex) {// استخدم معالج خطأ ربط لإنشاء fielderrors. لـ (propertyAccessException PAE: ex.getPropertyAccessExceptions ()) {getBindingErrorProcessor (). ProcessPropertyAccessException (PAE ، getInternalBindingResult ()) ؛ }}} /*** إرجاع propertyAccessor الأساسي من هذا الموثق. */ محمية configablePropertyAccessor getPropertyAccessor () {return getInternalBindingResult (). getPropertyAccessor () ؛ }أخيرًا ، تم تعيينه بواسطة GetPropertyAccessor (). هذا propertyAccessor هو org.springframework.boot.bind.relaxedDatabinder $ RelaxedBeanWrapper: compling object [org.apache.tomcat.jdbc.pool.dataSource@6a84bc2a] ، وهو org.apache.tomcat.jdbc.pool.
AbstractPropertyAccessor.SetPropertyvaluesspring-beans-4.3.13.release-sources.jar !/org/springframework/beans/abstractpropertyaccessor.java@override public setpropertyvalues (propertyvalues pvs ، boolean agnoreannown agnawinnvalid) قائمة <PrepertyAccessException> propertyAccessExceptions = null ؛ قائمة <PrepertyValue> propertyValues = (pvs extreamof ableablepropertyvalues؟ ((ageablepropertyvalues) pvs) .getPropertyValuelist (): Arrays.Aslist (pvS.GetPropertyValues ())) ؛ لـ (propertyValue PV: PropertyValues) {try {// قد يرمي هذه الطريقة أي beansexception ، والتي لن يتم اكتشافها // هنا ، إذا كان هناك فشل حاسم مثل عدم وجود حقل مطابقة. // يمكننا محاولة التعامل فقط مع استثناءات أقل خطورة. setPropertyValue (PV) ؛ } catch (notwritablePropertyException ex) {if (! destunknown) {throw ex ؛ } // خلاف ذلك ، فقط تجاهله ومتابعة ...} catch (nullValueIntedPathexception ex) {if (! reghoreinvalid) {throw ex ؛ } // خلاف ذلك ، فقط تجاهله ومتابعة ...} catch (propertyAccessException ex) {if (propertyAccessExceptions == null) {propertyAccessExceptions = new LinkedList <PropertAccessexception> () ؛ } propertyAccessExceptions.add (ex) ؛ }} // إذا واجهنا استثناءات فردية ، رمي الاستثناء المركب. if (propertyAccessExceptions! = null) {propertyAccessException [] paeArray = propertyAccessExceptions.toarray (propertyAccessException [propertyAccessExceptions.size ()]) ؛ رمي PropertyBatchUpDateException (paerray) ؛ }} Override public void setPropertyValue (propertyValue pv) يلقي beansexception {propertyTokenHolder Tokens = (propertyTokenHolder) pv.resolvedtokens ؛ if (tokens == null) {string propertyName = pv.getName () ؛ AbstractNestablePropertyAccessor nestedpa ؛ حاول {nestedpa = getPropertyAccessorForPropertyPath (propertyName) ؛ } catch (notreadablePropertyException ex) {رمي new nottablePropertyException (getRootClass () ، this.nestedPath + propertyName ، "خاصية متداخلة في المسار" + propertyName + "" "غير موجود" ، ex) ؛ } Tokens = getPropertynametokens (getFinalPath (nestedpa ، propertyName)) ؛ if (nestedpa == this) {pv.getoriginalPropertyValue (). resolvedTokens = الرموز ؛ } nestedpa.setPropertyValue (الرموز ، pv) ؛ } آخر {setPropertyValue (الرموز ، pv) ؛ }}هنا nestedpa.setPropertyValue (الرموز ، PV) ؛ الإعداد الحقيقي لـ Spring.Datasource.Tomcat قيمة خاصية هو org.springframework.boot.bind.relaxedDatabinder $ RelaftBeanWrapper: compling object [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a]
abstrumrtnestableProperTyProperTyAccessor.ProcessLocalPropertySpring-Beans-44.3.3.3.13.release-sources.jar! getLocalPropertyHandler (Tokens.actualName) ؛ if (ph == null ||! ph.iswritable ()) {if (pv.isoptional ()) {if (logger.isdebugenabled ()) {logger.deBug ("تجاهل القيمة الاختيارية للخاصية" + tokens.actualname + "' - الخاصية لم يتم العثور عليها على فئة الفول [getRootClass (). } يعود؛ } آخر {throw CreateNotWratePtertyException (Tokens.CanonicalName) ؛ }} object oldvalue = null ؛ حاول {Object OriginalValue = pv.getValue () ؛ كائن ValuetoApply = OriginalValue ؛ if (! boolean.false.equals (pv.conversionNecessary)) {if (pv.isconverted ()) {valuetoapply = pv.getConvertedValue () ؛ } آخر {if (isExtractOldValueForeditor () && ph.isReadable ()) {try {oldvalue = ph.getValue () ؛ } catch (استثناء ex) {if (ex extuteof terilegedgenceException) {ex = ((terilegedActionException) ex) .getException () ؛ } if (logger.isdebugenabled ()) {logger.debug ("لا يمكن قراءة القيمة السابقة للخاصية '" + this.nestedPath + Tokens.CanonicalName + "' '' ، ex) ؛ }} valuetoapply = convertForProperty (Tokens.CanonicalName ، Oldvalue ، OriginalValue ، ph.totypedescriptor ()) ؛ } pv.getoriginalPropertyValue (). conversionNecessary = (ValuetoApply! = OriginalValue) ؛ } ph.setValue (this.wrappedObject ، 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 () مثيل classcastException) {رمي typeMismatchException جديد (propertyChangeEvent ، ph.getPropertyType () ، ex.getTargetException ()) ؛ } else {throwable cause = ex.getTargetException () ؛ إذا كان (مثيل السبب من غير المعلن) {// قد يحدث على سبيل المثال مع الأساليب التي تم إنشاؤها بشكل رائع = cause.getCause () ؛ } رمي methodInvocationException (propertyChangeEvent ، السبب) ؛ }} catch (استثناء ex) {propertyChangeEvent pce = new propertyChangeEvent (this.rootobject ، this.nestedPath + Tokens.CanonicalName ، oldvalue ، pv.getValue ()) ؛ رمي methodInvocationException الجديد (PCE ، ex) ؛ }}إنه يجعله يستخدم باستخدام فئة org.springframework.beans.beanwrapperimpl $ beanpropertyhandler
BeanWrapperImpluteBeAnpropertyHandler.SetValuespring-beans-4.3.13.release-sources.jar! generictypeawarepropertydescriptor؟ if (! modifier.ispublic (writeMethod.getDeclaringClass (). getModifiers ()) &&! writeMethod.isAccessible ()) {if (system.getSecurityManager ()! = null) {accessController.doprivileged (new tarileged <Object> العودة null ؛ } آخر {writemethod.setAccessible (true) ؛ }} قيمة الكائن النهائي = valuetoapply ؛ if (system.getSecurityManager ()! = null) {try {AccessController.doprivileged (new TerilegedExceptionAction <Object> () {Override Public Object Run () rems {contractod.invoke (كائن ، قيمة) } catch (terilegedActionException ex) {throw ex.getException () ؛ }} آخر {writemethod.invoke (getWrappedInstance () ، value) ؛ }}}}هنا نستخدم الانعكاس للعثور على طريقة setxxx (مثل setMaxactive) ، ثم ضبطها في
تكوين مصدر البيانات المتعددة
التكوين أعلاه ليس مشكلة لمصدر بيانات واحد. بالنسبة لمصادر البيانات المتعددة ، فإن التكوين كما يلي
ConfigurationPublic Class MasterDataSourCeConfig {bean ("MasterDataSource") configurationProperties (prefix = "spring.datasource.master") public dataSource masterDataSource () {return dataSourceBuilder.create (). }}لاحظ أنك تحتاج إلى إضافة إعدادات إضافية لحقن ConfigurationProperties في تجمع Tomcat JDBC
الربيع: DataSource: Master: Type: org.apache.tomcat.jdbc.pool.datasource class-class-name: org.postgresql.driver url: jdbc: postgresql: //192.168.99.100: 5432/postgres؟ JMX-endability: True# tomcat: ## بالنسبة لمصادر بيانات متعددة ، نحتاج إلى إزالة tomcat هنا ووضعها تحت بادئة مصدر البيانات الأولي: 1 Max-Active: 5 ## عندما يتم تمكين البلياردو ، سيتم إغلاق اتصال الخمول الإضافي.
يجب وضع تكوين tomcat الأصلي تحت بادئة مصدر البيانات ، ولا يمكن أن يكون له ساري المفعول تحت spring.datasource.tomcat أو spring.datasource.master.tomcat.