为了账号安全,请及时绑定邮箱和手机立即绑定

代理模式

标签:
Java

定义和类型

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


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
228
获赞与收藏
996

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消