Deepen proxy mode, Mybaits how to call interface

How do Mybaits call interface?

There is no doubt, dynamic agency, it will deepen the impression through some source


1. Source article

1) generate the proxy

The first test code, scanning and Mybaits related package configuration files have been written

public class MapperTest {
    @Test
    public void testMapper() throws IOException, MyException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:/spring/applicationContext-dao.xml");
        SqlSessionFactory factory = (SqlSessionFactory) context.getBean("sqlSessionFactory");
        //可DEBUG这一行,这里创建并返回了Mapper的代理
        TestMapper mapper = factory.openSession().getMapper(TbItemMapper.class);
        //发送一个查询请求,这一行揭示了如何做到调用接口
        mapper.selectByExample(new TestMapper ());
    }
}

Here you do not have to look, know where you can enter

public class MapperRegistry {
 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        //检索Mapper是否注册代理工厂
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                //进入这一行,就可以看到代理的产生
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }
        //此处省略其他代码
}

Note that overriding method, the subject has been assembled the interface information in the configuration file, also equipped with a buffer

  • MapperProxy is a InvocationHandler
  • He then generate real JDK proxy object and return
    to this dynamic proxy object has been generated
public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;
    private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();

  protected T newInstance(MapperProxy<T> mapperProxy) {
        //JDK代理
        ***return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);***
    }
   
     //DEBUG进入在这一行
    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
    //此处省略其他代码
}

How 2) method call

invoke method receives the method call, only two things

  • Create a class and cache MapperMethod
  • Call MapperMethod.execute () method
//实现了InvocationHandler
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;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //如果调用了Object类的方法
        if (Object.class.equals(method.getDeclaringClass())) {
            try {
                return method.invoke(this, args);
            } catch (Throwable var5) {
                throw ExceptionUtil.unwrapThrowable(var5);
            }
        } else {
            //缓存并创建一个MapperMethod对象,KEY method VALUE mapperMethod
            MapperMethod mapperMethod = this.cachedMapperMethod(method);
            //把session和方法参数委托给MapperMethod
            return mapperMethod.execute(this.sqlSession, args);
        }
    }

    private MapperMethod cachedMapperMethod(Method method) {
        MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
        if (mapperMethod == null) {
            //用接口信息,方法信息,配置信息构造MapperMethod 
            mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
            this.methodCache.put(method, mapperMethod);
        }

        return mapperMethod;
    }
}

MapperMethod class did what? (Command mode?)

  • The method call information packed into SqlCommand
  • The method of xml configuration information packaged MethodSignature
  • Send SQL statements to obtain the results returned
public class MapperMethod {
 private final MapperMethod.SqlCommand command;
    private final MapperMethod.MethodSignature method;

    public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
        this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
        this.method = new MapperMethod.MethodSignature(config, method);
    }
     //进入这个方法,匹配指令执行SQL
    public Object execute(SqlSession sqlSession, Object[] args) {
        Object param;
        Object result;
        if (SqlCommandType.INSERT == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
        } else if (SqlCommandType.UPDATE == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
        } else if (SqlCommandType.DELETE == this.command.getType()) {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
        } else {
            if (SqlCommandType.SELECT != this.command.getType()) {
                throw new BindingException("Unknown execution method for: " + this.command.getName());
            }
            if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                this.executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (this.method.returnsMany()) {
                result = this.executeForMany(sqlSession, args);
            } else if (this.method.returnsMap()) {
                result = this.executeForMap(sqlSession, args);
            } else {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(this.command.getName(), param);
            }
        }

        if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
            throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
        } else {
            return result;
        }
    }
}


Naturally, this kind of thing after it and we use JDBC, assembling SQL, call the SQL, the assembly returns the result
but the dynamic agent here and in the past I've seen different past InvocationHandler need to hold a proxy object reference, but here no, because Mapper itself does not exist to achieve, it is that got me thinking
---

2. deepen proxy mode

What agents are? I thought the transition (not necessarily correct)

Phase One: Acquaintance AOP
this problem when I encountered beginner AOP was my understanding followed AOP, the purpose is to generate a proxy methods to enhance, add business logic before and after methods, interfaces, so the agency is a way enhanced mode, and the transaction is suitable for this.
After all, that is, before and after the open method of adding the transaction, the transaction is committed.
The Proxy.newProxyInstance (classloader, interface, invocationhandler) this API, get our hands I can not read.

Phase II: to strengthen the impression that
the Internet and read some articles, to understand the static agent, was perceived dynamic proxy, is the use of Java reflection mechanism, follow the agent's idea of a realization, the purpose is to decouple.
The argument is quite clear Proxy.newProxyInstance

  • classloader and interface reflection to create a proxy class runtime
  • invocationhandler hold a proxy object reference, is responsible for forwarding the request processing
    course, I think this is over

Phase III: Proxy mode
cursory read it again "headfirst design mode", before we know too much play acting, the agent is more like a Kagemusha (puppet), but a method of enhancing the tip of the iceberg, such as the protection agent in the proxy class If you call in to write XXX method throws an exception, and so on.

Phase IV: to broaden their horizons
I see the source code is certainly not much, so Mybaits proxy really surprised me, for there is no implementation of the interface class can also represent the method and parameters, with their class to be processed, information and methods SQL statement is bound to invoke methods on the implementation of the relevant statement, the original SQL statement is so called, of course, much more complex than what I said.


3. Summary

Mapper interface 1.Mybaits dynamic proxy method calls to implement
dynamic proxy 2.Mapper not approach, but forwarded to MapperMethod.
3.Mapper interface does not require the implementation class, but require a related XML configuration, since the matching process according to the XML configuration MapperMethod

Guess you like

Origin www.cnblogs.com/haon/p/11353434.html