The MyBatis map file loading is an analysis of how all of our XML mapping files are loaded, but in the process of learning SSM, I find that the interface of the DAO layer will inject an instantiated object into the service layer directly, but we do not do the DAO layer implementation class,
Very curious to check the information, the following analysis
MyBatis configuration file
MyBatis is implemented by the Org.mybatis.spring.mapper.MapperScannerConfigurer class to implement the DAO layer scan we enter the Mapperscannerconfigurer class, There is a Postprocessbeandefinitionregistry method
Public voidPostprocessbeandefinitionregistry (Beandefinitionregistry registry) {if( This. Processpropertyplaceholders) {processpropertyplaceholders (); } Classpathmapperscanner Scanner=NewClasspathmapperscanner (registry); Scanner.setaddtoconfig ( This. Addtoconfig); Scanner.setannotationclass ( This. Annotationclass); Scanner.setmarkerinterface ( This. Markerinterface); Scanner.setsqlsessionfactory ( This. sqlsessionfactory); Scanner.setsqlsessiontemplate ( This. sqlsessiontemplate); Scanner.setsqlsessionfactorybeanname ( This. Sqlsessionfactorybeanname); Scanner.setsqlsessiontemplatebeanname ( This. Sqlsessiontemplatebeanname); Scanner.setresourceloader ( This. ApplicationContext); Scanner.setbeannamegenerator ( This. Namegenerator); Scanner.registerfilters (); //Scan all DAO interfaces under the Basepackage packageScanner.scan (Stringutils.tokenizetostringarray ( This. Basepackage, configurableapplicationcontext.config_location_delimiters)); }
Enter the Doscan method
// The parent class finds the Qualifying interface class and transforms it into a bean class Super . Doscan (basepackages); if (Beandefinitions.isempty ()) { Logger.warn ("No MyBatis Mapper is found in '" + arrays.tostring ( basepackages) + "' package. Please check your configuration. " Else {// processing the found interface Bean class processbeandefinitions ( beandefinitions);} return beandefinitions;
And look at the Processbeandefinitions method.
Private voidProcessbeandefinitions (set<beandefinitionholder>beandefinitions) {genericbeandefinition definition; for(beandefinitionholder holder:beandefinitions) {definition=(genericbeandefinition) holder.getbeandefinition (); if(logger.isdebugenabled ()) {Logger.debug ("Creating Mapperfactorybean with Name" +Holder.getbeanname ()+ "' and '" + definition.getbeanclassname () + "' Mapperinterface"); } //The Mapper interface is the original class of the Bean//but, the actual class of the beans is MapperfactorybeanDefinition.getconstructorargumentvalues (). Addgenericargumentvalue (Definition.getbeanclassname ());//Issue #59
Set the Beanclass type to Mapperfactorybean definition.setbeanclass ( This. Mapperfactorybean.getclass ()); Definition.getpropertyvalues (). Add ("Addtoconfig", This. Addtoconfig); Booleanexplicitfactoryused =false; if(Stringutils.hastext ( This. Sqlsessionfactorybeanname)) {definition.getpropertyvalues (). Add ("Sqlsessionfactory",NewRuntimebeanreference ( This. Sqlsessionfactorybeanname)); Explicitfactoryused=true; } Else if( This. sqlsessionfactory! =NULL) {definition.getpropertyvalues (). Add ("Sqlsessionfactory", This. sqlsessionfactory); Explicitfactoryused=true; } if(Stringutils.hastext ( This. Sqlsessiontemplatebeanname)) { if(explicitfactoryused) {Logger.warn ("Cannot use Both:sqlsessiontemplate and sqlsessionfactory together. Sqlsessionfactory is ignored. "); } definition.getpropertyvalues (). Add ("Sqlsessiontemplate",NewRuntimebeanreference ( This. Sqlsessiontemplatebeanname)); Explicitfactoryused=true; } Else if( This. sqlsessiontemplate! =NULL) { if(explicitfactoryused) {Logger.warn ("Cannot use Both:sqlsessiontemplate and sqlsessionfactory together. Sqlsessionfactory is ignored. "); } definition.getpropertyvalues (). Add ("Sqlsessiontemplate", This. sqlsessiontemplate); Explicitfactoryused=true; } if(!explicitfactoryused) { if(logger.isdebugenabled ()) {Logger.debug ("Enabling Autowire by type for Mapperfactorybean with Name '" + holder.getbeanname () + "'."); } definition.setautowiremode (Abstractbeandefinition.autowire_by_type); } } }
The DAO layer interface will eventually be packaged into Mapperfactorybean
That is to say, we will be all the DAO layer files, encapsulated into the following configuration file the same effect, is not very familiar with
class= "Org.mybatis.spring.mapper.MapperFactoryBean" > <property name= "Mapperinterface" value= " Com.zsh.dao.UserMapper "></property> <property name=" sqlsessionfactory "ref=" sqlsessionfactory "/ ></bean>
The above is the principle of scanning the DAO layer, we continue to analyze how to instantiate the interface automatically
Again, before we instantiate the interface automatically, we know what it is. Dynamic proxy analysis and extension of dynamic agent mechanism
The above is a factory method to create the bean
First we locate the class Org.mybatis.spring.mapper.MapperFactoryBean
Public class extends Implements Factorybean<T> { private class<t> mapperinterface; Private boolean addtoconfig;
You can see that the class implements the Org.springframework.beans.factory.FactoryBean interface by invoking the
Org.mybatis.spring.mapper.MapperFactoryBean.getObject () method to get the bean
Public throws Exception { return getsqlsession (). Getmapper (this. mapperinterface);
We analyze the above getsqlsession () can see Getmapper implementation class is sqlsessiontemplate, we jump to sqlsessiontemplate look at Getmapper method
public <T> T getmapper (class<t> type) { return this ); }
As you can see, it first calls its own getconfiguration () method to return a configuration object and then calls the Getmapper method of the Configuration object.
We directly navigate to the Getmapper method of the configuration
public <T> T getmapper (class<t> type, sqlsession sqlsession) { return Mapperregistry.getmapper (type, sqlsession); }
Navigate directly to Mapperregistry.getmapper
Public<T> T Getmapper (class<t>type, sqlsession sqlsession) { FinalMapperproxyfactory<t> mapperproxyfactory = (mapperproxyfactory<t>) Knownmappers.get (type); if(Mapperproxyfactory = =NULL) { Throw NewBindingexception ("type" + Type + "is not known to the Mapperregistry.")); } Try { returnmapperproxyfactory.newinstance (sqlsession); } Catch(Exception e) {Throw NewBindingexception ("Error getting mapper instance. Cause: "+e, E); } }
In this method, first obtain a Mapperproxyfactory object mapperproxyfactory, and then call the object's Newinstance method to create the bean we need, navigate to the Newinstance method
Public T newinstance (sqlsession sqlsession) { finalnew mapperproxy<t>(sqlsession , Mapperinterface, Methodcache); return newinstance (mapperproxy); }
Finally we go into the newinstance this overloaded function
protected T newinstance (mapperproxy<t> mapperproxy) { returnnew class[] { Mapperinterface}, Mapperproxy); }
In this case, we created a proxy object with the JDK's dynamic proxy, that is, we finally created our own proxy object for all the interfaces of mapper, and executed our SQL through proxy objects.
Reference and thanks
Https://www.cnblogs.com/question-sky/p/6654101.html
http://blog.csdn.net/tanqidong1992/article/details/48026491
Https://www.jianshu.com/p/3e619786dd18
How the Mapper (DAO layer) interface is instantiated