mybatis的源代码解析(3)----------动态代理的使用

在mybatis中,实现我们的mapper的定义一般如下:

public interface UserMapper {
    /**
     * 新增用戶
     * 
     * @param user
     * @return
     * @throws Exception
     */
    public int insertUser(UserBean user) throws Exception;

}

使用时,获取如下:

/**
     * 新增用户
     */
    private static void insertUser() {

        SqlSession session = DBTools.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        UserBean user = new UserBean("懿", "1314520", 7000.0);
        try {
            mapper.insertUser(user);
            System.out.println(user.toString());
            session.commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
        }
    }

 

UserMapper是一个interface,那么是如何生成它的对象呢,原理就是使用了动态代理的功能。session.getMapper返回的是一个MapperProxy。MapperProxy的定义如下:
public class MapperProxy<T> implements InvocationHandler, Serializable 
{
}

 

DBTools.getSession()返回的是DefaultSqlSession。DefaultSqlSession的getMapper是一个模板函数,
public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
    }
configuration就是上一篇中讲到configuration类。configuration的getMapper定义如下:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }
MapperRegistry的getMapper的定义如下:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        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);
            }
        }
    }

从上一篇的讲解中,可以知道knownMappers存储的就是imterface mapper和其对应的MapperProxyFactory工厂类。

MapperProxyFactory的定义如下:

public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
        return this.mapperInterface;
    }

    public Map<Method, MapperMethod> getMethodCache() {
        return this.methodCache;
    }

    protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
}

MapperProxyFactory的newInstance生成了一个MapperProxy 动态代理对象,对于动态代理,其中必须要包含一个实现了interface的实现类,才能运行成功,在mybratis中,Mapper的动态代理包含的实现类都是SqlSession的子类,默认是DefaultSqlSession。

MapperProxy的定义如下:

public class MapperProxy<T> implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -6424540398559729838L;
    private final SqlSession sqlSession;------------mapper interface最终要调用的实现类
    private final Class<T> mapperInterface;--------mapper interface的类
    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 {
        try {
            if(Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }

            if(this.isDefaultMethod(method)) {
                return this.invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }

        MapperMethod mapperMethod = this.cachedMapperMethod(method);
        return mapperMethod.execute(this.sqlSession, args);
    }

    private MapperMethod cachedMapperMethod(Method method) {
        MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
        if(mapperMethod == null) {
            mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
            this.methodCache.put(method, mapperMethod);
        }

        return mapperMethod;
    }

    @UsesJava7
    private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
        Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(new Class[]{Class.class, Integer.TYPE});
        if(!constructor.isAccessible()) {
            constructor.setAccessible(true);
        }

        Class<?> declaringClass = method.getDeclaringClass();
        return ((Lookup)constructor.newInstance(new Object[]{declaringClass, Integer.valueOf(2)})).unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
    }

    private boolean isDefaultMethod(Method method) {
        return (method.getModifiers() & 1033) == 1 && method.getDeclaringClass().isInterface();
    }
}

 

当调用mapper.insertUser(user);函数时,就会进入到MapperProxy的invoke函数

 

posted @ 2017-08-02 18:00  王久勇  阅读(157)  评论(0)    收藏  举报