Why does Mybatis interface not need an implementation class

Yeah, why not? Guess what, maybe the dynamic proxy generates the corresponding class of the interface

When did that happen

That’s what I get when I get the Mapper by class

   UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Copy the code

Through the above we can get to the code below

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);/ / 1
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession); / / 2
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: "+ e, e); }}Copy the code
  1. Get the MapperProxyFactory of the corresponding type
  2. Create a MapperProxy, our UserMapper, on which we can invoke the methods we defined in our interface

How is the proxy generated?

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy); / / 1
  }
Copy the code
  1. Enter newInstance as follows
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
Copy the code

Here we return to the proxy.newProxyInstance code, which is the JDK’s method for creating a Proxy.

Wait, generate Proxy MapperProxyFactory to come

KnownMappers. Get (type) MapperProxyFactory

, mapperInterface

, mapperInterface

Where does MapperProxyFactory come from, SqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); We go all the way to parseConfiguration method, where mapperElement(root.evalNode(“mappers”)); The method is to parse the Mapper file and register the MapperProxyFactory to MapperRegistry. Trace all the way to the following method, in MapperRegistry.


 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<>(type)); / / 1
      MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
      parser.parse();
      loadCompleted = true;
    } finally {
      if(! loadCompleted) { knownMappers.remove(type); }}}Copy the code
  1. Trace all the way toknownMappers.put(type, new MapperProxyFactory<>(type));Method we found, when we created the proxy, was usedgetMethod,MapperProxyFactoryThat’s where I added it.

conclusion

Today we go from creating proxy objects for Mapper interfaces to how to create objects.

From initializing the configuration file to creating a MapperProxyFactory, to using the JDK dynamic proxy API to create proxy objects based on the type or corresponding MapperProxyFactory when the Mapper is obtained. So we can call the method.

Demonstrate relevant code

Welcome to discuss learning

Use JDK apis for dynamic proxy and source code analysis

Mybatis plugin and dynamic proxy

The interviewer asks why the Mybatis interface does not require an implementation class

How to control the order in which Mybatis enhances logic