springソースコード学習シリーズ3.2.1-commandオブジェクトのバインディング

11904 ワード

もっと読む
MultiAction Controller〓〓invoke NamedMethod法では、requestパラメータ値をcommandオブジェクトに設定する-別の形式のモデルドライバ
springmvc設計の重要な原則は開閉の原則です.
変更または処理の流れをオフにして、拡張に開放します.
しかし、カスタムコントローラに対してMultiAction Controllerを継承し、いくつかの方法をカバーし、springmvcの一部機能を変更しました.
Bind(HttpServletRequest request、Object command)をカバーするように、バインディングプロセスは完全にユーザーのプログラミング能力によって決定されます.
springバージョン3.2.2
バインディングエントリインターフェース:
Servlet Request Data Binder
日付フォーマットの変換はどこですか?
binderは属性エディタを登録できます.文字列フォーマットをData形式に変更します.
@InitBinder
    public void initBinder(WebDataBinder binder) {
    	DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        CustomDateEditor dateEditor = new CustomDateEditor(df, true); 
        binder.registerCustomEditor(Date.class, dateEditor);
    }
パラメータチェックはいつですか?
// If last parameter isn't of HttpSession type, it's a command.  
            if (paramTypes.length >= 3 &&  
                    !paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {  
                Object command = newCommandObject(paramTypes[paramTypes.length - 1]);  
                params.add(command);  
                bind(request, command);  
            }
MultiAction Controller〓〓〓bind
protected void bind(HttpServletRequest request, Object command) throws Exception {
		logger.debug("Binding request parameters onto MultiActionController command");
// 1    ServletRequestDataBinder 
		ServletRequestDataBinder binder = createBinder(request, command);
// 2   request   command
		binder.bind(request);
		if (this.validators != null) {
			for (Validator validator : this.validators) {
				if (validator.supports(command.getClass())) {
					ValidationUtils.invokeValidator(validator, command, binder.getBindingResult());
				}
			}
		}
		binder.closeNoCatch();
	}
カスタムvalidators、検証パラメータ、必ず検証など
MultiAction Controller〓〓createBinder
protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object command) throws Exception {
// 1.1    ServletRequestDataBinder
		ServletRequestDataBinder binder = new ServletRequestDataBinder(command, getCommandName(command));
// 1.2    binder-     -webBindingInitializer-springmvc   
		initBinder(request, binder);
		return binder;
	}
MultiAction Controllerにおける方法については、bindやinitBinderなど、カスタマイズされたcontrollerのサブクラスによってカバーされ、自分のバインディングロジックを定義することができます.しかし、一般的にはそうしません.このようにプロジェクトはspringmvcと結合性が強化されました.
@Override
    protected void bind(HttpServletRequest request, Object command) throws Exception {
    	System.out.println("       bind");
    }
    
    @Override
    protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object command) throws Exception {
    	return null;
    }
    
    @Override
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
    	binder.setAutoGrowNestedPaths(true);  
        binder.setAutoGrowCollectionLimit(1024);  
    	System.out.println("hi, i am initBinder");
    }
Servlet Request Data Binder継承システムは、
ServletRequest Data Binder extends WebData Binder extends Data Binder
ServletRequest Data Binderのオブジェクトを作成する場合は、設定値のcommandオブジェクトでbinderを初期化します.もうすぐcommandをData Binderにパッケージングします.
======================================================================職責分割線
実際にcommandオブジェクトを結びつける作業はData Binderインターフェースで行い、ユーザー(開発者)は設定値requestと設定値commandをData Binderに送るだけでいいです.
1.request->MutalbPropertyValues(data Binder)
2.MutalbPropertyValues->command(beanWrapper)
Servlet Request Data Binder胫bind
public void bind(ServletRequest request) {
// 2.1   MutablePropertyValues: request    ProperValues  
//   request.getParameterNames()     map,    MutablePropertyValues
		MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
		MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
		if (multipartRequest != null) {
			bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
		}
		addBindValues(mpvs, request);
// 2.2       ,   mpvs   command  -      ServletRequestDataBinder   
		doBind(mpvs);
	}
WebData Binder芫doBind
@Override
	protected void doBind(MutablePropertyValues mpvs) {
// 2.2.1        ( !    _  )    ,    -WebDataBinder     
//   (    )      controller ,  createBinder  ,         
		checkFieldDefaults(mpvs);
		checkFieldMarkers(mpvs);
// 2.2.2       ,    command  
		super.doBind(mpvs);
	}
2.2.1特殊属性名を処理し、プレフィックスを削除する.このロジックが必要でないなら、createBinderをカバーして、自分のdata Binder extexds ServletRequest Data Binderをカスタマイズします.
Data Binder萉doBind

/**
	 * Actual implementation of the binding process, working with the
	 * passed-in MutablePropertyValues instance.
	 * @param mpvs the property values to bind,
	 * as MutablePropertyValues instance
	 * @see #checkAllowedFields
	 * @see #checkRequiredFields
	 * @see #applyPropertyValues
	 */
protected void doBind(MutablePropertyValues mpvs) {
// 2.2.2.1                -DataBinder     
		checkAllowedFields(mpvs);
		checkRequiredFields(mpvs);
// 2.2.2.2     
		applyPropertyValues(mpvs);
	}
Data Binder胪doBindはmpvsをcommandオブジェクトに結びつけるところであり、これはrequestパラメータをMutble PropertyValuesにパッケージする意味かもしれない.Servlet Request Data Binderはrequestをmpvsにパッケージ化するだけでなく、他の形式の要求パラメータもあります.Data Binderを継承してから対応するパッケージを作ります.
テストのエラーまたは他の情報の処理に対して、springmvcは、DataBinderの属性bindingResoultに配置され、BenPropertyBindingResoultのようなオブジェクトです.
2.2.1と2.2.1を結合する前にチェックアウトした場合、なぜ彼女たちのチェックを一緒にしないですか?独立して見るべきです.それぞれの種類の関心や役割が違っています.彼女たちはそれぞれの方法の丈夫さを維持しなければなりません.
Data Binder萼appyPropertyValues
protected void applyPropertyValues(MutablePropertyValues mpvs) {
		try {
// 2.2.2.2.1 
			// Bind request parameters onto target object.
			getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
		}
		catch (PropertyBatchUpdateException ex) {
			// Use bind error processor to create FieldErrors.
			for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
				getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
			}
		}
	}
get BindingErrocessor().processPropertyAccess Exception(pae,get Internal BindingResoult();異常処理メカニズムのために、異常をbindingReltに設定し、バインディング終了時にServletRequest Data Binderを呼び出します.
request->mpvs
======================================================================職責分割線
DataBinderは最後にやはりバトンをBenWrapperに渡しました.
mpvs->command
AbstractPropertyAccess or啝set PropertyValues

public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
			throws BeansException {

		List propertyAccessExceptions = null;
		List propertyValues = (pvs instanceof MutablePropertyValues ?
				((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
		for (PropertyValue pv : propertyValues) {
			try {
				// This method may throw any BeansException, which won't be caught
				// here, if there is a critical failure such as no matching field.
				// We can attempt to deal only with less serious exceptions.
				setPropertyValue(pv);
			}
			catch (NotWritablePropertyException ex) {
				if (!ignoreUnknown) {
					throw ex;
				}
				// Otherwise, just ignore it and continue...
			}
			catch (NullValueInNestedPathException ex) {
				if (!ignoreInvalid) {
					throw ex;
				}
				// Otherwise, just ignore it and continue...
			}
			catch (PropertyAccessException ex) {
				if (propertyAccessExceptions == null) {
					propertyAccessExceptions = new LinkedList();
				}
				propertyAccessExceptions.add(ex);
			}
		}

		// If we encountered individual exceptions, throw the composite exception.
		if (propertyAccessExceptions != null) {
			PropertyAccessException[] paeArray =
					propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]);
			throw new PropertyBatchUpdateException(paeArray);
		}
	}
下に追跡すると、beanWrapperが属性値をどう設定しますか?最初のテーマのspringmvcの原理から遠くなります.だからもう下に降りません.
以下はbeanWrapperまたはConfigrable PropertyAccess orを得るための経路です.無視できます.
Data Binder萢get PropertyAccess or
protected ConfigurablePropertyAccessor getPropertyAccessor() {
		return getInternalBindingResult().getPropertyAccessor();
	}
Data Binder菵get Internal BindingResoult
protected AbstractPropertyBindingResult getInternalBindingResult() {
		if (this.bindingResult == null) {
			initBeanPropertyAccess();
		}
		return this.bindingResult;
	}
Data Binder莻initBenPropertyAccess
public void initBeanPropertyAccess() {
		Assert.state(this.bindingResult == null,
				"DataBinder is already initialized - call initBeanPropertyAccess before other configuration methods");
		this.bindingResult = new BeanPropertyBindingResult(
				getTarget(), getObjectName(), isAutoGrowNestedPaths(), getAutoGrowCollectionLimit());
		if (this.conversionService != null) {
			this.bindingResult.initConversion(this.conversionService);
		}
	}
BeanPropertyBindingResult啢get PropertyAccess or
/**
	 * Returns the {@link BeanWrapper} that this instance uses.
	 * Creates a new one if none existed before.
	 * @see #createBeanWrapper()
	 */
@Override
	public final ConfigurablePropertyAccessor getPropertyAccessor() {
		if (this.beanWrapper == null) {
			this.beanWrapper = createBeanWrapper();
			this.beanWrapper.setExtractOldValueForEditor(true);
			this.beanWrapper.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
			this.beanWrapper.setAutoGrowCollectionLimit(this.autoGrowCollectionLimit);
		}
		return this.beanWrapper;
	}
BenPropertyBindingResoult啢createBenWrapper
protected BeanWrapper createBeanWrapper() {
		Assert.state(this.target != null, "Cannot access properties on null bean instance '" + getObjectName() + "'!");
		return PropertyAccessorFactory.forBeanPropertyAccess(this.target);
	}
PropertyAccess orFactory啝forBenPropertyAccess
public static BeanWrapper forBeanPropertyAccess(Object target) {
		return new BeanWrapperImpl(target);
	}
感想:
commandバインディングをしないなら、正常なrequest.get Parameeter()、効率はきっとspringmvcのパラメータバインディング効率より高くて、空間的にも比較的少ないメモリを占有します.
時間と空間にはどのような違いがありますか?
Servlet Request Data Binderオブジェクトを作成しました.
MutablePropertyValuesオブジェクトを作成しました.
BenPropertyBindingResoultを作成しました.
Default BindingErrocessorを作成しました.
BenWrapperImplを作成しました.command属性を設定します.
参考:
Validation,Data Binding,and Type Coversion
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html