Zebra-dao is in order to solve the user access to the database in a one-step way to encapsulate the DAO, the current way of Java asynchronous access to the main thread pool technology, message middleware technology.
* * The current database asynchronous access scheme mainly has the following two kinds.
1. The business will be used by itself each timeDAOThe call is put into the asynchronous thread pool. Pros: Simple, no need for architecture to support anything. Disadvantage: Because it is a business migration, the cost of migration is relatively large.
2. Use Google's async-mysql-connector. Pros: The behind-the-scenes implementation is based on the NIO approach, with higher performance. Cons: The asynchronous JDBC interface does not have any support for the DAO framework, and the company's business is largely unusable. **
The current common DAO framework MyBatis and Hibernate are based on synchronous access to the database, once the database operation time is too long, the thread will continue to block. This is obviously not enough for some businesses that are demanding time-sensitive. So zebra tries to asynchronously package on a mybatis basis. Zebra is mainly based on the spring-mybatis based on the corresponding package, the lower layer still uses mybatis. The following will be a brief analysis of Zebra-dao specific packaging process and principles.
ZebraThe core configuration class isZebramapperscannerconfigurer, this class increases and decreases the thread pool configuration functionality on Mapperscannerconfigurer, because Zebra-dao is the base line pool for asynchronous encapsulation. This type of real
Now Beandefinitionregistrypostprocessor, Initializingbean,applicationcontextaware, beannameaware these several interfaces, by implementing these interfaces, During spring initialization, the Mapper interface is created
The dynamic proxy class is built and registered in the Spring container. In fact Zebra-dao created a dynamic agent process for the Mapper object, and during the analysis of Zebra-dao, it was discovered that the original Spring-mybatis was actually created for the interface.
A dynamic agent, more precisely spring-mybatis is the dynamic implementation of the Mapper interface, in-depth source found Spring-mybatis did not call the Method.invoke (object) method in the proxy class. Zebra-dao in Spring-mybatis
On the basis of dynamically implementing interface, the object of implementing interface is obtained, on the basis of which the JDK dynamic Agent technology is used to create the proxy class of the Spring-mybatis dynamically implemented interface object and the asynchronous operation database in the proxy class.
When the interface is actually used, the Method.invoke (object) of the proxy class will be invoked. In the method of Zebra-dao, the operation database is encapsulated into threads to be executed by the thread pool, thus the asynchronous processing is realized. The following article for the entire initialization process
The source code to carry on shallow to analyze.
The following will take the Usermapper interface as an example.
Public interface usermapper { Public void Finduserbyid(@Param("UserId")intUserId, Asyncdaocallback<userentity> callback); PublicUserentityFinduserbyid(@Param("UserId")intUSERID);@TargetMethod(name ="Finduserbyid") PublicFuture<userentity>finduserbyidbyfuture(@Param("UserId")intUSERID); PublicList<userentity>GetAll();@TargetMethod(name ="GetAll") PublicFuture<list<userentity>>getAll1(); Public int Insertuser(userentity user);@TargetMethod(name ="Insertuser") Public void InsertUser1(userentity user, asyncdaocallback<integer> callback);@TargetMethod(name ="Insertuser") PublicFuture<integer>InsertUser2(userentity user);}
The Zebramapperscannerconfigurer configuration is required for Zebra-dao, and the only difference with Spring-mybatis is the need to configure the thread pool.
class="com.dianping.zebra.dao.mybatis.ZebraMapperScannerConfigurer"> <propertyname="basePackage" value="com.dianping.zebra.dao.mapper" /> <propertyname="corePoolSize" value="${zebra-dao.executepool.corePoolSize}"></property></bean>
Zebramapperscannerconfigurer re-implemented the Mapperscannerconfigurer class in Spring-mybatis, the main function of which is to search the base package for all of the following interface, and register it in the Spring bean container, and its registered class bean is zebramapperfactorybean. Here is an introduction to the important methods in this class.
public void Postprocessbeandefinitionregistry (Beandefinitionregistry registry) throws Beansexception {if (this. Processpropertyplaceholders) {processpropertyplaceholders ();} Zebraclasspathmapperscanner scanner = new Zebraclasspathmapperscanner (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();Created a dynamic proxy for an interface scanner. Scan(StringUtils. Tokenizetostringarray(This. Basepackage, Configurableapplicationcontext. CONFIG_location_delimiters));}
The method is executed when spring initializes. It is primarily used to search all mapper classes under base packages and register them in spring's benfinitionholder. The main methods in Scanner.scan (Stringutils.tokenizetostringarray (This.basepackage,
configurableapplicationcontext.config_location_delimiters), execution, which invokes the scan method of the parent class Classpathbeandefinitionscanner, where Doscan (basepackages) is called in the Csan method, the method of modification
Modified by protected for subclass implementations, the Zebraclasspathmapperscanner class was designed in Zebra-dao, which overrides the Dosan of the parent class Classpathbeandefinitionscanner ( Basepackages) method.
@Override PublicSet<beandefinitionholder>Doscan(String ... basepackages) {/** calls the parent class method to get the Beandefinitionholder object that formulates all the interfaces under the package, and in spring initializes the bean process, and spring first takes All classes to be initialized are first registered through Beandefinitionregistry, and some of the bean's property information (such as scope, ClassName, Beanname, and so on) is saved to Beandefinitionholder Zebra-dao here first calls the Classpathbeandefinitionscanner.doscan method in spring, registers the class of all mapper interfaces with the Beandefinitionholder instance, and then returns a set <beandefinitionholder>, the other contains all the Mapper class beandefinitionholder objects that were searched. */Set<beandefinitionholder> beandefinitions =Super. Doscan (Basepackages);if(Beandefinitions.isempty ()) {Logger.warn ("No MyBatis Mapper was found in '"+ arrays.tostring (basepackages) +"' Package. Please check your configuration. "); }Else{The classname for all holder in the For loop in/** is Zebramapperfactorybea.class, and the class name of Mapper interface is setter to Mapperfact Orybean property is in Mapperinterface * / for(Beandefinitionholder holder:beandefinitions) {genericbeandefinition definition = (genericbeandefinition) holder.getbeandefinition ();if(Logger.isdebugenabled ()) {Logger.debug ("Creating Mapperfactorybean with Name "+ holder.getbeanname () +"' and '"+ definition.getbeanclassname () +"' Mapperinterface"); }//Set the type of the interface inDefinition.getpropertyvalues (). Add ("Mapperinterface", Definition.getbeanclassname ());//Set the True type of bean ZebramapperfactorybeanDefinition.setbeanclass (Zebramapperfactorybean.class);//Whether to add the Mapper interface to the MyBatis configDefinition.getpropertyvalues (). Add ("Addtoconfig", This. Addtoconfig);Booleanexplicitfactoryused =false;//If the Sqlsessionfactorybeanname name is not empty, query in the spring container //For multiple data sources 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 the Sqlsessiontemplatebeanname name is not empty, query in the spring container for multiple data sources 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); } } }returnBeandefinitions; }
So far, the initialization of Zebra-dao is basically complete. When we inject an instance with the Mapper interface, the Mapper interface instance will need Zebramapperfactorybean because Zebra-dao is registering the interface with Zebramapperfactorybean.
To create. The following will enter into the Zebramapperfactorybean class, there is a method Checkdaoconfig ()
@Overrideprotected void Checkdaoconfig() {Super. Checkdaoconfig (); Notnull ( This. Mapperinterface,"Property ' Mapperinterface ' is required"); Configuration configuration = Getsqlsession (). GetConfiguration ();if( This. Addtoconfig &&!configuration.hasmapper ( This. Mapperinterface)) {Try{//Add the Mapper interface to the global configuration object;Configuration.addmapper ( This. mapperinterface); }Catch(Throwable t) {Logger.error ("Error while adding the Mapper '"+ This. Mapperinterface +"' to Configuration.", t);Throw NewIllegalArgumentException (t); }finally{errorcontext.instance (). reset ();} }}
The method is executed after spring initialization because the method overrides the Checkdaoconfig () method in the parent class Sqlsessiondaosupport. The Sqlsessiondaosupport implements the abstract Daosupport abstract Method Checkdaoconfig (), Daosupport also implements the Initializingbean interface and calls the abstract method Checkdaoconfig () in the interface method, so the method is ultimately called after spring initialization. The above method first detects whether the mapperinterface currently needed to be created is present in the global configuration and is added if it does not exist. After the method call is complete, call the GetObject method to generate the mapper instance, and see Zebramapperfactorybean.getobject's code for the method as follows:
PublicTGetObject()throwsException {T mapper = Getsqlsession (). Getmapper ( This. mapperinterface); Asyncmapperproxy<t> Asyncmapperproxy =NewAsyncmapperproxy<t> (mapper);return(T) Proxy.newproxyinstance (Mapperinterface.getclassloader (),NewClass[] {mapperinterface}, asyncmapperproxy);}/** continues to invoke GetConfiguration () in the Getmapper () method in sqlsession. Getmapper (type, this); Trace in to find then call Mapperregistry.getmapper (type, sqlsession); method, and then trace it will find that the following method is called * / Public<T> TGetmapper(class<t> type, sqlsession sqlsession) {FinalMapperproxyfactory<t> mapperproxyfactory = (mapperproxyfactory<t>) knownmappers.get (type);if(Mapperproxyfactory = =NULL)Throw NewBindingexception ("Type"+ Type +"isn't known to the mapperregistry.");Try{returnMapperproxyfactory.newinstance (sqlsession); }Catch(Exception e) {Throw NewBindingexception ("Error getting mapper instance. Cause: "+ E, E); }}
The Mapper interface instance object is obtained in the change method, which is a proxy object. Further depth can be found in the proxy object that performs this method of manipulating the database
publicMethod method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args);}
So far we've got the proxy object for the interface, and for that, go back to
publicgetObjectthrows Exception { T mapper = getSqlSession().getMapper(thisnewreturnnew Class[] { mapperInterface }, asyncMapperProxy);}
method, at this time our Mapper object is the proxy object of the interface, it can also be said to be a dynamic implementation of the object, the object after the acquisition of some column operation or a synchronous operation, in order to achieve asynchronous operation, Zebra-dao further to the object is asynchronous encapsulation.
Encapsulates mapper as an asynchronous proxy class Asyncmapperproxy, and finally uses dynamic Proxy technology to create proxy objects for Mapper objects. Next we will go to Asyncmapperproxy.
Not to be continued
How Zebra DAO Works