首先是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这个接口
就可以看出来,那代理模式在各种框架中,应用非常广泛,也是因为他的动态特性,把代理模式学好,为以后学习其他框架,
也是非常非常有帮助的,相信在代理模式这里,学到的不仅仅是代理模式,还有代理模式在源码中的应用