1. 程式人生 > >mybatis 中的註解

mybatis 中的註解

正常使用 mybatis時的寫法:

AddressMapper mapper = session.getMapper(AddressMapper.class);  (第一句)

Address address = mapper.queryById(101); (第二句)

Q1mapper 如何 通過sqlmap-XXX.xml 呼叫到 mysql

第一句 實際返回的 是MapperProxy

實際執行時:會執行到MapperProxy的invoke方法:

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); }

MapperMethod 下面

一個是:SqlCommand

String statementName = mapperInterface.getName() + "." + method.getName();

MappedStatement ms = null;

if (configuration.hasStatement(statementName)) {

ms = configuration.getMappedStatement(statementName);

}

name = ms.getId();

type = ms.getSqlCommandType();

另一個是:

MethodSignature

用於說明方法的一些資訊,主要有返回資訊

最終 方法執行時:execute(SqlSession sqlSession, Object[] args)

會執行:

Object param = method.convertArgsToSqlCommandParam(args);

result = sqlSession.selectOne(command.getName(), param);

Address address = session.selectOne("org.mybatis.example.AddressMapper.queryById", 101);

statement 標識: sqlmap-XXX.xml 下的namespace. id

/**

* Retrieve a single row mapped from the statement key and parameter.

* @param <T> the returned object type

* @param statement Unique identifier matching the statement to use.

* @param parameter A parameter object to pass to the statement.

* @return Mapped object

*/

<T> T selectOne(String statement, Object parameter);

底層基於

MappedStatement ms = configuration.getMappedStatement(statement);

MyBatis框架會把每一個節點(如:select節點、delete節點)生成一個MappedStatement類。

executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

## Q2 mybatisspring整合 後 發生了什麼?

整合後 XXXDAO  只要有介面就可以, 連實現都不用寫了。

也就是框架幫我們做了

AddressMapper mapper = session.getMapper(AddressMapper.class);

這一句。

呼叫時直接 呼叫所需方法即可。


 從MapperScannerConfigurer 開始

*   <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
*       <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
*       <!-- optional unless there are multiple session factories defined -->
*       <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
*   </bean>
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  if (this.processPropertyPlaceHolders) {
    processPropertyPlaceHolders();
}

  ClassPathMapperScanner scanner = new ClassPathMapperScanner(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();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

在Bean註冊到容器之後, 例項化 Bean 之前 掃描basePakage 下的介面。 將其 轉換為MapperFactoryBean

## 2 MapperFactoryBean

public abstract class DaoSupport implements InitializingBean {

   /** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@Override
public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
      // Let abstract subclasses check their configuration.
checkDaoConfig();
// Let concrete implementations initialize themselves.
try {
         initDao();
}
      catch (Exception ex) {
         throw new BeanInitializationException("Initialization of DAO failed", ex);
}
   }

## Mybatis中的

public <T> void addMapper(Class<T> type) {
  mapperRegistry.addMapper(type);
}
public <T> void addMapper(Class<T> type) {
  if (type.isInterface()) {
    if (hasMapper(type)) {
      throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
    boolean loadCompleted = false;
    try {
      knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
      // otherwise the binding may automatically be attempted by the
      // mapper parser. If the type is already known, it won't try.
下面兩行是關鍵:
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
      if (!loadCompleted) {
        knownMappers.remove(type);
}
    }
  }
}
public void parse() {
  String resource = type.toString();
  if (!configuration.isResourceLoaded(resource)) {
    loadXmlResource();
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());
parseCache();
parseCacheRef();
Method[] methods = type.getMethods();
    for (Method method : methods) {
      try {
        // issue #237
if (!method.isBridge()) {
          parseStatement(method);
}
      } catch (IncompleteElementException e) {
        configuration.addIncompleteMethod(new MethodResolver(this, method));
}
    }
  }
  parsePendingMethods();
}

以CacheNamespace註解解析為例:

private void parseCache() {
  CacheNamespace cacheDomain = type.getAnnotation(CacheNamespace.class);
  if (cacheDomain != null) {
    Integer size = cacheDomain.size() == 0 ? null : cacheDomain.size();
Long flushInterval = cacheDomain.flushInterval() == 0 ? null : cacheDomain.flushInterval();
Properties props = convertToProperties(cacheDomain.properties());
assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), flushInterval, size, cacheDomain.readWrite(), cacheDomain.blocking(), props);
}
}

## 涉及到的 Spring 知識點

### 1 spring容器、Bean配置資訊、Bean 實現類 和應用程式 4者之間的關係

### 2 spring中處理bean的具體過程



### 3 Spring鉤子方法和鉤子介面的使用詳解

https://www.jianshu.com/p/e22b9fef311c