Implementation analysis of the extraction of URL and controller mapping relationship of spring MVC based on annotations __url

Source: Internet
Author: User

In spring MVC, a variety of URLs and controller mapping relationships are defined. In the annotations-based spring MVC, Java annotations Describe the relationship between URLs and controller, so how does spring MVC get these mapping relationships and register them in Handlermap? These problems will be the focus of this paper.

Spring MVC uses the Handlermapping interface abstraction to represent the behavior of fetching controller by request, in the use of the annotation-driven spring MVC, The specific implementation class for handlermapping is: Defaultannotationhandlermapping, which inherits from Abstractdetectinghandlermapping, In the Abstractdetectinghandlermapping class, the method Detecthandlers () is defined, and the purpose of this method is to obtain all possible controller, The URL is registered with the controller mapping relationship to the Handlermap. First, open the code implementation for this method.

//register all handlers found on the current applicationcontext. protected void Detecthandlers () throws {if (logger.isdebugenabled ()) {Logger.debug ("Looking for URL mappings in application context:" + getapplicationcontext ( )); //Get the container in the search bean string[] beannames = (this.detecthandlersinancestorcontexts?) Beanfactoryutils.beannamesfortypeincludingancestors (Getapplicationcontext (), Object.class): Getapplicationcontext (). Getbeannamesfortype (Object.class)); Take any bean name so we can determine URLs for. for (String beanname:beannames) {//obtain URL string[] urls = Determineurlsforhandler (beanname) that each bean can handle; Objectutils.isempty (URLs)) {//URL paths Found:let ' s consider it a handler.//Register to register the URL with the controller mapping relationship to Handlermap Sterhandler (URLs, beanname); else {if (logger.isdebugenabled ()) {Logger.debug ("Rejected bean name ' + beanname + ': No URL paths identified"); } } }

      in Abstractdetectinghandlermapping, Determineurlsforhandler (String beanname) is an abstract method, given the implementation by a specific subclass, where we need to focus on how the Defaultannotationhandlermapping class implements the method. The code is as follows:

Protected string[] Determineurlsforhandler (String beanname) {ApplicationContext context = Getapplicationcontext (); class<?> Handlertype = Context.gettype (beanname); Gets the requestmapping annotation for this bean class level requestmapping mapping = Context.findannotationonbean (Beanname, Requestmapping.class) ; if (mapping!= null) {//@RequestMapping found at type level this.cachedMappings.put (handlertype, mapping); set<string> urls = new linkedhashset<string> (); string[] Typelevelpatterns = Mapping.value (); if (Typelevelpatterns.length > 0) {//@RequestMapping specifies paths in type level//Get the URL defined in Requestmapping in the method. (requestmapping can be defined on a class, or on a method) string[] Methodlevelpatterns = Determineurlsforhandlermethods (Handlertype); for (String typelevelpattern:typelevelpatterns) {if (!typelevelpattern.startswith ("/")) {Typelevelpattern = "/" + type Levelpattern; ///To merge the URL defined by the class level with the URL defined by the method level (after the consolidation rule), added to the collection of URLs that the bean can handle after merging for (String Methodlevelpattern:methodlevelpatterns) { String combinedPattern = Getpathmatcher (). Combine (Typelevelpattern, methodlevelpattern); Addurlsforpath (URLs, Combinedpattern); ///Add the URL of the class level definition to the collection of URLs that the bean can handle Addurlsforpath (URLs, Typelevelpattern); return Stringutils.tostringarray (URLs); else {//actual paths specified by @RequestMapping in method level///If the requestmapping of the class level does not specify a URL, then return the requestmapping definition URL return determineurlsforhandlermethods (handlertype); } else if (Annotationutils.findannotation (Handlertype, controller.class)!= null) {//@RequestMapping to be introspecte D at methods level//If class levels do not define requestmapping, but controller annotations are defined, returns the URL defined in the method requestmapping Determineurlsforhandlermethods (Handlertype); The else {//class level, which does not define requestmapping and does not define controller, returns null return NULL;}

      The above code is a requestmapping annotation at the spring processing class level, but requestmapping annotations can also be defined at the method level. The Determineurlsforhandlermethods () method is to get all the URLs in the class that the method that defines the requestmapping annotation can handle. Let's look at the implementation of this method.

Protected string[] Determineurlsforhandlermethods (class<?> handlertype) {final set<string> urls = new Linkedhashset<string> (); The type may be a proxy class, and if it is a proxy class, get all of its interfaces class<?>[] Handlertypes = Proxy.isproxyclass (handlertype)? Handlertype.getinterfaces (): New class<?>[]{handlertype}; for (class<?> currenthandlertype:handlertypes) {//All methods of the class are processed sequentially reflectionutils.dowithmethods ( Currenthandlertype, New Reflectionutils.methodcallback () {public void Dowith (methods method) {//acquisition of the methodology domain requestmapping requestmapping mapping = Annotationutils.findannotation (method, Requestmapping.class); if (mapping!= null) {//Get the URL that can be processed string[] mappedpaths = Mapping.value ();///Put these URLs into a collection of processed URLs for (String Mappedpath: mappedpaths) {Addurlsforpath (URLs, Mappedpath);}} } }); return Stringutils.tostringarray (URLs); }

       Gets the URLs defined in the class and method-level requestmapping, and basically completes the extraction of the URL. But there is a situation that needs to be handled: the class and the method define the URL at the same time, how the two URLs are merged. What about the rules? Look at the URL merge code:

public string Combine (string pattern1, String pattern2) {if (! Stringutils.hastext (PATTERN1) &&! Stringutils.hastext (PATTERN2)) {//If all two URLs are empty, return null "";} else if (! Stringutils.hastext (PATTERN1)) {//If the first is null, returns the second return pattern2;} else if (! Stringutils.hastext (PATTERN2)) {//If the second is empty, returns the first return PATTERN1;} else if (Match (PATTERN1, pattern2)) {//If two URLs match, return Back to the second return pattern2; else if (Pattern1.endswith ("*")) {if (Pattern2.startswith ("/")) {///hotels/* +/booking->/hotels/booking return Pattern1.substring (0, Pattern1.length ()-1) + pattern2.substring (1); else {///hotels/* + booking->/hotels/booking return pattern1.substring (0, Pattern1.length ()-1) + pattern2;}} else if (Pattern1.endswith ("/**")) {if (Pattern2.startswith ("/")) {///hotels/** +/booking->/hotels/**/booking re Turn Pattern1 + pattern2; else {///hotels/** + booking->/hotels/**/booking return pattern1 + "/" + Pattern2;}} else {int dotPos1 = Pattern1.indexof ('. ')); if (dotPos1 = = 1) {//Simply concatenate the two patterns if (Pattern1.endswith ("/") | | pattern2.startswith ("/")) {Retu RN Pattern1 + pattern2; else {return pattern1 + "/" + Pattern2;}} String fileName1 = pattern1.substring (0, DOTPOS1); String Extension1 = pattern1.substring (DOTPOS1); String fileName2; String Extension2; int dotPos2 = Pattern2.indexof ('. '); if (DotPos2!=-1) {fileName2 = pattern2.substring (0, dotPos2); extension2 = pattern2.substring (DOTPOS2);} else {Filena Me2 = pattern2; Extension2 = "";} String fileName = Filename1.endswith ("*")? filename2:filename1; String extension = Extension1.startswith ("*")? Extension2:extension1; return fileName + extension; } }

Through the above processing, basically completed the bean can handle the extraction of URL information, in the code has a method often appears: Addurlsforpath (), the purpose of this method is to add requestmapping defined path in the URL collection, If the specified path does not end in the default way, Spring adds the default end to the path and adds the processing results to the URL collection.

protected void Addurlsforpath (set<string> URL, String path) {urls.add (path); if (This.usedefaultsuffixpattern & amp;& path.indexof ('. ') = = 1 &&!path.endswith ("/")) {Urls.add (path + ". *"); Urls.add (path + "/");}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.