Spring Boot Tomcat JDBC 풀의 속성 바인딩 코드를 살펴 보겠습니다. 특정 코드는 다음과 같습니다.
Spring : DataSource : type : org.apache.tomcat.jdbc.pool.datasource 드라이버 클래스-이름 : org.postgresql.driver url : jdbc : jdbc : postgresql : //192.168.99.100 : 5432/postgres? connecttimeout = 6000 & postgres postgres : 6000 username : 6000 jmx-enabled : true 초기 크기 : 1 Max-Active : 5 ## 풀 스웨터가 활성화되면 추가 공전 연결이 닫히게됩니다 : 5 ## 유휴 연결> Min-idle이면 Poolsweeper가 Min-Idle을 닫기 시작합니다 : 1
위의 구성을 사용하여 마침내 초기 크기, Max-Active, Max-Idle, Min-idle 및 기타 구성이 유효하지 않다는 것을 알았습니다. 생성 된 Tomcat JDBC DataSource는 여전히 기본 구성입니다.
올바른 구성
Spring : DataSource : type : org.apache.tomcat.jdbc.pool.datasource 드라이버 클래스-이름 : org.postgresql.driver url : jdbc : jdbc : postgresql : //192.168.99.100 : 5432/postgres? connecttimeout = 6000 & postgres postgres : 6000 username : 6000 jmx-enabled : true tomcat : ## 단일 데이터베이스 연결 풀 및 Tomcat 속성 구성을 초기 크기 : 1 max-active : 5 ## 풀 스위퍼가 활성화되면 추가 공전 연결이 닫히게됩니다.
특정 TomCat 데이터베이스 연결 풀의 구성 속성은 Spring.datasource.tomcat 속성 아래에 배치되어 적용 할 수 있습니다.
소스 코드 분석
Spring-boot-autoconfigure-1.5.9. release-sources.jar !/org/springframework/boot/autoconfigure/jdbc/datasourceautoconfiguration.java@configuration @conditional (PooleddatasourceCondition.class) @conditionalonmissingbean xadatasource.class}) @import ({dataSourceConfiguration.tomcat.class, dataSourceConfiguration.hikari.class, dataSourceConfiguration.dbcp.class, dataSourceConfiguration.dbcp2.class, dataSourceConfiguration.generic.generic.generic.generic.generic. @suppresswarnings ( "감가 상각") 보호 된 정적 클래스 풀 레드 다타 이어 컨퍼레이션 {}DataSourceConfiguration.tomcat
Spring-Boot-autoconfigure-1.5.9. release-sources.jar! /org/springframework/boot/autoconfigure/jdbc/datasourceconfiguration.java/*** Tomcat Pool DataSource 구성. */ @ConditionalOnclass (org.apache.tomcat.jdbc.pool.datasource.class) @ConditionalOnProperty (name = "spring.datasource.type", adgevalue = "org.apache.tomcat.jdbc.pool.datasource" DataSourceConfiguration {@bean @configurationProperties (prefix = "spring.datasource.tomcat") public org.apache.tomcat.jdbc.pool.datasource dataSource (dataSourceProperTies 속성) {org.apache.tomcat.jdbc.pool.pool.poolc.pool. createAtasource (속성, org.apache.tomcat.jdbc.pool.datasource.class); DataBasedRiver DataBasedRiver = DatabasedRiver .fromjdbcurl (properties.determineurl ()); String validationQuery = databasedRiver.getValidationQuery (); if (validationQuery! = null) {dataSource.setTestOnbrong (true); DataSource.setValidationQuery (ValidationQuery); } return dataSource; }}여기의 DataSourceProperties는 URL, 사용자 이름, 암호, DriverClassName과 같은 spring.datasource 직접 속성의 구성 만 있음을 알 수 있습니다. Tomcat에는 특정 속성이 없습니다.
생성물
Protected <T> T CreateAtAsource (DataSourceProperties 속성, 클래스 <? extends dataSource> type) {return (t) properties.initializedataSourceBuilder (). type (type) .build (); }org.apache.tomcat.jdbc.pool.datasource poolproperties는 직접 생성 된 기본 구성입니다.
configurationProperties
특정 마법은 코드 @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 (물체 Bean, String Beanname, 구성 요법 대상) {object = bean; PropertiesConfigurationFactory <BORFERTORY = New PropertiesConfigurationFactory <BORVER> (대상); Factory.SetPropertySources (this.propertySources); Factory.setValidator (결정 Validator (Bean)); // 명시적인 변환 서비스가 제공되지 않으면 (적어도) // 컨버터블의 컨버터링 배열이 자동으로 팩토리로 바인딩되도록 추가하십시오. if (annotation! = null) {factory.setignoreinvalidfields (Annotation.ignoreInvalidFields ()); factory.setignoreunkNownfields (Annotation.ignoreUlkNownFields ()); factory.setexceptionifinvalid (Annotation.exceptionifinValid ()); factory.setignorEnestedProperties (Annotation.ignorEnestedProperties ()); if (stringUtils.haslength (Annotation.prefix ())) {factory.setTargetName (Annotation.prefix ()); }} try {factory.bindProperTiestOtArget (); } catch (예외 예) {문자열 targetclass = classutils.getShortName (target.getClass ()); 새로운 BeanCreationException (Beanname, "" + targetclass + "에 속성을 바인딩 할 수 없습니다 (" + getAnnotationDetails (Annotation) + ")", ex); }} 여기서 주석은 @ConfigurationProperties(prefix = "spring.datasource.tomcat") 이며, 접두사는 spring.datasource.tomcat PropertiesConfigurationFactory targetname입니다.
PropertiesConfigurationFactory.BindProperTiestOtAtAgetSpring-Boot-1.5.9. Release-Sources.jar! /org/springframework/boot/bind/propertiesconfigurationFactory.javapublic void bindProperTiestOtAgget (in Assert.state) (this.propersources whourcess! " null "); try {if (logger.istraceenabled ()) {logger.trace ( "속성 소스 :" + this.propertysources); } this.hasbeenbound = true; doBindProperTiestOtArget (); } catch (bindexception ex) {if (this.exceptionifinValid) {throw ex; } propertiesconfigurationFactory.logger .Error ( "속성 유효성 검사 bean을로드 실패." + "속성이 유효하지 않을 수 있습니다.", ex); }}DoBindPropertiestOtArget 메소드를 대표합니다
propertiesconfigurationFactory.dobindProperTiestOtArgetPrivate void doBindProperTiestOtArget () rows bindException {allestDatabinder Databinder = (this.targetName! = null? new allingdatabinder (this.target, this.targetname) : 새로운 편안한 databinder (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.SetIngEnestEdProperties (this.IngorEnestEdProperties); Databinder.SetIngoreInvalidFields (this.ignoreInvalidFields); Databinder.SetIngOrUnkNownFields (this.ignoreUlkNownFields); CustomizeBinder (데이터베이너); 반복 가능한 <string> allighedTargetNames = getRelaxedTargetNames (); set <string> names = getNames (relainedTargetNames); PropertyValues propertyValues = getPropertySourcesPropertyValues (이름, allingtargetNames); Databinder.bind (PropertyValues); if (this.validator! = null) {databinder.validate (); } checkforBindingErrors (데이터베이너); }여기에서 allingdatabinder.bind 메소드를 사용하십시오
getRelaxedTargetNamesPrivate 반복 가능한 <string> getRelaxedTargetNames () {return (this.target! = null && stringUtils.haslength (this.targetName)? new allingNames (this.targetName); }다음은 여러 변수의 변형을 식별 할 수있는 새로운 완화 이름입니다.
편안한 이름
spring-boot-1.5.9. release-sources.jar! /org/springframework/boot/bind/relaxednames.javaprivate void initialize (문자열 이름, <string> values) {if (vales.contains (name)) {return; } for (variation variation : variation.values ()) {for (조작 조작 : Manipulation.values ()) {String result = name; 결과 = 조작. Apply (결과); 결과 = variation.Apply (결과); values.add (결과); 초기화 (결과, 값); }}} /*** 이름 변형. */ enum variation {none {@override public string apply (문자열 값) {return value; }}, 소문자 {@override public string apply (문자열 값) {return value.isempty ()? 값 : value.tolowercase (); }}, 대문자 {@override public string apply (문자열 값) {return value.isempty ()? 값 : value.toupperCase (); }}; 공개 초록 문자열 적용 (문자열 값); }즉, org.springframework.bind.bind.bind.relaxednames@6ef81f31에서 구성 메소드 작성 방법 [name = spring.datasource.tomcat, value = [spring.datasource.tomcat, spring_datasource_tomcat, springdatousourcetomcat, springdatomcat, springdatomcat, spring.datasource.tomcat, spring_datasource_tomcat, springdatasourcetomcat]]가 지원됩니다.
getPropertySourcesProperValuesPrivate PropertyValues getPropertySourcesPropertyValues (set <string> 이름, Iterable <string> relazedTargetNames) {propertynamepatternsmatcher 포함 = getProperManepatternsMatcher (이름, relastedTargetNames); 새로운 PropertySourcesPropertyValues를 반환합니다 (this.propertySources, 이름, 포함, this.resolveplopholders); }이 방법은 spring.datasource.tomact에서 속성 구성을 PropertyValues 객체로 가져옵니다.
편안한 Databinder.bind
spring-boot-1.5.9.release-sources.jar! /org/springframework/boot/bind/relaxeddatabinder.java의 바인드 메소드는 부모 클래스의 메소드 Spring-context-4.3.13.release-sources.jar! /org/spramwork/validation/databinder.java/**를 호출합니다. * <p>이 호출은 필드 오류를 만들 수 있으며, 필수 필드 (코드 "필수")와 같은 기본 바인딩 * 오류를 나타내거나 값과 Bean 속성 (코드 "typesmismatch") 사이의 불일치 *를 입력 할 수 있습니다. * <p> 주어진 속성 값은 끔찍한 인스턴스 여야합니다. * 효율성을 위해서는 MexpropertyValues 인터페이스를 구현하는 경우 허용 필드 만 포함하도록 수정됩니다. 그렇지 않으면,이 목적을 위해 내부 변동성 * 사본이 생성됩니다. 원래 인스턴스가 수정되지 않은 상태를 유지하려면 PropertyValues 사본을 전달하십시오. * @param pvs 속성 값 bind * @see #dobind (org.springframework.beans.mutablePropertyValues) */ public void bind (propertyvalues pvs) {mutablePropertyValues mpvs = (pvs instanceof mutablepropertyvalues)? (MutablePropertyValues) PVS : 새로운 MutablePropertyValues (PVS); Dobind (MPVS); } /** * 통과 된 MutablePropertyValues 인스턴스와 함께 작업하는 바인딩 프로세스의 실제 구현. * @param mpvs indation 값을 바인딩 할 속성 값 * @see #checkallowedfields * @see #checkrequiredfields * @see #applypropertyvalues */ propected void dobind (mutablepropertyvalues mpvs) {mpvs); CheckRequiredFields (MPVS); ApplyPropertyValues (MPVS); } /*** 주어진 속성 값을 대상 객체에 적용합니다. * <p> 기본 구현은 제공된 모든 속성 * 값을 Bean 속성 값으로 적용합니다. 기본적으로 알 수없는 필드는 무시됩니다. * @Param MPVS 바운드 값 (수정 가능) * @see #getTarget * @see #getProperTyAccessor * @see #IsignoreUnkNownFields * @see #getBindingErrorProcessor * @see bindingErrorProcessor #processProperCessecception */ Protecected ApplopeRoperTureTureceTurecesseception mpvs) {try {// 요청 매개 변수를 대상 객체에 바인딩합니다. getPropertyAccessor (). setPropertyValues (mpvs, isignoreunknownfields (), isignoreinvalidfields ()); } catch (PropertyBatchUpDateException ex) {// 바인드 오류 프로세서를 사용하여 Fielderror를 생성합니다. for (propertyAccessException pae : ex.getPropertyAccessExceptions ()) {getBindingErrorProcessor (). ProcessPropertyAccessException (PAE, GetInternalBindingResult ()); }}} /***이 바인더의 BindingResult의 기본 속성 액세서를 반환합니다. */ 보호 된 configurablePropertyAccessor getPropertyAccessor () {return getInternalBindingResult (). getPropertyAccessor (); }마지막으로 getPropertyAccessor ()에 의해 설정됩니다. 이 PropertyAccessor는 org.springframework.boot.bind.relaxeddatabinder $ allelybeanWrapper : 포장 객체 [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a], 이는 랩핑 된 org.apache.tomcat.jdbc.pool.datasouce입니다.
AbstractPropertyAccessor.setPropertyValuesspring-beans-4.3.13. release-sources.jar !/org/springframework/beans/abtractpropertyaccessor.java@override public void setpropertyvalues (property setpropervalues, boolean thown warlid) List <posperationAccessException> PropertyAccessExceptions = null; list <propertyvalue> propertyValues = (pvs mexpropertyvalues의 pvs 인스턴스? for (propertyValue pv : propertyValues) {try {//이 메소드는 ainsexception을 던질 수 있습니다. // 우리는 덜 심각한 예외 만 다루려고 시도 할 수 있습니다. SetPropertyValue (PV); } catch (notwariteProperneException ex) {if (! ingoreUlkNown) {throw ex; } // 그렇지 않으면, 그냥 무시하고 계속 ...} catch (nullValueInnestedPathException ex) {if (! ingoreInvalid) {throw ex; } // 그렇지 않으면, 그냥 무시하고 계속 ...} catch (propertyAccessException ex) {if (propertyAccessExceptions == null) {propertyAccessExceptions = new LinkedList <PropertyAccessException> (); } propertyAccessExceptions.add (ex); }} // 개별 예외가 발생하면 복합 예외를 던지십시오. if (propertyAccessExceptions! = null) {propertyAccessException [] paearray = propertyAccessExceptions.ToArray (new PropertyAccessException [propertyAccessExceptions.size ()]); 새로운 PropertybatchUpDateException (Paearray)을 던지십시오. }} @override public void setpropertyvalue (propertyValue pv)는 beansexception {propertyTokenherder tokens = (propertyTokenher) pv.ResolvedTokens; if (tokens == null) {String propertyname = pv.getName (); AbstractNestablePropertyAccessor Nestedpa; try {nestedpa = getPropertyAccessorForPropertyPath (PropertyName); } catch (notreadableProperneException ex) {wrach new notwritableProperneException (getRootClass (), this.nestedPath + PropertyName, "경로의 중첩 속성 '" + PropertyName + "'존재하지 않는다", Ex); } tokens = getProperTynametOkens (getFinalPath (NestEdpa, PropertyName)); if (nestedpa == this) {pv.getoriginalPropertyValue (). ResolvedTokens = 토큰; } NestEdpa.setPropertyValue (Tokens, PV); } else {setPropertyValue (Tokens, PV); }}여기서 Nestedpa.setPropertyValue (Tokens, PV); spring.datasource.tomcat 속성 값의 실제 설정은 org.springframework.bind.bind.bind.relaxeddatabinder $ allelybeanwapper : rapping object [org.apache.tomcat.jdbc.pool.datasource@6a84bc2a] 최종적으로 chacknestabletyccescessor.propscecescecescecescescesceccescesce
AbstractNestablePropertyAccessor.processlocalPropertyspring-beans-4.3.13. Release-Sources.jar! /org/springframework/beans/abtractnestablepropertyaccessor.javaprivate void ProcessLocalProperty (PropertyToken Holder Tokens) {PropertyValue Pold, PropertyValue Pold, getLocalPropertyHandler (Tokens.actualName); if (ph == null ||! ph.iswritable ()) {if (pv.isoptional ()) {if (logger.isdebugenabled ()) {logger.debug ( "속성의 선택적 값 무시 '" + Tokens.ActualName + "' - Bean 클래스에서 찾을 수없는 속성 [" + getRootClass ())); } 반품; } else {strow createNotWritableProperneException (Tokens.canonicalName); }} 개체 OldValue = null; {Object OriginalValue = 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 (예외) {if (ex instanceof privilegedActionException) {ex = ((privilegedActionException) ex) .getexception (); } if (logger.isdebugenabled ()) {logger.debug ( "Property의 이전 값을 읽을 수 없습니다 ' + this.nestedPath + Tokens.canonicalName +"', Ex); }} valuetoApply = convertForProperty (tokens.canonicalName, OldValue, OriginalValue, ph.totypedescriptor ()); } pv.getoriginalPropertyValue (). conferionnecessary = (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 인스턴스) {throw new typemismatchexception (propertychangeevent, ph.getPropertytype (), ex.getTargetexception ()); } else {throwable 원인 = 예 getTargetexception (); if (비정상적으로 발생하지 않은 방법) {// groovy 생성 메소드가 발생할 수 있습니다. 원인 = 원인 .getCause (); } 새 MethodInVocationException을 던지십시오 (PropertyChangeEvent, Cause); }} catch (예외 예) {propertychangeevent pce = new 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 public void setValue (최종 객체, 객체 valuetoApply) 예외 {최종 방법 writeMethod = genericpeawarepropertydescriptor? (genericpeawarepropertydescriptor). if (! modifier.ispublic (writeMethod.getDeclaringClass (). getModifiers ()) &&! riteMethod.isaccessible ())) {if (system.getSecurityManager ()! = null) {accessController.doprivileged (new PrivilegedAction <object> () {@override run () {) { writemethod.setAccessible (true); } else {writeMethod.setAccessible (true); }} 최종 객체 값 = valuetoApply; if (system.getSecurityManager ()! = null) {try {accessController.doprivileged (new privilegeDexceptionAction <botort> () {@Override public Object Run () 예외 {writemethod.invoke (Object, value); return null;}}, acc); } catch (privilegedActionException ex) {throw ex.getexception (); }} else {writemethod.invoke (getwrappedInstance (), value); }}}}여기서 반사를 사용하여 setxxx 메소드 (예 : setmaxactive)를 찾은 다음 설정합니다.
멀티 데이터 소스 구성
위 구성은 단일 데이터 소스에 대해 문제가되지 않습니다. 여러 데이터 소스의 경우 구성은 다음과 같습니다
@ConfigurationPublic Class MasterDatasourceConfig {@Bean ( "Mas }}configurationProperties를 Tomcat JDBC Pool에 주입하려면 추가 설정을 추가해야합니다.
스프링 : DataSource : mas jmx-enabled : true# tomcat : ## 여러 데이터 소스의 경우 여기에 Tomcat을 제거하고 데이터 소스의 접두사 아래에 놓아야합니다. 1 Max-Active : 5 ## 풀 스위퍼가 활성화되면 최대 연결이 닫힙니다.
원래 Tomcat 구성은 데이터 소스 접두사 아래에 배치해야하며 Spring.datasource.tomcat 또는 Spring.datasource.master.tomcat에서는 적용 할 수 없습니다.