作者 | 波哥
审校 | 孙淑娟
如果老铁们对Spring框架足够熟悉,整合MyBatis其实很容易理解,当然这里假定老铁们也已经熟悉了MyBatis框架。
在我们正常的应用开发过程中,使用MyBatis一般分为如下几个步骤:
1.在配置类上增加MAPPerScan注解,例如:@MapperScan(basePackages = {“com.test.dao”},annotationClass = Mapper.class);
2.在basePackages指定的目录下创建待MyBatis读取的接口文件,例如:
@Mapperpublic interface TestMapper ......
3.在Service或者其他地方使用该Mapper来操作数据库。
使用起来是很简单的,但是有没有老铁想过,为什么做了这么一个简单的配置,这个Mapper就能操作数据库了?按理说这个Mapper是个接口,应该是不能被创建才对啊!如果你有这个疑问,证明你是个爱思考的好童鞋。
咱们直接进入主题。Spring要与MyBatis整合,简单来说只要解决如下两个问题:
一、Spring如何知道哪些类应该被管理?
要让Spring去管理Bean的生命周期,首先需要对应的类被Spring扫描到,并且生成DeanDefinition,然后基于BeanDefinition生成Bean。下面对Spring生成BeanDefinition的方式做个小总结:
我们分析源码,第一步得找到它的入口,Spring整合MyBatis的入口,毫无疑问是MapperScan这个注解,在MapperScan注解上包含Import(MapperScannerRegistrar.class)注解,Spring整合MyBatis正是用了Import和ImportBeanDefinitionRegistrar的方式。我们先通过一张流程图来了解下整体流程,然后再慢慢品。
我们来看MapperScannerRegistrar这个类的继承关系图:

MapperScannerRegistrar是ImportBeanDefinitionRegistrar的实现类,Spring会去调用这个类的registerBeanDefinitions方法添加beanDefinition,这个方法中具体做了些什么呢:
获取MapperScan注解的配置信息,比如basePackages、annotationClass,basePackages表示需要扫描的路径,annotationClass则是指定了增加了这种注解类的类需要被Spring进行管理,比如增加了Mapper注解的类需要被Spring管理。
生成MapperScannerConfigurer这个类型的beanDefinition,并且把MapperScan注解的配置信息添加到该beanDefinition的属性集合中。
后续Spring就会基于这个MapperScannerConfigurer做一系列文章,看下它的继承关系:
它是BeanDefinitionRegistryPostProcessor的实现类,是一个BeanFactory后置处理器,Spring会调用该类的postProcessBeanDefinitionRegistry方法来添加beanDefinition的操作,MapperScannerConfigurer这个类中具体实现如下:
它定义了ClassPathMapperScanner这个扫描器,然后使用这个扫描器来扫描类,扫描哪些类呢?扫描有Mapper注解的类,看它的关系知道,它是ClassPathBeanDefinitionScanner的子类,而spring则是使用ClassPathBeanDefinitionScanner来进行扫描的。
为什么ClassPathMapperScanner能够扫描到带有Mapper注解的类呢?看上面代码,就是通过调用registerFilters方法来添加includeFilter(实际类型是:TypeFilter),这个就是Spring提供的扩展点,让咱们自己来指定需要被扫描的类,这里使用的是MappScan注解中annotationClass属性配置的注解类型,我们这里配置了Mapper,所以调用scan方法开启扫描后,Spring就会将包含Mapper注解的类扫描为BeanDefinition。注意这里的扫描能力还是调用Spring的扫描器来实现的,ClassPathMapperScanner并没有修改,只是当扫描完成后,ClassPathMapperScanner会对扫描出的BeanDefinition进行重新处理,主要是把原来的BeanClass修改成了MapperFactoryBean.class:
而这个MapperFactoryBean是FactoryBean的实现类,老铁们,FactoryBean这种Bean有什么特点?这个可是面试的高发点哦。
做个小小的总结:Spring扫描到有Mapper注解的类,生成BeanDefinition,并且将这一类BeanDefinition的BeanClass的值修改为MapperFactoryBean,也就是说它的类型不再是咱们自己编写的Mapper接口了,而是一个FactoryBean,这样Spring就能做妖了。
二、Mapper注解的类是接口
那如何实例化呢?
到这一步,其实老铁们也大概清楚了,Spring在实例化Mapper实例时,实际上首先会实例化MapperFactoryBean,然后再调用它的getObject方法。我们知道在Java里面接口是肯定不能被实例化的,那这个被实例化的对象只能是一个代理对象,所以我们有理由猜想这个getObject方法应该是用来创建代理对象的。要创建代理对象,得从以下两个方面着手:
1.准备工作
这里Spring准备的是接口类型和创建代理对象的代理工厂。具体如何准备的呢?来看上述MapperFactoryBean类型的整体继承关系:
它实现了InitializingBean,于是可以知道,在MapperFactoryBean初始化完成后,Spring会调用它的afterPropertiesSet方法,从而会执行到checkDaoConfig方法:
在该方法中调用configuration的addMapper方法,这个方法里面到底做了啥?
看出门道了吗?其实就是使用Mapper的接口类型作为key,MapperProxyFactory做为value,然后添加到mapperRegistry对象的Map集合中,注意这个type同时也是MapperProxyFactory对象的构造参数哦。
2.实例化
上述动作已经准备好了,接下来就应该是创建了。Spring在创建完成MapperFactoryBean对象后,最终会调用它的getObject方法来获得真实的对象:
getObject方法中,会调用getMapper方法,该方法中从knowMappers这个Map集合中拿到MapperProxyFactory对象,这个对象不就是我们在准备阶段添加的嘛!它就是用来创建代理对象的工厂。
从上面代码中也不难看出,确实是为咱们自己的接口创建了代理对象,而代理类的处理类则是MapperProxy对象,也就是说对所有接口对象的调用,都会进入MapperProxy的Invoke方法,至此Spring成功对接MyBatis。
作者介绍
波哥,互联行业从业10余年,先后担任项目总监及架构师。目前专攻技术,喜欢研究技术原理。技术全面,主攻java,精通JVM底层机制及Spring全家桶底层框架原理,熟练掌握当前主流的中间件、服务网格等技术原理。
Spring的MVC模式工作原理
1:spring3开发效率高于struts2:spring3 mvc可以认为已经100%零配置3:struts2是类级别的拦截, 一个类对应一个request上下文,springmvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应所以说从架构本身上 spring3 mvc就容易实现restful url 而struts2的架构实现起来要费劲因为struts2 action的一个方法可以对应一个url而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了 4:spring3mvc的方法之间基本上独立的,独享request response数据请求数据通过参数获取,处理结果通过ModelMap交回给框架方法之间不共享变量而struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的这不会影响程序运行,却给我们编码 读程序时带来麻烦 5:由于Struts2需要针对每个Request进行封装,把Request,Session等Servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全。所以在原则上,是比较耗费内存的
hibernate导jar包
最小必要包为,,, , , ,, ,, Hibernate3.2 核心包作用 包 作用 说明 标准的JTA API 必要 日志功能 必要 集合类 必要 Another Tool for Language Recognition(antlr) 必要 XML配置和映射解释器 必要 核心库 必要 ASM字节码库 如果使用“cglib”则必要 ASM字节码库 如果使用“cglib”则必要 EHCache缓存 如果没有其它的缓存,则它是必要的 CGLIB 字节码解释器 如果使用“cglib”则必要以下包可选 版本检查 TreeCache JAXP API C3PO JDBC链接池 JCA API 使用TreeCache时必要 jacc-1_ JACC 库 Javassist 字节码解释器 JAAS API jdbc2_ JDBC扩展API Ant antlr支持 cleanimports SAX parser JDK版本低于1.4时必要 Jaxen 如果想提高启动性能则去使用 Ant junit support ant swing support Proxool JDBC连接池 使用TreeCache需要
hibernate4与oracle11g整合中利用hibernate的查询语句怎么查到的Admin为空,在数据库里能查到,代码如下:
直接这样写试试Query query=(from Adminwhere username=‘+username+“’”);(query:+query);Admin u=(Admin) ();
发表评论