Mybatis based on annotations mapper source code Analysis

Source: Internet
Author: User

Currently MyBatis in addition to the SQL can be configured through XML, but also through the form of annotations to configure SQL, this article mainly describes how MyBatis is handling annotated SQL mapping, through the source code analysis process

XML configuration
Parsing process

  private void Mapperelement (xnode parent) throws Exception {//If the Mapper node is configured in the configuration (parent! = NULL) {          For (XNode Child:parent.getChildren ()) {//If the configuration pair is a packet path if ("Package". Equals (Child.getname ())) {          String mapperpackage = Child.getstringattribute ("name");        Configuration.addmappers (Mapperpackage);          } else {//Gets the resource attribute in the mapper element String resource = Child.getstringattribute ("resource");          Gets the URL property of the mapper element, String url = child.getstringattribute ("url");          Gets the class attribute in the mapper element, if the mapper configuration of the annotation-based configuration is class String Mapperclass = Child.getstringattribute ("class"); For Resource,url,mapperclass precedence using resource, followed by the URL is finally the class if (resource! = null && URL = = NULL &&amp ;            Mapperclass = = null) {//Create exception Context errorcontext.instance (). resource (Resource);            InputStream InputStream = resources.getresourceasstream (Resource); Create XMLMApperbuilder Xmlmapperbuilder mapperparser = new Xmlmapperbuilder (inputstream, configuration, resource, Configu            Ration.getsqlfragments ());          Parse XML mapperparser.parse (); } else if (resource = = NULL && URL! = NULL && Mapperclass = = null) {errorcontext.instance (). Re            Source (URL);            InputStream inputstream = resources.geturlasstream (URL); Xmlmapperbuilder mapperparser = new Xmlmapperbuilder (inputstream, configuration, URL, configuration.getsqlfragments ()            );          Mapperparser.parse (); } else if (resource = = NULL && URL = = NULL && Mapperclass! = null) {//Get interface C for mapper            lass<?> mapperinterface = Resources.classforname (Mapperclass);          Register the interface with a known mapper configuration.addmapper (mapperinterface); } else {throw new Builderexception ("A mapper element may be only specify a URL, resource or class, and not more t Han one. "); }        }      }    }  }

  

Public <T> void Addmapper (class<t> type) {    mapperregistry.addmapper (type);  }

  

Register mapper public  <T> void Addmapper (class<t> type) {    //If type is an interface if    (Type.isinterface ()) {      ///Determine if the interface has already registered the corresponding mapper, and if so, throw an exception because Knownmappers's key is type      if (Hasmapper (type)) {        throw new Bindingexception ("type" + Type + "is already known to the Mapperregistry.");      Boolean loadcompleted = false;      try {        //Creates a mapperproxyfactory on the interface and guarantees registration to Knownmappers        knownmappers.put (type, new mapperproxyfactory<t > (type));        Create Mapperannotationbuilder        mapperannotationbuilder parser = new Mapperannotationbuilder (config, type);        Analytic annotation        parser.parse ();        A successful parse indicates that the load is complete        loadcompleted = true;      } finally {        //If the load is not completed, remove it from the knownmappers if        (! loadcompleted) {          knownmappers.remove (type);}}}}  

  

Public Mapperannotationbuilder (Configuration configuration, class<?> type) {
String resource = Type.getname (). replace ('. ', '/') + ". Java (best guess)";
This.assistant = new Mapperbuilderassistant (configuration, Resource);
this.configuration = Configuration;
This.type = type;
Initialize annotation types, divided into two groups
Sqlannotationtypes.add (Select.class);
Sqlannotationtypes.add (Insert.class);
Sqlannotationtypes.add (Update.class);
Sqlannotationtypes.add (Delete.class);

Sqlproviderannotationtypes.add (Selectprovider.class);
Sqlproviderannotationtypes.add (Insertprovider.class);
Sqlproviderannotationtypes.add (Updateprovider.class);
Sqlproviderannotationtypes.add (Deleteprovider.class);
}

public void Parse () {
String resource = type.tostring ();
Determine if the resource is already registered
if (!configuration.isresourceloaded (Resource)) {
The XML resource needs to be loaded without registering
Loadxmlresource ();
Add the resource name to the already registered collection
Configuration.addloadedresource (Resource);
Set namespace
Assistant.setcurrentnamespace (Type.getname ());
Parse Cache
Parsecache ();
Parsing Cacheref
Parsecacheref ();
Get
Method[] methods = Type.getmethods ();
for (Method method:methods) {
try {
Parse statement If it is not the bridge method
if (!method.isbridge ()) {
Parsestatement (method);
}
} catch (Incompleteelementexception e) {
Configuration.addincompletemethod (New Methodresolver (This, method));
}
}
}
Resolve Pending methods
Parsependingmethods ();
}

  

private void Loadxmlresource () {    //determines if the resource has been loaded if    (!configuration.isresourceloaded ("namespace:" + Type.getname ())) {      //Gets the resource's path      String xmlresource = Type.getname (). replace ('. ', '/') + ". xml";      InputStream inputstream = null;      try {        InputStream = Resources.getresourceasstream (Type.getclassloader (), xmlresource);      } catch (IOException E ) {        //Ignore, resource is not required      }      //If the resource exists if      (inputstream! = null) {        // Build Xmlmapperbuilder        Xmlmapperbuilder xmlparser = new Xmlmapperbuilder (InputStream, Assistant.getconfiguration () , Xmlresource, Configuration.getsqlfragments (), Type.getname ());        Parse XML        xmlparser.parse ();}}}  

  

private void Parsecache () {    //gets @CacheNamespace annotation on interface    cachenamespace cachedomain = type.getannotation ( Cachenamespace.class);    If the annotation exists if    (cachedomain! = null) {      //Get annotation configured cache size      Integer size = cachedomain.size () = = 0? null:cachedomain. Size ();      Get cache refresh Frequency      Long flushinterval = cachedomain.flushinterval () = = 0? null:cacheDomain.flushInterval ();      Resolves the properties of the Cachenamespace configuration properties      props = Converttoproperties (Cachedomain.properties ());      Create cache Assistant.usenewcache with annotations configured data (      cachedomain.implementation (), Cachedomain.eviction (), Flushinterval, Size, Cachedomain.readwrite (), cachedomain.blocking (), props);    }  }

  

private void Parsecacheref () {    //gets @CacheNamespaceRef annotation on interface    cachenamespaceref cachedomainref = Type.getannotation (cachenamespaceref.class);    If the cache reference is configured if    (cachedomainref! = null) {      //Gets the referenced type      class<?> reftype = Cachedomainref.value ();      String refName = Cachedomainref.name ();      If both the reference type and the reference name are empty, throw an exception if      (RefType = = Void.class && refname.isempty ()) {        throw new Builderexception (" Should is specified either value () or name () attribute in the @CacheNamespaceRef ");      }      Throws an exception if both the reference type and the reference name are configured with valid data, both of which are mutually exclusive data      if (reftype! = Void.class &&!refname.isempty ()) {        throw new Builderexception ("Cannot use both value () and name () attribute in the @CacheNamespaceRef");      }      Get namespace      String namespace = (reftype! = void.class)? Reftype.getname (): RefName;      Use cache      Assistant.usecacheref (namespace);    }  }

  

  void Parsestatement (method) {//Get parameter type class<?> Parametertypeclass = Getparametertype (method);    Get languagedriver Languagedriver Languagedriver = Getlanguagedriver (method);    Get sqlsource Sqlsource Sqlsource = Getsqlsourcefromannotations (method, Parametertypeclass, Languagedriver) from the annotations; If Sqlsource is not NULL if (Sqlsource! = null) {//Gets @Options annotations Options options = Method.getannotation (options.c      LASS);      Create Statementid final String Mappedstatementid = type.getname () + "." + Method.getname ();      Integer fetchsize = null;      Integer timeout = null;      StatementType StatementType = statementtype.prepared;      ResultsetType ResultsetType = resultsettype.forward_only;      Gets the SQL type Sqlcommandtype Sqlcommandtype = Getsqlcommandtype (method);      is the query Boolean isselect = Sqlcommandtype = = Sqlcommandtype.select;      Whether the cache needs to be refreshed, and if the query is not the default value of True, the query defaults to false Boolean flushcache =!isselect; Whether the cache is used, the query defaults to TRUE, not the query defaultis false Boolean usecache = Isselect;      Keygenerator Keygenerator;      String keyproperty = "id";      String keycolumn = null; If it is an INSERT or update if (SqlCommandType.INSERT.equals (sqlcommandtype) | | SqlCommandType.UPDATE.equals (Sqlcommandtype)) {//Get selectkey annotations Selectkey Selectkey = method.getannotation (S        Electkey.class); if (Selectkey! = null) {Keygenerator = Handleselectkeyannotation (Selectkey, Mappedstatementid, Getparametertype (          method), Languagedriver);        Keyproperty = Selectkey.keyproperty (); } else if (options = = null) {Keygenerator = Configuration.isusegeneratedkeys ()?        Jdbc3KeyGenerator.INSTANCE:NoKeyGenerator.INSTANCE; } else {keygenerator = Options.usegeneratedkeys ()?          Jdbc3KeyGenerator.INSTANCE:NoKeyGenerator.INSTANCE;          Keyproperty = Options.keyproperty ();        KeyColumn = Options.keycolumn (); }} else {//is not inserted or updated i.e. query and delete is keygenerator to Nokeygenerator instance KeygeneratoR = nokeygenerator.instance; }//If the @options annotation is not null if (options = null) {/////is set to refresh cache if (FlushCachePolicy.TRUE.equals (op        Tions.flushcache ())) {Flushcache = true;        } else if (FlushCachePolicy.FALSE.equals (Options.flushcache ())) {Flushcache = FALSE;        }//Whether to use cache UseCache = Options.usecache (); Fetchsize fetchsize = options.fetchsize () >-1 | | Options.fetchsize () = = Integer.min_value? Options.fetchsize (): null; Issue #348 timeout = options.timeout () >-1?        Options.timeout (): null;        StatementType = Options.statementtype ();      ResultsetType = Options.resultsettype ();      } String resultmapid = null;      Get resultmap annotations Resultmap resultmapannotation = method.getannotation (Resultmap.class);        if (resultmapannotation! = null) {string[] resultmaps = Resultmapannotation.value ();        StringBuilder sb = new StringBuilder (); for (String ResultmaP:resultmaps) {if (sb.length () > 0) {sb.append (",");        } sb.append (Resultmap);      } resultmapid = Sb.tostring ();      } else if (isselect) {resultmapid = Parseresultmap (method); } assistant.addmappedstatement (Mappedstatementid, Sqlsource, StatementType, SqlC          Ommandtype, Fetchsize, timeout,//parametermapid null, Parametertypeclass,          Resultmapid, Getreturntype (method), ResultsetType, Flushcache, UseCache, TODO Gcode issue #577 false, Keygenerator, Keyproperty, KeyColumn,// DatabaseID null, Languagedriver,//resultsets options! = null?    Nullorempty (Options.resultsets ()): null); }  }

Private Sqlsource Getsqlsourcefromannotations (method, class<?> ParameterType, Languagedriver Languagedriver) {try {//Get @select, @Insert, @Update, @Delete types of annotations class<? extends annotation> Sqlann      Otationtype = Getsqlannotationtype (method); Get @SelectProvider, @InsertProvider, @UpdateProvider @DeleteProvider annotations class<?      Extends annotation> Sqlproviderannotationtype = Getsqlproviderannotationtype (method); If the SQL annotations are NOT NULL if (sqlannotationtype! = null) {///SQLProvider annotations are also not empty then an exception is thrown, both mutually exclusive if (Sqlproviderannotat Iontype! = null) {throw new Bindingexception ("Cannot supply both a static SQL and SQLProvider to method name        D "+ method.getname ());        }//Get annotations Annotation sqlannotation = method.getannotation (Sqlannotationtype);        Gets the value of the annotation configuration final string[] strings = (string[]) Sqlannotation.getclass (). GetMethod ("value"). Invoke (Sqlannotation); Create Sqlsource return bui based on the configured dataLdsqlsourcefromstrings (Strings, ParameterType, languagedriver); } else if (sqlproviderannotationtype! = null) {//If SQLProvider annotation is not empty Annotation sqlproviderannotation = Method.getan        Notation (Sqlproviderannotationtype); Create a Providersqlsource return new Providersqlsource (Assistant.getconfiguration (), sqlproviderannotation, type, met      HOD);    }//If no SQL annotations are configured and no SQLProvider annotations are configured, return null return null;  } catch (Exception e) {throw new Builderexception ("Could not the Find value method on SQL annotation.    Cause: "+ E, E); }  }

  

Mybatis based on annotations mapper source code Analysis

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.