代理模式源码解析(jdk+spring+mybatis)

首先是java.lang.reflect,也就是我们刚刚使用的Proxy这个类,这里面coding的时候,也就是debug的时候,

这个就是代理的一个典型应用,还有proxyFactoryBean,这个是一个代理的工厂bean,他呢首先是一个bean

@SuppressWarnings("serial")
public class ProxyFactoryBean extends ProxyCreatorSupport
		implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
		
他是一个什么bean呢,它是代理的工厂类,这么一个bean,那这里面的实现我们就不扩展来讲了,有兴趣的小伙伴可以来这里

看一下,那这个代理工厂bean呢,核心方法就是getObject这么一个方法,里面进行各种判断,同时在这里面生成一个单例对象,

生成一个PrototypeInstance,那我们在使用Spring的时候

	/**
	 * Return a proxy. Invoked when clients obtain beans from this factory bean.
	 * Create an instance of the AOP proxy to be returned by this factory.
	 * The instance will be cached for a singleton, and create on each call to
	 * {@code getObject()} for a proxy.
	 * @return a fresh AOP proxy reflecting the current state of this factory
	 */
	@Override
	@Nullable
	public Object getObject() throws BeansException {
		initializeAdvisorChain();
		if (isSingleton()) {
			return getSingletonInstance();
		}
		else {
			if (this.targetName == null) {
				logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
						"Enable prototype proxies by setting the 'targetName' property.");
			}
			return newPrototypeInstance();
		}
	}
	
不加prototype这种声明的话,他就是一个单例对象,那如果声明成prototype这种类型呢,他就是一个多例对象,也就是每次重新

调用它的时候呢,都会生成一个新的instance,那这个类呢比较复杂,有兴趣的可以来这里看一下,这个类也是Spring的一个核心类,

那Spring实现AOP的话,还有两个重要的类,分别是JdkDynamicAopProxy,它是AOP包下的,这里就是对JDK的动态代理进行了一些封装,

那JDK的动态代理在这里,final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

我们还要看一下CglibAopProxy,这些都是在Spring中的一些体现

class CglibAopProxy implements AopProxy, Serializable

那在Mybatis当中当然也有使用代理模式,我们来看一下MapperProxyFactory这么一个类,他呢是Mybatis下边的,从名字就可以看出来,

它是Mapper的代理工厂,我们主要看一下这个方法

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
	
这里面传入了SqlSession,哪里调用他了呢,在MapperRegistry里边,有一个getMapper方法,这里面调用了工厂的newInstance,

那这个getMapper又在哪里调用了呢,
	
  @SuppressWarnings("unchecked")
  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);
    }
  }
	
他呢是在Configuration这里边,
	
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
	
getMapper调用了,Configuration里面是对应的各种配置,然后我们看一下里面的声明,方法声明,里面有addMapper,还有

处理一些ResultMap,比如ResultMap,这里面处理ResultMap,各种配置的处理,
	
  public ResultMap getResultMap(String id) {
    return resultMaps.get(id);
  }
	
再回到工厂里面我们看一下,这里面是怎么做的呢,首先它通过具体的各种参数,包括methodCache,

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

这个就是接口,然后创建一个MapperProxy,然后又调用了newInstance(mapperProxy);这个方法,这个方法就是

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

可以看到呢,Proxy.newProxyInstance,和我们刚刚写动态代理调用的方法是一样的,里面传入了ClassLoader,还有对应的interface,

还有MapperProxy,也就是这里生成了一个代理对象,然后把它进行返回,那我们来看一下MapperProxy这里面是怎么写的,进来,

我们主要关注一个invoke方法,

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

invoke方法自然是InvocationHandler这个接口所要实现的方法

public class MapperProxy<T> implements InvocationHandler, Serializable

接着来看,因为我们动态代理也实现了invoke方法, if (Object.class.equals(method.getDeclaringClass()))

这里进行一个判断,判断这个类型是不是Object类型,如果是的就直接返回,return method.invoke(this, args);

然后重点看这两行

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

对Method进行一个Cache,怎么Cache的呢,看一下,

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

这里像不像我们这里的享元模式呢,这里面可以理解为享元模式,return就开始执行execute,也就是说,通过这种方式,只需要编写

对应的Mapper.java的interface就可以了,我们用户订单,产品的Mapper呢,通过工具生成一个ProductMapper.java,

而当执行这个接口里面的insert,update操作的时候呢,就会给MapperProxy这个代理,然后就会调用invoke这个方法,如果没有

Object.class.equals(method.getDeclaringClass()),

final MapperMethod mapperMethod = cachedMapperMethod(method);

这里首先通过享元进行一个Cache,提高速度,mapperMethod.execute方法,我们进来看一下

  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);
        }
        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;
  }
  
这里面进行了各种判断,如果是INSERT,UPDATE,DELETE,SELECT,各种判断,还有FLUSH等等,然后把返回结果返回回去,

那这一块就是代理模式在Mybatis里面的应用,而且使用的是JDK的原生动态代理,通过实现InvocationHandler这个接口

就可以看出来,那代理模式在各种框架中,应用非常广泛,也是因为他的动态特性,把代理模式学好,为以后学习其他框架,

也是非常非常有帮助的,相信在代理模式这里,学到的不仅仅是代理模式,还有代理模式在源码中的应用

猜你喜欢

转载自blog.csdn.net/Leon_Jinhai_Sun/article/details/91388945