1. 程式人生 > >SpringMVC 深度解析@RequestMapping(一)

SpringMVC 深度解析@RequestMapping(一)

    SpringMVC作為一個MVC框架,有控制層,當我們在瀏覽器發出了一個請求,SpringMVC是怎麼處理請求,而且通過請求找到對應的類的方法?我們今天帶著這麼問題來解析SpringMVC原始碼處理過程。

  我們在實現SpringMVC控制層時,標示了請求路徑,並標示請求地址對應的哪個方法,原始碼如下:

@Controller
@RequestMapping(value="/test")
public class TestController2 {
	@Autowired
	private TestService testService;
	
	@RequestMapping(value="/index")
	public ModelAndView getIndex(Model model){
       ModelAndView mv = new ModelAndView();  
		  return mv;      
	}
}

    註解@RequestMapping是處理方法的對映。我們在類上面註解和方法上註解這樣會更加的清晰,我們在類上標示更能清晰的知道這個路徑是請求這個類,並在方法上註解比較清楚的是請求哪個方法。例如:http://127.0.0.1:8080/test/index.jhtml。如圖所示:

     

  我們先介紹兩個比較重要的元件HandlerMapping和HandlerAdapter是@Contoller@RequestMapping註解的處理器, HandlerMapping是處理請求對映的處理器;HandlerAdapter介面卡處理器(動態呼叫方法和處理引數)。我們在XML配置檔案中進行配置這兩種處理器。程式碼如下:

 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

一:我們通過解析SpringMVC處理請求深度解析,並介紹HandlerMapping對映處理器

  我們講到這個這個XML配置,找到@RequestMapping@Controller

並封裝成RequestMappingInfo,為後面我們解析處理請求會比較清晰,我在這在補充一下,我們在初始化Bean時我們在上一篇有介紹過,對@RequestMapping註解處理這部分我們沒介紹,所以我在這裡在補充一下,RequestMappingHandlerMapping間接實現了InitializingBean介面,如圖所示:


   RequestMappingHandlerMapping間接實現了InitializingBean介面重寫了afterPropertiesSet方法,初始化RequestMappingHandlerMapping時,會呼叫afterPropertiesSet方法,跟 <bean class="" init-method=""/>屬性init-method處理一樣。afterPropertiesSet呼叫了RequestMappingHandlerMappinginitHandlerMethods實現的。處理@RequestMapping的,我們這邊來分析一下它是怎麼實現的。原始碼:

 protected void initHandlerMethods() {
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));
		for (String beanName : beanNames) {
			if (isHandler(getApplicationContext().getType(beanName))){
				<span style="color:#cc0000;">detectHandlerMethods(beanName);</span>
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

	@Override
	protected boolean isHandler(Class<?> beanType) {
		return ((AnnotationUtils.findAnnotation(beanType, <span style="color:#cc0000;">Controller.class</span>) != null) ||
				(AnnotationUtils.findAnnotation(beanType, <span style="color:#cc0000;">RequestMapping.class</span>) != null));
	}        

 說明:

   (1isHandler這個方法是判斷是否被@Controller@RequestMapping標記

   (2)如果有被@Controller@RequestMapping標記,然後生成RequestMappingInfo例項註冊到快取中,供我們在請求時通過URL能匹配找到。

我們來看怎麼生成RequestMappingInfo例項註冊到快取,由detectHandlerMethods這個方法實現的。原始碼如下:

	protected void detectHandlerMethods(final Object handler) {
		Class<?> handlerType =
				(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());

		final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
			public boolean matches(Method method) {
				T mapping = <span style="color:#cc0000;">getMappingForMethod(method, userType);</span>
				if (mapping != null) {
					mappings.put(method, mapping);
					return true;
				}
				else {
					return false;
				}
			}
		});

		for (Method method : methods) {
                        //註冊到快取中
			<span style="color:#cc0000;">registerHandlerMethod(handler, method, mappings.get(method))</span>;
		}
	}

    
   @Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		RequestMappingInfo info = null;
               //查詢該類下註解的@RequestMapping的所有方法
		RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
		if (methodAnnotation != null) {
			RequestCondition<?> methodCondition = getCustomMethodCondition(method);
                       //建立RequestMappingInfo
			info = createRequestMappingInfo(methodAnnotation, methodCondition);
                       //對類進行查詢有沒有標示@RequestMapping註解
			RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
			if (typeAnnotation != null) {
				RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
                                //成成RequestMappingInfo。類別和方法級別的RequestMapping註解進行組合
				info = <span style="color:#ff0000;">createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);</span>
			}
		}
		return info;
	}
   //設定RequestMappingInfo的屬性然後建立<span style="font-family: 宋體;">RequestMappingInfo</span>
  protected RequestMappingInfo createRequestMappingInfo(RequestMapping annotation, RequestCondition<?> customCondition) {
		String[] patterns = resolveEmbeddedValuesInPatterns(annotation.value());
		return new RequestMappingInfo(
				new PatternsRequestCondition(patterns, getUrlPathHelper(), getPathMatcher(),
						this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
				new RequestMethodsRequestCondition(annotation.method()),
				new ParamsRequestCondition(annotation.params()),
				new HeadersRequestCondition(annotation.headers()),
				new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
				new ProducesRequestCondition(annotation.produces(), annotation.headers(), getContentNegotiationManager()),
				customCondition);
	}

  當我們在瀏覽器傳送了http://127.0.0.1:8080/test/index.jhtml這樣的請求,SpringMVC註冊在web.xml中的前端轉發器DispatcherServlet接收,在這個之前,我們對initHandlerMappingsinitHandlerAdapters初始化,這個在上一篇有介紹過。接下來我們開始分析DispatcherServlet處理請求。

   DispatcherServlet是間接的繼承了HttpSevlet,由父類FrameworkServlet實現了doPost和doGet方法,然後在呼叫子類,DispatcherServletdoDispatch方法處理請求,實現了設計原則介面隔離原則。請求的包含了一些頭部的資訊等,如圖所示:

  

 doDispatch方法的原始碼如下:

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		       HttpServletRequest processedRequest = request;
                               //判斷是否是檔案流請求
				processedRequest = checkMultipart(request);
                                //獲取了對映處理器,裡面是通過請求的URL獲取對應的類並獲取例項化的Bean,包裝成HandlerMethod
				mappedHandler = <span style="color:#990000;">getHandler(processedRequest, false);</span>
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
                               //獲取HandlerAdapter
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						String requestUri = urlPathHelper.getRequestUri(request);
						logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				try {
				   mv = <span style="color:#cc0000;">ha.handle(processedRequest, response, mappedHandler.getHandler());</span>
				}
				applyDefaultViewName(request, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);		
			    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
	}
 

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			HandlerExecutionChain handler = <span style="color:#990000;">hm.getHandler(request);</span>
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

說明:

  (1Spring3.1開始的版本,建議使用RequestMappingHandlerMappingRequestMappingHandlerAdapter,所以我們在XML配置了這個Bean元件。 List<HandlerMapping> handlerMappings裡面存放的是對映處理器,Spring內建了很多對映處理器,例如SimpleUrlHandlerMappingBeanNameUrlHandlerMapping,如圖所示:

   

  (2HandlerExecutionChain包含了處理該請求的處理器,還包含一系列可以攔截請求的攔截器。

   RequestMappingHandlerMapping也是繼承了AbstractHandlerMappinggetHandler具體實現是由AbstractHandlerMapping來實現的,原始碼如下:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}
		return <span style="color:#990000;">getHandlerExecutionChain(handler, request);</span>
	}

說明:

     (1getHandlerInternal方法是處理對映的,獲取request獲取了請求路徑,然後找到對應的RequestMappingInfo獲取了Controller類,並找到了對應的方法。

     (2HandlerExecutionChain帶了一系列的interceptors

第一:getHandlerInternal方法是通過URL找到對應的處理對映的,並找到對應的Bean例項,我們通過原始碼分析是怎麼處理的?

  getHandlerInternal方法原始碼如下:

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
               //通過UrlPathHelper獲取request獲取了請求路徑  例如:test/index.jhtml
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}
                //
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		if (logger.isDebugEnabled()) {
			if (handlerMethod != null) {
				logger.debug("Returning handler method [" + handlerMethod + "]");
			}
			else {
				logger.debug("Did not find handler method for [" + lookupPath + "]");
			}
		}
               //返回對handlerMethod 進行設定已經初始化Bean並設定屬性的handlerMethod 
		return (handlerMethod != null ? handlerMethod.<span style="color:#990000;">createWithResolvedBean</span>() : null);
	}
     //對bean進行初始化
   public HandlerMethod createWithResolvedBean() {
		Object handler = this.bean;
		if (this.bean instanceof String) {
			String beanName = (String) this.bean;
                         //獲取對應的Bean
			handler = this.beanFactory.getBean(beanName);
		}
		return new HandlerMethod(this, handler);
	}
 //設定bean、還有beanFactory 、method、parameters 等屬性
private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
		Assert.notNull(handlerMethod, "HandlerMethod is required");
		Assert.notNull(handler, "Handler object is required");
		this.bean = handler;
		this.beanFactory = handlerMethod.beanFactory;
		this.method = handlerMethod.method;
		this.bridgedMethod = handlerMethod.bridgedMethod;
		this.parameters = handlerMethod.parameters;
	}

 說明:

1UrlPathHelper是分析請求的URLLookupPathForRequest(request)這個方法中有alwaysUseFullPath預設是false使用相對路徑。

2lookupHandlerMethod通過URL檢視對映到哪個方法和類,MultiValueMap<String, T> urlMap 存放的keyurlvalueRequestMappingInfo資訊(params等),通過lookupPath查詢對應的RequestMappingInfo,然後通過RequestMappingInfoMap<T, HandlerMethod> handlerMethods查詢對應的HandlerMethod,並返回。MultiValueMap<String, T> urlMap這個快取中是我們在最開始時有介紹,處理@RequestMapping@Controll 並封裝成RequestMappingInfo並放到快取,如圖所示:



如果查詢對應的方法時,放到Match,裡面有包含的HandlerMethod,如圖所示:

  

   然後通過HandlerMethodcreateWithResolvedBean方法實現了通過beanName獲取已經初始化的 Bean。然後重新初始化HandlerMethod物件,並設定bean、還有beanFactory methodparameters 等屬性。


第二:HandlerExecutionChain 包含了一系列攔截器。會在呼叫Controller類對應方法之前、處理完方法還沒返回檢視、返回檢視之後,這些動態加以攔截。

HandlerExecutionChain這個類屬性很很多新增一系列的攔截器,原始碼如下:

public class HandlerExecutionChain {
	private HandlerInterceptor[] interceptors;
	private List<HandlerInterceptor> interceptorList;
}

getHandler具體實現是由AbstractHandlerMapping中,在這個 方法中實現了加入了攔截器,我們在看一下我們怎麼加入攔截器,原始碼如下:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain =
			(handler instanceof HandlerExecutionChain) ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
                //新增攔截器
		<span style="color:#990000;">chain.addInterceptors(getAdaptedInterceptors());</span>
		String lookupPath = urlPathHelper.getLookupPathForRequest(request);
		for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
			if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}

		return chain;
	}
}

說明:

       我們在XML裡沒配置自己的攔截器,所以這邊都是為空的。

       HandlerInterceptor攔截器介面,裡面有三個方法:

     (1preHandle方法:請求處理之前執行的這個方法,在Controller方法呼叫之前呼叫。例如:呼叫之前判斷是否有登陸。

     (2postHandle方法: 請求進行處理之後,在Controller 方法呼叫之後執行,會在DispatcherServlet 呼叫ModelView檢視之前呼叫。

     (3afterCompletion方法:是在DispatcherServlet 呼叫ModelView檢視之後呼叫。

     既然HandlerInterceptor是介面,我們可以自己實現一個類實現這個介面,這樣我們就自己定義自己的攔截器,然後加到SpringMVC攔截中?當然可以。

    我們自己定義了一個類實現了HandlerInterceptor 介面,例如:public class myInterceptor implements HandlerInterceptor 然後重寫了這個3個方法。我們在XML配置這個類,把自己定義的攔截器加到SpringMVC攔截中。在配置檔案加入了

<span style="color:#990000;"><beans xmlns:mvc="http://www.springframework.org/schema/mvc"
     xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"></span>
 <mvc:interceptors>
<mvc:interceptor>
  <!--攔截哪個包下的類例如:-->
      <mvc:mapping path="/test/*"/>
      <bean class="test.myInterceptor "></bean>
    </mvc:interceptor>
  </mvc:interceptors>

這樣就把我們定義好的攔截器加到SpringMVC的攔截器中。


到這裡,我們對HandlerMapping對映處理器介紹完了,


二:我們通過解析SpringMVC處理請求深度解析,並介紹HandlerAdapter介面卡處理器(動態呼叫方法和處理引數)

HandlerAdapter處理HandlerMethod對映並返回了檢視和資料的物件。getHandlerAdapter獲取了我們在配置檔案的如圖所示:

 

父類AbstractHandlerMethodAdapter實現的,我們先看一下 繼承關係,這種開封閉原則。如圖所示:


我們來看一下這個handle(processedRequest, response, mappedHandler.getHandler());動態的呼叫方法和處理引數的具體實現。原始碼如下:

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return handleInternal(request, response, (HandlerMethod) handler);
	}

  @Override
	protected final ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			// Always prevent caching in case of session attribute management.
			checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
		}
		else {
			// Uses configured default cacheSeconds setting.
			checkAndPrepare(request, response, true);
		}

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);、
				synchronized (mutex) {
					return invokeHandleMethod(request, response, handlerMethod);
				}
			}
		}
         //動態的呼叫方法和處理引數
		return invokeHandleMethod(request, response, handlerMethod);
	}

說明:

  通過HandlerAdapter動態的呼叫方法和處理引數,呼叫方法。我們這邊具體怎麼動態呼叫方法和處理引數,並返回檢視,等下一章在具體的介紹,這裡涉及也比較多。

總結:

  (1) 當我們在瀏覽器傳送了http://127.0.0.1:8080/test/index.jhtml這樣的請求,SpringMVC註冊在web.xml中的前端轉發器DispatcherServlet接收時。

  (2)通過URL檢視對映到哪個方法和類,MultiValueMap<String, T> urlMap 存放的keyurlvalueRequestMappingInfo資訊(params等),RequestMappingInfo獲取了Controller類,並找到了對應的方法。幷包裝返回了HandlerMethod。

  (3)通過BeanName,到工廠獲取已經初始化的Bean,然後重新初始化HandlerMethod物件,並設定bean、還有beanFactory methodparameters 等屬性。

   (4)對HandlerExecutionChain新增攔截器和handler然後返回HandlerExecutionChain

  (5)HandlerAdapter對HandlerExecutionChain進行動態的呼叫方法會返回ModelAndView。

瀏覽器請求已經獲取到了,也找到了對應的類和方法,那怎麼動態的請求方法和處理引數等,執行完方法並返回ModelAndView等?,帶著這些問題我們繼續前進。

相關推薦

SpringMVC 深度解析@RequestMapping

    SpringMVC作為一個MVC框架,有控制層,當我們在瀏覽器發出了一個請求,SpringMVC是怎麼處理請求,而且通過請求找到對應的類的方法?我們今天帶著這麼問題來解析SpringMVC原始碼處理過程。   我們在實現SpringMVC控制層時,標示了請求路徑,

Spring原始碼深度解析總結3—— 配置檔案的讀取和Bean的載入

上一篇總結了Spring利用Resource介面對配置檔案的封裝,接下來我們要看看Spring對封裝好的資源是如何解析的,以及如何利用解析出的資訊載入Bean的。BeanFactory bf = new XmlBeanFactory(new ClassPathResoure(

Spring原始碼解析步分析,springMVC專案啟動過程

 springMVC專案啟動過程,分析原始碼。1、環境搭建,這步我就省略細節,只把我的大概環境說下:windows 7 、jdk 8、maven-3.3.9、tomcat 8.5.11、IDEA 2017.1 x64版 具體環境安裝,我就略過,可自行google、baidu安

樹狀解析深度優先演算法

  導讀:最近有一個解析樹的業務,之前參加過藍橋杯演算法比賽學過一些演算法。(還好沒有全部忘記哈哈)怕以後忘記這種思路特寫此博文。 一、深度優先,記得廣告中經常聽到過,抱著試試看的態度買了3個療程,效果不錯........  也經常聽人說過什麼車到山前必有路,船到橋頭自然直。哈哈,這種思想就是回溯思

SpringMVC的流程分析—— 整體流程概括

classes amp 不同 方法 restfu equals 類圖 strong .get SpringMVC的整體概括 之前也寫過springmvc的流程分析,只是當時理解的還不透徹所以那篇文章就放棄了,現在比之前好了些,想著寫下來分享下,也能增強記憶,也希望可以幫助到

springmvc參數傳遞

har enc parameter tle log con println req tex 1.項目結構 2.UserController.java代碼 package com.spring; import javax.servlet.http.HttpServl

Android框架原始碼解析Volley

前幾天面試CVTE,HR面掛了。讓內部一個學長幫我查看了一下面試官評價,發現二面面試官的評價如下: 廣度OK,但缺乏深究能力,深度與實踐不足 原始碼:只能說流程,細節程式碼不清楚,retrofit和volley都是。 感覺自己一方面:自己面試技巧有待提高吧(框

Android 建立與解析XML—— 概述

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Fragment全解析系列:那些年踩過的坑

本篇主要介紹一些最常見的Fragment的坑以及官方Fragment庫的那些自身的BUG,並給出解決方案;這些BUG在你深度使用時會遇到,比如Fragment巢狀時或者單Activity+多Fragment架構時遇到的坑。 Fragment是可以讓你的app縱享絲滑的設計,如果你的app想在

優達學城-深度學習筆記

優達學城-深度學習筆記(一) 標籤: 機器學習 優達學城-深度學習筆記一 一 神經網路簡介 最大似然概率 交叉熵Cross entropy

深度強化學習: Deep Q Network(DQN)

原文:https://blog.csdn.net/LagrangeSK/article/details/80321265 一、背景 DeepMind2013年的論文《Playing Atari with Deep Reinforcement Learning》指

19java原始碼解析-LinkedList

其他 原始碼解析 https://blog.csdn.net/qq_32726809/article/category/8035214 通過大體瀏覽原始碼,可知,Linkedlist的儲存機構是一個連結串列 類的宣告 public class LinkedList

藍鯨DevOps深度解析系列1:藍盾平臺總覽

關注嘉為科技,獲取運維新知 2018年10月,嘉為科技與騰訊雲、藍鯨智雲攜手,在北京、上海、廣州、深圳舉辦 “研運一體,資料驅動,讓運維走向運營”為主題的分享會,來自金融、電力、能源、製造等行業的數百家企業到場參加。 在這個分享會上,除了下一代的研發運營體系、基於藍鯨平臺實現企業IT自

實戰深度學習OpenCV:canny邊緣檢測

利用canny邊緣檢測,我們可以很好地得到哦一個影象的輪廓,下面是基於C++的,這是我們通過這段程式碼得到的結果: #include "pch.h" #include <iostream> #include <opencv2/core/core.hpp> #inc

深度學習實踐—tensorflow之概述

內容預覽 1.1 深度學習與機器學習的區別 1.1.1 特徵提取方面 1.1.2 資料量和計算效能要求 1.1.3 演算法代表 1.2 深度學習的應用場景 1.2.1 影象識別 1.2

spring原始碼深度解析筆記

之前提到在xmlBeanFactory建構函式中呼叫了XmlBeanDefinitionReader型別的reader屬性提供的方法this.reader.loadBeanDefinitions(resource),這就是載入整個資源載入的切入點。 當進入XmlBeanDe

spring原始碼深度解析筆記

DTD與XSD的區別 DTD(Document Type Definition)即文件型別定義,是一種XML約束模式語言,是XML檔案的驗證機制,是屬於XML檔案組成的一部分。DTD是一種保證XML文件格式正確的有效方法,可以通過比較XML文件和DTD檔案來看

java解析jsonjson的基本格式

最近一直在和json字串交流,還是使用的java。對於一個以前一直使用python的人來說,使用java來解析json,真的是有十萬個不方便。因此也踩了不(很)少(多)坑,特來記載一下。一共分為兩篇,這篇介紹josn的基本格式。 json主要包括: “{” 括起來的物件,例如 {"nam

深度學習tricks——shuffle——同時打亂兩個陣列,保持原先的對應關係仍然存在

自己做資料處理,因為資料比較複雜的關係(我自己也不太熟練),不太方便藉助框架封裝好了的包 在做到需要打亂資料這一步的時候,遇到了如何打亂陣列,使得原始輸入與label的對應關係仍然存在 以上是S

# 深度學習筆記

從感知機到神經網路 感知機中:作為神經網路的起源演算法,感知機有若干輸入,而只有一個輸出 這裡以最簡單的一層感知機舉例: W1W2x1yx2 此時,x1對應的權重為W1,x2對應的權重為W2,而W1和W2權重的大小對應著x1與x2各自重要程度,而他們的乘積和共同