继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

代理模式

慕标5832272
关注TA
已关注
手记 1254
粉丝 231
获赞 1002

定义和类型

webp

使用场景

webp

优点

webp

缺点

webp

扩展

webp

Spring 代理

webp

代理速度对比

webp

相关设计模式

webp

2 实战

2.1 静态代理

webp


webp


webp


webp


看 UML 图
展开包节点


webp


webp

image.png

动态代理

webp


webp


webp

源码分析

 /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.
     *
     * <p>{@code Proxy.newProxyInstance} throws
     * {@code IllegalArgumentException} for the same reasons that
     * {@code Proxy.getProxyClass} does.
     *
     * @param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
     * @throws  IllegalArgumentException if any of the restrictions on the
     *          parameters that may be passed to {@code getProxyClass}
     *          are violated
     * @throws  SecurityException if a security manager, <em>s</em>, is present
     *          and any of the following conditions is met:
     *          <ul>
     *          <li> the given {@code loader} is {@code null} and
     *               the caller's class loader is not {@code null} and the
     *               invocation of {@link SecurityManager#checkPermission
     *               s.checkPermission} with
     *               {@code RuntimePermission("getClassLoader")} permission
     *               denies access;</li>
     *          <li> for each proxy interface, {@code intf},
     *               the caller's class loader is not the same as or an
     *               ancestor of the class loader for {@code intf} and
     *               invocation of {@link SecurityManager#checkPackageAccess
     *               s.checkPackageAccess()} denies access to {@code intf};</li>
     *          <li> any of the given proxy interfaces is non-public and the
     *               caller class is not in the same {@linkplain Package runtime package}
     *               as the non-public interface and the invocation of
     *               {@link SecurityManager#checkPermission s.checkPermission} with
     *               {@code ReflectPermission("newProxyInPackage.{package name}")}
     *               permission denies access.</li>
     *          </ul>
     * @throws  NullPointerException if the {@code interfaces} array
     *          argument or any of its elements are {@code null}, or
     *          if the invocation handler, {@code h}, is
     *          {@code null}
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException {        // 检查代理对象非空
        Objects.requireNonNull(h);     
        // 安全检查
        final Class<?>[] intfs = interfaces.clone();        final SecurityManager sm = System.getSecurityManager();        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

webp


生成代理类实现方法

  • 检查接口数量

  • 代理缓存

 /**
     * Look-up the value through the cache. This always evaluates the
     * {@code subKeyFactory} function and optionally evaluates
     * {@code valueFactory} function if there is no entry in the cache for given
     * pair of (key, subKey) or the entry has already been cleared.
     *
     * @param key       possibly null key
     * @param parameter parameter used together with key to create sub-key and
     *                  value (should not be null)
     * @return the cached value (never null)
     * @throws NullPointerException if {@code parameter} passed in or
     *                              {@code sub-key} calculated by
     *                              {@code subKeyFactory} or {@code value}
     *                              calculated by {@code valueFactory} is null.
     */
    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;        while (true) {            if (supplier != null) {                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();                if (value != null) {                    return value;
                }
            }            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);                if (supplier == null) {                    // successfully installed Factory
                    supplier = factory;
                }                // else retry with winning supplier
            } else {                if (valuesMap.replace(subKey, supplier, factory)) {                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }            final Constructor<?> cons = cl.getConstructor(constructorParams);            final InvocationHandler ih = h;            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {                    public Void run() {
                        cons.setAccessible(true);                        return null;
                    }
                });
            }            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();            if (t instanceof RuntimeException) {                throw (RuntimeException) t;
            } else {                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {            throw new InternalError(e.toString(), e);
        }
    }

Spring 使用示例

Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP。

Spring自己的AOP实现在于ProxyFactoryBean。先看下使用案例

  • 接口MyService


    webp

  • 实现类MyServiceImpl


    webp

  • 通知MyBeforeAdvice


    webp

  • 然后就是xml的配置:

<bean id="aServiceImpl" class="com.lg.aop.service.impl.AServiceImpl"/>
    <bean id="myBeforAdvice" class="com.lg.aop.MyBeforeAdvice"/>

    <bean class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interfaces" value="com.lg.aop.service.AService"/>
        <property name="target">
            <ref bean="aServiceImpl"/>
        </property>
         <property name="interceptorNames">  
            <list>  
                <value>myBeforAdvice</value>  
            </list>  
        </property>  
    </bean>

然后就可以使用了:

    @Autowired
    private AService aService;    @Test
    public void testAOP(){
        aService.barA();
    }

运行这个单元测试,然后你就会看到报如下错误:

No qualifying bean of type [com.lg.aop.service.AService] is defined: expected single matching bean but found 2: aServiceImpl,org.springframework.aop.framework.ProxyFactoryBean#0

对于接口MyService,有两个实现类MyServiceImpl和ProxyFactoryBean所生产的代理类
所以我们不能使用@Autowired(它是按类型注入),要使用按名称注入,我们怎么获取ProxyFactoryBean所产生的代理类的名称呢?
其实就是ProxyFactoryBean配置的名称。因为ProxyFactoryBean实现了FactoryBean接口

webp


对于这种接口从容器中获取该bean,不是获取的本身而是获取其getObject方法所返回的值,看FactoryBean的文档:


/**
 * Interface to be implemented by objects used within a {@link BeanFactory}
 * which are themselves factories. If a bean implements this interface,
 * it is used as a factory for an object to expose, not directly as a bean
 * instance that will be exposed itself.
 *
 * <p><b>NB: A bean that implements this interface cannot be used as a
 * normal bean.</b> A FactoryBean is defined in a bean style, but the
 * object exposed for bean references ({@link #getObject()} is always
 * the object that it creates.

所以通过beanName找到了ProxyFactoryBean,然而不是返回该对象,而是返回他的getObject方法的返回值,所以我们通过ProxyFactoryBeanid就可以获取到它所产生的代理对象,所以更改如下:

<bean  id="MyServiceImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
...

在使用注入的时候按名称注入

@Resource(name="MyServiceImplProxy")
private AService aService;

然后就可以正常运行了如下:

Run my before adviceMyServiceImpl.barA()

然后我们就要源码分析下这一过程,先看下是如何产生代理对象的,在ProxyFactoryBean的getObject方法中:


webp


重点1:就是根据我们配置的interceptorNames来获取对应的bean,并转化成Advisor

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {        if (this.advisorChainInitialized) {            return;
        }        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
            }            // Globals can't be last unless we specified a targetSource using the property...
            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                throw new AopConfigException("Target required after globals");
            }            // Materialize interceptor chain from bean names.
            for (String name : this.interceptorNames) {                if (logger.isTraceEnabled()) {
                    logger.trace("Configuring advisor or advice '" + name + "'");
                }                if (name.endsWith(GLOBAL_SUFFIX)) {                    if (!(this.beanFactory instanceof ListableBeanFactory)) {                        throw new AopConfigException(                                "Can only use global advisors or interceptors with a ListableBeanFactory");
                    }
                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                }                else {                    // If we get here, we need to add a named interceptor.
                    // We must check if it's a singleton or prototype.
                    Object advice;                    if (this.singleton || this.beanFactory.isSingleton(name)) {                        // Add the real Advisor/Advice to the chain.
                        advice = this.beanFactory.getBean(name);
                    }                    else {                        // It's a prototype Advice or Advisor: replace with a prototype.
                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                        advice = new PrototypePlaceholderAdvisor(name);
                    }
                    addAdvisorOnChainCreation(advice, name);
                }
            }
        }        this.advisorChainInitialized = true;
    }

advisorChainInitialized:标示是否已初始化,若已初始化则不再进行初始化

webp


然后就是将interceptorNames转化成Advisor

webp


根据interceptorNames所包含的字符串到容器中进行查找,如果含有*则表示进行一定的匹配,符合的都会纳入

webp


<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">    <property name="target" ref="service"/>
    <property name="interceptorNames">
        <list>
            <value>global*</value>
        </list>
    </property></bean><bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/><bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>

这中间也经过了AdviceAdvisor的转换

   /**
     * Invoked when advice chain is created.
     * <p>Add the given advice, advisor or object to the interceptor list.
     * Because of these three possibilities, we can't type the signature
     * more strongly.
     * @param next advice, advisor or target object
     * @param name bean name from which we obtained this object in our owning
     * bean factory
     */
    private void addAdvisorOnChainCreation(Object next, String name) {        // We need to convert to an Advisor if necessary so that our source reference
        // matches what we find from superclass interceptors.
        Advisor advisor = namedBeanToAdvisor(next);        if (logger.isTraceEnabled()) {
            logger.trace("Adding advisor with name '" + name + "'");
        }
        addAdvisor(advisor);
    }
private Advisor namedBeanToAdvisor(Object next) {        try {            return this.advisorAdapterRegistry.wrap(next);
        }
        }
    }
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {        if (adviceObject instanceof Advisor) {            return (Advisor) adviceObject;
        }        if (!(adviceObject instanceof Advice)) {            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;        if (advice instanceof MethodInterceptor) {            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }        for (AdvisorAdapter adapter : this.adapters) {            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {                return new DefaultPointcutAdvisor(advice);
            }
        }        throw new UnknownAdviceTypeException(advice);
    }

这个包裹过程,采用了适配器模式
之后又是和其他的AOP方式接轨了,设置一些列要实现的接口和参数,使用DefaultAopProxyFactory先创建出AopProxy,然后就可以调用AopProxy的getProxy方法来获取代理对象了
这种方式实现的AOP还是比较麻烦的,同时配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean
所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程

JdkDynamicAopProxy使用实例

代理类是由默认AOP代理工厂DefaultAopProxyFactorycreateAopProxy方法产生的

  • 如果代理对象是接口类型,则生成JdkDynamicAopProxy代理

  • 否则生成ObjenesisCglibAopProxy代理,ObjenesisCglibAopProxy代理是继承于CglibAopProxy

从熟悉的入手,选择JdkDynamicAopProxy分析

构造器

webp


一个final类,不能被继承和实现


webp


JdkDynamicAopProxy依赖于AdvisedSupport,根据config配置信息创建动态代理对象

getProxy

实现AopProxy接口,在创建代理时,既可以采用默认的类加载器,也可以指定特定的类加载器
JDK动态代理的代理对象是接口类型,先获取被代理对象的完整接口、根据指定的类加载器以及实现的调用处理器应用静态方法Proxy.newProxyInstance创建代理对象

    @Override
    public Object getProxy() {        return getProxy(ClassUtils.getDefaultClassLoader());
    }    @Override
    public Object getProxy(ClassLoader classLoader) {        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }    /**
     * Finds any {@link #equals} or {@link #hashCode} method that may be defined
     * on the supplied set of interfaces.
     * @param proxiedInterfaces the interfaces to introspect
     */
    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {        for (Class<?> proxiedInterface : proxiedInterfaces) {
            Method[] methods = proxiedInterface.getDeclaredMethods();            for (Method method : methods) {                if (AopUtils.isEqualsMethod(method)) {                    this.equalsDefined = true;
                }                if (AopUtils.isHashCodeMethod(method)) {                    this.hashCodeDefined = true;
                }                if (this.equalsDefined && this.hashCodeDefined) {                    return;
                }
            }
        }
    }

invoke

该类实现了InvocationHandler 接口,必然实现invoke方法

    /**
     * Implementation of {@code InvocationHandler.invoke}.
     * <p>Callers will see exactly the exception thrown by the target,
     * unless a hook method throws an exception.
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;        Object target = null;        try {            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {                // The target does not implement the hashCode() method itself.
                return hashCode();
            }            if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }            Object retVal;            if (this.advised.exposeProxy) {                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }            // May be null. Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            // 得到被代理对象的类名
            target = targetSource.getTarget();            if (target != null) {
                targetClass = target.getClass();
            }            // Get the interception chain for this method
            // 根据被代理类名和方法名得到通知链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);            // 如果通知链为空,则直接反射调用被代理方法,
            if (chain.isEmpty()) {                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                // 反射执行被代理方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
            }            else {                // 否则创建代理方法
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);                // Proceed to the joinpoint through the interceptor chain.
                // 执行代理方法
                retVal = invocation.proceed();
            }            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();            if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                retVal = proxy;
            } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {                throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
            }            return retVal;
        }        finally {            if (target != null && !targetSource.isStatic()) {                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }            if (setProxyContext) {                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

反射执行被代理方法是调用工具类AopUtils中方法invokeJoinpointUsingReflection实现的,具体如下:

    /**
     * Invoke the given target via reflection, as part of an AOP method invocation.
     * @param target the target object
     * @param method the method to invoke
     * @param args the arguments for the method
     * @return the invocation result, if any
     * @throws Throwable if thrown by the target method
     * @throws org.springframework.aop.AopInvocationException in case of a reflection error
     */
    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable {        // Use reflection to invoke the method.
        try {
            ReflectionUtils.makeAccessible(method);            return method.invoke(target, args);
        }        catch (InvocationTargetException ex) {            // Invoked method threw a checked exception.
            // We must rethrow it. The client won't see the interceptor.
            throw ex.getTargetException();
        }        catch (IllegalArgumentException ex) {            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                    method + "] on target [" + target + "]", ex);
        }        catch (IllegalAccessException ex) {            throw new AopInvocationException("Could not access method [" + method + "]", ex);
        }
    }

创建代理方法是通过ReflectiveMethodInvocation实现的,然后调用proceed()方法执行拦截链和被代理方法。ReflectiveMethodInvocation实现了Joinpoint接口,其构造器如下:

    /**
     * Construct a new ReflectiveMethodInvocation with the given arguments.
     * @param proxy the proxy object that the invocation was made on
     * @param target the target object to invoke
     * @param method the method to invoke
     * @param arguments the arguments to invoke the method with
     * @param targetClass the target class, for MethodMatcher invocations
     * @param interceptorsAndDynamicMethodMatchers interceptors that should be applied,
     * along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime.
     * MethodMatchers included in this struct must already have been found to have matched
     * as far as was possibly statically. Passing an array might be about 10% faster,
     * but would complicate the code. And it would work only for static pointcuts.
     */
    protected ReflectiveMethodInvocation(
            Object proxy, Object target, Method method, Object[] arguments,
            Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {        this.proxy = proxy;        this.target = target;        this.targetClass = targetClass;        this.method = BridgeMethodResolver.findBridgedMethod(method);        this.arguments = arguments;        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

ReflectiveMethodInvocation调用proceed方法执行代理,proceed方法是在Joinpoint接口中定义的,ReflectiveMethodInvocation中进行了实现。具体实现如下:

    @Override
    public Object proceed() throws Throwable {        //  We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {                return dm.interceptor.invoke(this);
            }            else {                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }        else {            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

从上面分析源码大致可以了解Spring AOP 动态代理的设计思想,采用类加载器根据接口产生代理方法,代理方法是在原方法的基础上加上通知链,以实现AOP功能。当执行方法时,判断该方法通知链是否为空,若为空,则通过反射直接调用原方法;若不为空,则产生代理方法,执行代理方法

MapperProxyFactory


webp


在MyBatis中Mapper文件中的方法和xml配置文件中的SQL映射最重要的3个类就是
MapperProxyFactory
MapperProxy
MapperMethod
弄懂这3个类你就理解Mapper接口与SQL的映射,为什么是接口,没有实例类也可以完成注入或者调用。


在调用MyBatis的addMapper的时候如果你跟踪源码就会最终跟到MapperRegistry的addMapper中有如下的语句:


webp


type就是Mapper接口

MapperProxyFactory

一看名字我们就知道肯定是一个工厂类,就是为了生成MapperProxy
其实MapperProxyFactory也非常简单

2个成员

webp


就是Mapper接口


webp


对Mapper接口中的方法和方法的封装类(MapperMethod)的映射
MapperMethod主要:处理Mapper接口中方法的注解,参数,和返回值

2个newInstance方法

工厂方法

  • public方法
    参数SqlSession:处理执行一次SQL的过程
    public的newInstance就是new了一个MapperProxy,然后调用了protected的newInstance

    webp

  • protected的newInstance
    protected简单明了,就是使用Java Proxy的工厂方法生成一个了Mapper接口的代理类

    webp


    MapperRegistry中调用了该方法

    webp

MapperProxy

MapperProxy实现了InvocationHandler
MapperProxy#invoke则把Method包装成了MapperMethod

  • MapperMethod处理Mapper接口方法与xml映射的关系,处理方法的注解,参数,返回值,参数与SQL语句中的参数的对应关系
    MapperProxy实现了InvocationHandler接口,基于Java动态代理


    webp

首先检查如果是Object类中方法就直接调用
如果不是就把方法包装成MapperMethod
因为把Method处理为MapperMethod还是一个比较重的操作,所以这里做了缓存处理

webp

享元模式实例



作者:芥末无疆sss
链接:https://www.jianshu.com/p/7596ae4398db


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP