mybatis-spring Classpathmapperscanner Source Analysis (custom annotation load bean)

Source: Internet
Author: User
Tags static class throwable
Summary:When using MyBatis, a series of DAO interfaces can be configured through Mybatis-spring Mapperfactorybean, and Mapperfactorybean GetObject method can return the dynamic proxy class corresponding to the DAO interface. The implementation class of the DAO interface is actually generated by defaultsqlsession in a dynamic proxy manner. And when there are many DAO classes, you can implement Mapperfactorybean objects and reduce configuration by configuring the packages to be described through the Mybatis-spring Mappercannerconfigurer class. a review of Mapperfactorybean and Mappercannerconfigurer configurationMapperfactorybean Configure the DAO to use
<bean id= "Usermapper" class= "Org.mybatis.spring.mapper.MapperFactoryBean" >  
  <property name= " Mapperinterface "value=" Org.mybatis.spring.sample.mapper.UserMapper "/>  
  <property name=" Sqlsessionfactory "ref=" sqlsessionfactory "/>  
</bean>  
Through the above configuration in the service layer can directly inject usermapper this DAO, Mapperfactorybean internal will invoke defaultsqlsession as a dynamic proxy generation of the DAO interface implementation class.
Mappercannerconfigurer configure multiple DAO to use
<bean class= "Org.mybatis.spring.mapper.MapperScannerConfigurer" >  
  <property name= "Basepackage" value= "Org.mybatis.spring.sample.mapper"/>  
  <property name= "Sqlsessionfactorybeanname" Sqlsessionfactory "/>
</bean>  

The corresponding Mapperfactorybean object is generated by the corresponding DAO interface in the package Org.mybaits.spring.sample.mapper, and then invoked by the service layer. The DAO is declared as an interface, because the implementation class of the DAO interface is generated in dynamic proxies within the defaultsqlsession. Mappercannerconfigurer is to complete the customization and modification of Beandefinitionregistry by implementing the Beandefinitionregistrypostprocessor interface, The Classpathmapperscanner class is called in the Postprocessbeandefinitionregistry method. This class specifies the bean to be generated by scanning the package ... Second, Classpathmapperscanner code analysisThe Classpathmapperscanner class implements the Classpathbeandefinitionscanner and overrides the Registerfilters method and the Doscan method. The Registerfilters method is primarily based on the Annotationclass or the Markerinterface property to specify that only the classes below the specified package have an interface with a note or a sub-interface for an interface.
public void Registerfilters () {Boolean acceptallinterfaces = true; If specified, use the given annotation and/or marker interface if (This.annotationclass!= null) {ADDINCLU
      Defilter (New Annotationtypefilter (This.annotationclass));
    Acceptallinterfaces = false; }//override Assignabletypefilter to ignore matches on the actual marker-if (interface this.markerinterface n  ull) {Addincludefilter (new Assignabletypefilter (this.markerinterface) {@Override protected Boolean
        Matchclassname (String className) {return false;
      }
      });
    Acceptallinterfaces = false; } if (acceptallinterfaces) {//default include filter accepts all classes Addincludefilter (new Type  Filter () {public boolean match (Metadatareader Metadatareader, Metadatareaderfactory metadatareaderfactory) throws
        IOException {return true;
    }
      }); }//Exclude Package-info.java
    Addexcludefilter (New TypeFilter () {public boolean match (Metadatareader Metadatareader, Metadatareaderfactory m
        Etadatareaderfactory) throws IOException {String className = Metadatareader.getclassmetadata (). GetClassName ();
      Return Classname.endswith ("Package-info");
  }
    }); }

The Doscan method is used to convert the interface below the package into a Mapperfactorybean class.
Public set<beandefinitionholder> Doscan (String ... basepackages) {set<beandefinitionholder>

    Beandefinitions = Super.doscan (basepackages);  if (Beandefinitions.isempty ()) {Logger.warn ("No mybatis mapper is found in" "+ arrays.tostring (basepackages) +" " Package. Please check your configuration. ");} else {for (Beandefinitionholder holder:beandefinitions) {genericbeandefinition definition = (genericbean

        Definition) 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 Mappe
        Rfactorybean definition.getpropertyvalues (). Add ("Mapperinterface", Definition.getbeanclassname ());
Definition.setbeanclass (Mapperfactorybean.class);
        Definition.getpropertyvalues (). Add ("Addtoconfig", this.addtoconfig);
        Boolean explicitfactoryused = false; if (Stringutils.hastext (This.sqlsessionfactorybeanname)) {definition.getpropertyvalues (). Add ("SqlSessionFactory
          ", New Runtimebeanreference (This.sqlsessionfactorybeanname));
        Explicitfactoryused = true; else if (this.sqlsessionfactory!= null) {definition.getpropertyvalues (). Add ("Sqlsessionfactory", this.sqlses
          Sionfactory);
        Explicitfactoryused = true; } if (Stringutils.hastext (this.sqlsessiontemplatebeanname)) {if (explicitfactoryused) {lo Gger.warn ("Cannot use Both:sqlsessiontemplate and sqlsessionfactory together.
          Sqlsessionfactory is ignored. "); Definition.getpropertyvalues (). Add ("Sqlsessiontemplate", New Runtimebeanreference (
          This.sqlsessiontemplatebeanname));
        Explicitfactoryused = true; else if (this.sqlsessiontemplate!= NULL) {if (explicitfactoryused) {Logger.warn ("Cannot use Both:sqlsessiontemplate and sqlsessionf Actory together.
          Sqlsessionfactory is ignored. ");
          Definition.getpropertyvalues (). Add ("Sqlsessiontemplate", this.sqlsessiontemplate);
        Explicitfactoryused = true; } if (!explicitfactoryused) {if (logger.isdebugenabled ()) {Logger.debug ("Enabling AUTOWIR
          E by type for Mapperfactorybean with Name ' "+ holder.getbeanname () +" '. ");}
        Definition.setautowiremode (Abstractbeandefinition.autowire_by_type);
  }} return beandefinitions; }

third, by implementing the Classpathbeandefinitionscanner class to define the scan of bean annotations 1, the definition of their own notesThe annotations here are not @component annotated, but are scanned by the Classpathbeandefinitionscanner class.
@Target ({elementtype.type})
@Retention (retentionpolicy.runtime)
@Documented public
@interface customizecomponent {
 String value () default "";
}

2, the annotated class
@CustomizeComponent public
class ScanClass1 {public
void print () {
    System.out.println ("ScanClass1");
}
}

3, the custom Beanscannerconfigurer classBeanscannerconfigurer is used to embed in the spring loading process, where beanfactorypostprocessor and Applicationcontextaware are used. Spring provides a number of interfaces that allow programs to embed the spring loading process. The inherited Applicationcontextaware interface in this class, spring reads the JavaBean of the Applicationcontextaware type and calls Setapplicationcontext ( ApplicationContext applicationcontext) incoming spring applicationcontext.
Similarly, the Beanfactorypostprocessor interface is inherited, and spring will invoke the Postprocessbeanfactory method to perform custom functions after Beanfactory's related processing completes.
@Component public
Static class Beanscannerconfigurer implements  Beanfactorypostprocessor, Applicationcontextaware {
	private applicationcontext applicationcontext;
	
	public void Setapplicationcontext (ApplicationContext applicationcontext) throws Beansexception {
	    This.applicationcontext = ApplicationContext;
	}
	public void Postprocessbeanfactory (Configurablelistablebeanfactory beanfactory) throws beansexception {
	    Scanner Scanner = new Scanner ((Beandefinitionregistry) beanfactory);
	    Scanner.setresourceloader (this.applicationcontext);
	    Scanner.scan ("Org.wcong.test.spring.scan");
	}

4, Classpathbeandefinitionscanner implementation class scannerThe scanner inherited Classpathbeandefinitionscanner is the scanner that is defined by spring's built-in bean.
Includefilter defines a filter for a class, Newannotationtypefilter (Customizecomponent.class) represents a class that is only customizecomponent decorated. Scan only our own defined annotations.
Doscan in the bottom of the bag read to Beandefinitionholder, custom genericbeandefinition related features.
Public final static class Scanner extends Classpathbeandefinitionscanner {public Scanner (beandefinitionregistry regist
	  RY) {super (registry); public void Registerdefaultfilters () {This.addincludefilter () (New Annotationtypefilter Customizecomponent.class
	  )); Public set<beandefinitionholder> Doscan (String ... basepackages) {set<beandefinitionholder> beanDe
	      Finitions = Super.doscan (basepackages); for (Beandefinitionholder holder:beandefinitions) {genericbeandefinition definition = (genericbeandefinition
	          ) holder.getbeandefinition ();
	          Definition.getpropertyvalues (). Add ("Innerclassname", Definition.getbeanclassname ());
	      Definition.setbeanclass (Factorybeantest.class);
	  return beandefinitions; public boolean iscandidatecomponent (Annotatedbeandefinition beandefinition) {return super.iscandidatecomponent (beandefinition) && beandefinition.getmetadata (). Hasannotation (CustomizeComponent.class.getName ()); }
}

5, get our beanFactorybean is one of the more important classes in spring. It is described as follows

Interface to is implemented by objects used within a beanfactory which the are themselves.
If A bean implements this interface, it's used as a factory for ' an object to expose, not directly as a bean* instance tha T'll be exposed itself
An ordinary JavaBean is an instance of using a class directly, but if a bean inherits this excuse, it can be derived from defining the contents of the instance through the GetObject () method, and the GetObject () of the factorybeantest is by proxy the method of the original class. The method of customizing the class.
public static class Factorybeantest<t> implements Initializingbean, factorybean<t> {private String INNERCL
	  Assname;
	  public void Setinnerclassname (String innerclassname) {this.innerclassname = Innerclassname;
	      Public T GetObject () throws Exception {Class innerclass = Class.forName (innerclassname);
	      if (Innerclass.isinterface ()) {return (T) interfaceproxy.newinstance (innerclass);
	          else {Enhancer enhancer = new enhancer ();
	          Enhancer.setsuperclass (Innerclass);
	          Enhancer.setnamingpolicy (springnamingpolicy.instance);
	          Enhancer.setcallback (New Methodinterceptorimpl ());
	      Return (T) enhancer.create ();
	      } public class<?> Getobjecttype () {try {return class.forname (innerclassname);
	      catch (ClassNotFoundException e) {e.printstacktrace ();
	  return null; public Boolean Issingleton () {returnTrue public void Afterpropertiesset () throws Exception {}} public static class Interfaceproxy implements Invocatio Nhandler {public object Invoke (Object Proxy, Method method, object[] args) throws Throwable {System.out.printl
	      N ("ObjectProxy execute:" + method.getname ());
	  Return Method.invoke (proxy, args); public static <T> T newinstance (class<t> innerinterface) {ClassLoader ClassLoader = Innerinterfac
	      E.getclassloader ();
	      Class[] interfaces = new class[] {innerinterface};
	      Interfaceproxy proxy = new Interfaceproxy ();
	  Return (T) proxy.newproxyinstance (ClassLoader, interfaces, Proxy); } public static class Methodinterceptorimpl implements Methodinterceptor {public object Intercept (object o, Metho  D method, object[] objects, Methodproxy methodproxy) throws Throwable {System.out.println ("Methodinterceptorimpl:"
	      + Method.getname ());
      Return Methodproxy.invokesuper (O, objects);
}} 
6, main function
@Configuration public
class Customizescantest {public
   static void Main (string[] args) {
    Annotationconfigapplicationcontext Annotationconfigapplicationcontext = new        Annotationconfigapplicationcontext ();                
    Annotationconfigapplicationcontext.register (customizescantest.class);
    Annotationconfigapplicationcontext.refresh ();
    ScanClass1 Injectclass = Annotationconfigapplicationcontext.getbean (scanclass1.class);
    Injectclass.print ();
   }
Detailed code See Https://github.com/wcong/learn-java/blob/master/src/main/java/org/wcong/test/spring/CustomizeScanTest.java

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.