赞
踩
MapperScan注解中有 @Import(MapperScannerRegistrar.class),MapperScannerRegistrar实现了接口ImportBeanDefinitionRegistrar。
通过MapperScannerRegistrar执行registerBeanDefinitions方法,扫描basePackages路径下的包,并把对应的mapper接口注入到spring的初始容器BeanDefinition,不过需要注意的是,这些接口的BeanDefinition的属性beanClass是 org.mybatis.spring.mapper.MapperFactoryBean
这一阶段就完成了mapper接口的初始注入
- @Override
- public SqlSessionFactory getObject() throws Exception {
- if (this.sqlSessionFactory == null) {
- afterPropertiesSet();
- }
-
- return this.sqlSessionFactory;
- }
- protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
-
- Configuration configuration;
-
- XMLConfigBuilder xmlConfigBuilder = null;
- if (this.configuration != null) {
- configuration = this.configuration;
- if (configuration.getVariables() == null) {
- configuration.setVariables(this.configurationProperties);
- } else if (this.configurationProperties != null) {
- configuration.getVariables().putAll(this.configurationProperties);
- }
- } else if (this.configLocation != null) {
- xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
- configuration = xmlConfigBuilder.getConfiguration();
- } else {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
- }
- configuration = new Configuration();
- if (this.configurationProperties != null) {
- configuration.setVariables(this.configurationProperties);
- }
- }
-
- if (this.objectFactory != null) {
- configuration.setObjectFactory(this.objectFactory);
- }
-
- if (this.objectWrapperFactory != null) {
- configuration.setObjectWrapperFactory(this.objectWrapperFactory);
- }
-
- if (this.vfs != null) {
- configuration.setVfsImpl(this.vfs);
- }
-
- if (hasLength(this.typeAliasesPackage)) {
- String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
- ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
- for (String packageToScan : typeAliasPackageArray) {
- configuration.getTypeAliasRegistry().registerAliases(packageToScan,
- typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
- }
- }
- }
-
- if (!isEmpty(this.typeAliases)) {
- for (Class<?> typeAlias : this.typeAliases) {
- configuration.getTypeAliasRegistry().registerAlias(typeAlias);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Registered type alias: '" + typeAlias + "'");
- }
- }
- }
-
- if (!isEmpty(this.plugins)) {
- for (Interceptor plugin : this.plugins) {
- configuration.addInterceptor(plugin);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Registered plugin: '" + plugin + "'");
- }
- }
- }
-
- if (hasLength(this.typeHandlersPackage)) {
- String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
- ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
- for (String packageToScan : typeHandlersPackageArray) {
- configuration.getTypeHandlerRegistry().register(packageToScan);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
- }
- }
- }
-
- if (!isEmpty(this.typeHandlers)) {
- for (TypeHandler<?> typeHandler : this.typeHandlers) {
- configuration.getTypeHandlerRegistry().register(typeHandler);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Registered type handler: '" + typeHandler + "'");
- }
- }
- }
-
- if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
- try {
- configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
- } catch (SQLException e) {
- throw new NestedIOException("Failed getting a databaseId", e);
- }
- }
-
- if (this.cache != null) {
- configuration.addCache(this.cache);
- }
-
- if (xmlConfigBuilder != null) {
- try {
- // 解析mybatis-config.xml配置
- xmlConfigBuilder.parse();
-
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
- }
- } catch (Exception ex) {
- throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
- } finally {
- ErrorContext.instance().reset();
- }
- }
-
- if (this.transactionFactory == null) {
- this.transactionFactory = new SpringManagedTransactionFactory();
- }
-
- configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
-
- if (!isEmpty(this.mapperLocations)) {
- for (Resource mapperLocation : this.mapperLocations) {
- if (mapperLocation == null) {
- continue;
- }
-
- try {
- // 解析 Mapper.xml文件,并封装成MappedStatement对象保存到Configuration
- XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
- configuration, mapperLocation.toString(), configuration.getSqlFragments());
- xmlMapperBuilder.parse();
- } catch (Exception e) {
- throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
- } finally {
- ErrorContext.instance().reset();
- }
-
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
- }
- }
- } else {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
- }
- }
-
- return this.sqlSessionFactoryBuilder.build(configuration);
- }

在生成mapper bean实例时,和其他Bean实例方式差不多,只不过应为mapper是接口,而他的beanClass属性是 org.mybatis.spring.mapper.MapperFactoryBean,所以对于其他常规bean还是有区别的,他会走FactoryBean的路线,通过factoryBean.getObject()返回代理对象,这里用到的是JDK动态代理,生成后填充到spring容器中。
代理几个关键的类
- public class MapperProxyFactory<T> {
-
- private final Class<T> mapperInterface;
- private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
-
- public MapperProxyFactory(Class<T> mapperInterface) {
- this.mapperInterface = mapperInterface;
- }
-
- public Class<T> getMapperInterface() {
- return mapperInterface;
- }
-
- public Map<Method, MapperMethod> getMethodCache() {
- return methodCache;
- }
-
- @SuppressWarnings("unchecked")
- protected T newInstance(MapperProxy<T> mapperProxy) {
- return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
- }
-
- public T newInstance(SqlSession sqlSession) {
- final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
- return newInstance(mapperProxy);
- }
-
- }

- public class MapperProxy<T> implements InvocationHandler, Serializable {
-
- private static final long serialVersionUID = -6424540398559729838L;
- private final SqlSession sqlSession;
- private final Class<T> mapperInterface;
- private final Map<Method, MapperMethod> methodCache;
-
- public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
- this.sqlSession = sqlSession;
- this.mapperInterface = mapperInterface;
- this.methodCache = methodCache;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (Object.class.equals(method.getDeclaringClass())) {
- try {
- return method.invoke(this, args);
- } catch (Throwable t) {
- throw ExceptionUtil.unwrapThrowable(t);
- }
- }
- final MapperMethod mapperMethod = cachedMapperMethod(method);
- return mapperMethod.execute(sqlSession, args);
- }
-
- private MapperMethod cachedMapperMethod(Method method) {
- MapperMethod mapperMethod = methodCache.get(method);
- if (mapperMethod == null) {
- mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
- methodCache.put(method, mapperMethod);
- }
- return mapperMethod;
- }
-
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。