Mybaits Zatan

Foreword

Use mybaits in the spring is simply not to be too simple and requires only a few configuration, a DAO interface and can be completed once a mapper.xml database interaction. Behind the often complex simple realization, now let's explore that principle inside it.

How is the integration of spring and mybaits

 spring is a framework, mybaits is a framework, a framework in order to work, must have a call entry. springboot entrance we should be very clear, as follows 

@SpringBootApplication(scanBasePackages = "com.example.demo")
@MapperScan("com.example.demo.repository.dao")
public class StartApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }
}

main method which calls SpringApplication.run (StartApplication.class, args), began a series of springboot initialization process. And mybaits we do not seem to call ah, that is how it initialized.

@MapperScan("com.example.demo.repository.dao")

Take a closer look, we seem to be using the mybaits bag inside MapperScan comment. It is this which

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
  ///省略
}

The key lies in the above Notes @Import (MapperScannerRegistrar.class), with the @ Import, spring can be MapperScannerRegistrar registered as bean, also can achieve a special kind of interface do treatment, and then see what is MapperScannerRegistrar

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

  void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
        //省略
  }
  void setResourceLoader(ResourceLoader resourceLoader)
  {
      //省略
  }
//省略 }

MapperScannerRegistrar ResourceLoaderAware implements the interface, can be obtained in the resource loader ResourceLoader instantiated. It also implements ImportBeanDefinitionRegistrar, you can get BeanDefinitionRegistry, have the ability to register BeanDefinition.

And from the main flow of the spring, in the spring after the initialization container, the container will call the refresh method, and then after a series of calls will execute registerBeanDefinitions method MapperScannerRegistrar began mybaits registered BeanDefinition the trip.

void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    //省略
    List<String> basePackages = new ArrayList<>();
    //省略
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("basePackages"))
            .filter(StringUtils::hasText)
            .collect(Collectors.toList()));
    //省略
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }

The above code is mainly to get basePackages we define value, and then start scanning method is executed scanner.doScan eligible class, and then register to BeanDefinition. Once registered, mybaits also performs processBeanDefinitions method BeanDefinition list

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
      //省略 
      definition.setBeanClass(this.mapperFactoryBeanClass);
       //省略
      definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
       //省略
      definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
        explicitFactoryUsed = True ; 
      } 
     // optional 
    } 
  }

Can be seen from the above, mybaits processBeanDefinitions in which the BeanClass to mapperFactoryBean, also linked to sqlSessionTemplate sqlSessionFactory and properties. After this, DAO we define the interface becomes quietly lying in wait getbean the container.

How to become an example DAO interface definition

As already described probably become BeanDefinition DAO interface, but if you want to get the instance, but also through a process getBean, the general BeanDefinition only through reflection can become an example of. But mybaits registered BeanDefinition types are changed to mapperFactoryBean, as follows

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
   //省略
  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }
   //省略
}

MapperFactoryBean achieve the FactoryBean seen from the above, such BeanDefinition not get reflected by the examples, but of FactoryBean.getObject obtained by (). So this time, DAO interface instance of the process by the Spring of getMapper to Mybaits responsible. getMapper processing is as follows

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

//mapperProxyFactory
  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<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

In the above code, mybaits for the proxy interface generation. And we need to pay attention to what is to generate proxy, MapperProxy code is as follows

public class MapperProxy<T> implements InvocationHandler, Serializable {

 //省略
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
}

MapperProxy agents are interfaces, so invoke to perform is actually execute MapperMethod of execution, as follows

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

The code above is simply, mybaits based label mapper.xml defined, processed differently, and returns the results.

summary

This article describes a simple step by step how to become DAO interface instance can be invoked in the spring and mybaits in. Which ImportBeanDefinitionRegistrar and FactoryBean is the key point, mybaits by two key classes integrated into the spring. If we do a similar framework integrated into the spring, you can also learn about in this way.

Guess you like

Origin www.cnblogs.com/caizl/p/10946071.html