Análisis del código fuente del proxy de creación de Spring AOP

Análisis del código fuente del proxy de creación de Spring AOP

Programación de tecnología Java TSMYK

Prefacio

En el último artículo, el análisis del código fuente del método de anotación Spring AOP ha obtenido el potenciador correspondiente del bean, luego de eso, se puede crear el proxy correspondiente. La capa inferior de Spring AOP es el proxy dinámico JDK y el proxy CGLIB. Se puede usar JDK Proxy dinámico, cuando usar Proxy CGLIB, echemos un vistazo al código fuente.


// AbstractAutoProxyCreator.java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //......
    // 获取的增强器
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }
    //............
    return bean;
}

Crear proxy createProxy


protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    // ....
    ProxyFactory proxyFactory = new ProxyFactory();
    //复制当前类的一些属性
    proxyFactory.copyFrom(this);
    // 如果在配置文件中配置的aop标签的属性proxy-target-class为false,
    if (!proxyFactory.isProxyTargetClass()) {
        // 是否需要代理当前类而不是代理接口,根据preserveTargetClass属性来判断Boolean.TRUE.equals(bd.getAttribute("preserveTargetClass")
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            // 如果代理的是接口,则添加代理接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    // 对增强器进行包装,有些增强是通过拦截器等方式来实现的,所以这里统一封装为 Advisor 进行处理
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 加入增强器
    proxyFactory.addAdvisors(advisors);
    // 设置要代理的类
    proxyFactory.setTargetSource(targetSource);
    // 用户自定义代理
    customizeProxyFactory(proxyFactory);
    // 该属性用来控制代理工厂被配置以后,是否还允许修改通知,默认为false
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    // 创建代理
    return proxyFactory.getProxy(getProxyClassLoader());
}

// 添加接口代理
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
    Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
    boolean hasReasonableProxyInterface = false;
    //....
    if (hasReasonableProxyInterface) {
        for (Class<?> ifc : targetInterfaces) {
            proxyFactory.addInterface(ifc);
        }
    }
    else {
        proxyFactory.setProxyTargetClass(true);
    }
}

Mejora de encapsulación. En Spring, algunas mejoras se implementan a través de interceptores, por lo que aquí hay encapsulación unificada para Advisor para su procesamiento, correspondiente al método buildAdvisors ():


protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
    //解析所有的 InterceptorName
    Advisor[] commonInterceptors = resolveInterceptorNames();

    List<Object> allInterceptors = new ArrayList<>();
    if (specificInterceptors != null) {
        // 添加参数传进来的,即我们自定义的增强
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        if (commonInterceptors.length > 0) {
            // 添加拦截器
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            }
            else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    //把拦截器包装为Advisor
    Advisor[] advisors = new Advisor[allInterceptors.size()];
    for (int i = 0; i < allInterceptors.size(); i++) {
        // wrap包装
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}

//wrap包装
// 仅仅对 Advisor 和 Advice进行包装
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    // 如果本来就是 Advisor,则直接返回
    if (adviceObject instanceof Advisor) {
        return (Advisor) adviceObject;
    }
    // 类型不正确,异常
    if (!(adviceObject instanceof Advice)) {
        throw new UnknownAdviceTypeException(adviceObject);
    }
    Advice advice = (Advice) adviceObject;
    if (advice instanceof MethodInterceptor) {
        // MethodInterceptor 类型使用 DefaultPointcutAdvisor 封装
        return new DefaultPointcutAdvisor(advice);
    }
    // 如果存在 Advisor 的适配器,也需要包装
    for (AdvisorAdapter adapter : this.adapters) {
        if (adapter.supportsAdvice(advice)) {
            return new DefaultPointcutAdvisor(advice);
        }
    }
    throw new UnknownAdviceTypeException(advice);
}

Crear proxy getProxy


return proxyFactory.getProxy(getProxyClassLoader());

public Object getProxy(ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

createAopProxy () :

Aquí se juzgará si el método de creación de proxy es utilizar el proxy dinámico de JDK o el proxy de CGLIB.


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //这里初步判断代理的创建方式,如果不满足则直接使用 JDK 动态代理,如果满足条件,则进一步在判断是否使用 JKD 动态代理还是 CGLIB 代理
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("......");
        }
        // 如果代理的是接口或者设置代理的类就是当前类,则使用 JDK 动态代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 否则使用 CGLIB 代理
        return new ObjenesisCglibAopProxy(config);
    }
    // 条件不满足CGBLIB的方式直接使用JDK动态代理
    else {
        return new JdkDynamicAopProxy(config);
    }
}
  1. Hay tres condiciones si aquí:

config.isOptimize (): se usa para controlar si el proxy creado por CGLIB usa una estrategia de optimización agresiva, actualmente solo se usa para el proxy CGLIB

  1. config.isProxyTargetClass (): En el análisis del código fuente de las anotaciones de Spring AOP, aprendimos que podemos forzar a Spring a usar CGLIB para el proxy, siempre que el atributo proxy-target-class esté establecido en verdadero en el archivo de configuración, como : <aop: aspectj- autoproxy expose-proxy = "true" proxy-target-class = "true" />, si este atributo está configurado, se usará CGLIB para crear el proxy

    1. hasNoUserSuppliedProxyInterfaces (config): si hay una interfaz de proxy, si no hay una interfaz de proxy, use CGLIB para proxy

    Si se cumple una de estas tres condiciones, se juzgará nuevamente, si la clase que necesita ser proxy es una interfaz o si está configurada para proxy de la clase actual, si es así, se usará el proxy dinámico JDK, de lo contrario Se utilizará el proxy CGLIB.

1. Si la clase de proxy implementa la interfaz, Spring usa el proxy dinámico JDK de forma predeterminada, pero se puede configurar para forzar el uso de proxy CGLIB
2. El proxy dinámico JDK solo puede usar interfaces proxy pero no clases
3. Clase proxy CGLIB, a través de herencia, es el objetivo La clase genera subclases y reescribe métodos para implementar el proxy. No puede
usar proxy de clases o métodos finales . 4. Para el uso del proxy dinámico JDK y el proxy CGLIB, consulte los detalles de uso de la función Spring AOP

A continuación, observe el proceso de creación del proxy dinámico JDK y el proxy CGLIB:

Proxy dinámico JDK


return new JdkDynamicAopProxy(config);

// JdkDynamicAopProxy.java
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
    this.advised = config;
}

Obtenga el método de proxy getProxy () a través del proxy dinámico JDK:


public Object getProxy(ClassLoader classLoader) {
    // 获取代理类的接口
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    // 处理 equals , hashcode 方法
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // 创建代理
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

Como puede ver, no hay diferencia entre el uso de Spring de JDK para crear un proxy y el JDK que usamos para crear un proxy. Ambos se crean usando Proxy.newProxyInstance; sabemos que el proxy dinámico JDK tiene un método de invocación para ejecutar el objetivo. JdkDynamicAopProxy implementa la interfaz InvocationHandler, por lo que también reescribirá este método e implantará mejoras en este método:


public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;
    // 目标类
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        // 如果接口没有定义 equals 方法且当前方法是 equals 方法,则不会增强,直接返回
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            return equals(args[0]);
        }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // 如果接口没有定义 hashCode方法且当前方法是 hashCode方法,则不会增强,直接返回
            return hashCode();
        }
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // 如果方法所在的类和Advised是同一个类或者是父类子类关系,则直接执行
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }
        // 返回值
        Object retVal;

        // 这里对应的是expose-proxy属性的应用,把代理暴露处理
        // 目标方法内部的自我调用将无法实施切面中的增强,所以在这里需要把代理暴露出去
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 获取该方法的拦截器
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        //如果方法的拦截器为空,则直接执行目标方法,避免创建 MethodInvocation 对象
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 执行目标方法:method.invoke(target, args)
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // 把所有的拦截器封装在ReflectiveMethodInvocation中,以便于链式调用 
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 执行拦截器链
            retVal = invocation.proceed();
        }
        // ..........
        return retVal;
    }
    finally {
      // .            
    }
}

El método de mejora se ejecuta en el método de interceptor de ejecución. Por ejemplo, la mejora previa se ejecuta antes del método y la mejora posterior se ejecuta después del método. El método de continuación es el siguiente:


public Object proceed() throws Throwable {
    //当执行完所有增强方法后执行目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // method.invoke(target, args)
        return invokeJoinpoint();
    }
     // 获取下一个要执行的拦截器
    Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // 动态匹配
        InterceptorAndDynamicMethodMatcher dm = interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        // 如果能够匹配,则执行拦截器的方法,
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            // 比如 @After @Before 对应的增强器(拦截器)的方法
            // 比如 @After 对应的增强器 AspectJAfterAdvice 的invoke方法为:MethodInvocation.proceed();
            return dm.interceptor.invoke(this);
        }
        else {
            // 如果动态匹配失败,则跳过该拦截器,执行下一个拦截器
            return proceed();
        }
    }
    else {
        // 普通拦截器,直接调用
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

La implantación mejorada se completa en este método. La lógica principal es que cada método tendrá una cadena de interceptor, que llamamos mejora en AOP, y luego ejecutará cada cadena de interceptor en un bucle, cuando todos los interceptores se ejecutan Después de eso, el método objetivo será ejecutado. Por ejemplo, el potenciador AspectJAfterAdvice correspondiente a @After, el potenciador AspectJAroundAdvice correspondiente a @Around, etc.

Lo anterior es un proceso en el que Spring implementa AOP a través del proxy dinámico JDK.

Agente CGLIB

ObjenesisCglibAopProxy hereda de CglibAopProxy


return new ObjenesisCglibAopProxy(config)

public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
    this.advised = config;
    this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}

El método getProxy de CglibAopProxy es el siguiente:


public Object getProxy(ClassLoader classLoader) {
    // 代理的目标类
    Class<?> rootClass = this.advised.getTargetClass();
    Class<?> proxySuperClass = rootClass;
    if (ClassUtils.isCglibProxyClass(rootClass)) {
        proxySuperClass = rootClass.getSuperclass();
        Class<?>[] additionalInterfaces = rootClass.getInterfaces();
        for (Class<?> additionalInterface : additionalInterfaces) {
            this.advised.addInterface(additionalInterface);
        }
    }
    // 创建并配置 CGLIB Enhancer
    Enhancer enhancer = createEnhancer();
    if (classLoader != null) {
        enhancer.setClassLoader(classLoader);
        if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isCla***eloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
        }
    }
    enhancer.setSuperclass(proxySuperClass);
    enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
    enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

    // 设置拦截器
    Callback[] callbacks = getCallbacks(rootClass);
    Class<?>[] types = new Class<?>[callbacks.length];
    for (int x = 0; x < types.length; x++) {
        types[x] = callbacks[x].getClass();
    }
    enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
    enhancer.setCallbackTypes(types);

    //生成代理类和创建代理
    return createProxyClassAndInstance(enhancer, callbacks);
}

// 生成代理类和创建代理
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    enhancer.setInterceptDuringConstruction(false);
    enhancer.setCallbacks(callbacks);
    return (this.constructorArgs != null && this.constructorArgTypes != null ?
            enhancer.create(this.constructorArgTypes, this.constructorArgs) :
            enhancer.create());
}

A partir del método anterior, podemos ver que Sping usa CGLIB para crear clases de proxy y objetos de proxy, tal como lo usamos nosotros. Se crean usando Enhancer.create (). Lo principal aquí es configurar el interceptor, que se implementa a través de el método getCallbacks () de la siguiente manera:


private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    //expose-proxy 属性
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isFrozen = this.advised.isFrozen();
    boolean isStatic = this.advised.getTargetSource().isStatic();

    // 将拦截器封装在 DynamicAdvisedInterceptor 中
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

    //暴露代理
    Callback targetInterceptor;
    if (exposeProxy) {
        targetInterceptor = (isStatic ?
                new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
    }
    else {
        targetInterceptor = (isStatic ?
                new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
    }
    // 将拦截器 aopInterceptor 进入到 Callback 中 
    Callback[] mainCallbacks = new Callback[] {
            aopInterceptor,  // for normal advice
            targetInterceptor,  // invoke target without considering advice, if optimized
            new SerializableNoOp(),  // no override for methods mapped to this
            targetDispatcher, this.advisedDispatcher,
            new EqualsInterceptor(this.advised),
            new HashCodeInterceptor(this.advised)
    };
    // ..............
    return callbacks;
}

Sabemos que cuando se usa CGLIB para implementar la función de proxy, cuando se ejecuta el proxy, se llamará al método de intercepción, que es similar al método de invocación del proxy dinámico de JKD; el método de intercepción de CGLIB en Spring es el siguiente, el El método está en DynamicAdvisedInterceptor, del proxy anterior, utilícelo para encapsular el interceptor, es una subclase de CglibAopProxy:


public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy){
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    // 目标类
    TargetSource targetSource = this.advised.getTargetSource();
    // 处理 expose-proxy 属性,暴露代理
    if (this.advised.exposeProxy) {
        oldProxy = AopContext.setCurrentProxy(proxy);
        setProxyContext = true;
    }
    target = targetSource.getTarget();
    Class<?> targetClass = (target != null ? target.getClass() : null);

    // 获取拦截器链
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    // 返回值
    Object retVal;

    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        // 如果拦截器为空则直接执行目标方法
        retVal = methodProxy.invoke(target, argsToUse);
    }
    else {
        //封装拦截器链并执行
        retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
    }
    // 处理返回值类型
    retVal = proce***eturnType(proxy, target, method, retVal);
    return retVal;
    // .....................
}

CGLIB usa CglibMethodInvocation para encapsular la cadena del interceptor, que es una clase interna de CglibAopProxy:


private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

    @Nullable
    private final MethodProxy methodProxy;

    public CglibMethodInvocation(Object proxy, Object target, Method method,Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

        super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);

        this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
                method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
                !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
                methodProxy : null);
    }

    // proceed 方法会调用该方法来执行
    @Override
    protected Object invokeJoinpoint() throws Throwable {
        if (this.methodProxy != null) {
            return this.methodProxy.invoke(this.target, this.arguments);
        }
        else {
            return super.invokeJoinpoint();
        }
    }
}

Cuando se invoca el método continue, el procesamiento es el mismo que el del JDK, excepto que después de que se ejecutan todos los interceptores, el método de destino de ejecución llama al invokeJoinpoint de CglibMethodInvocation para ejecutarlo;

Debido a que CglibMethodInvocation hereda de ReflectiveMethodInvocation, y JDK usa ReflectiveMethodInvocation para ejecutar, el método invokeJoinpoint de ReflectiveMethodInvocation es: method.invoke (target, args)

Lo anterior es el principio de que Spring usa un proxy dinámico JDK y un proxy CGLIB para implementar AOP.

Supongo que te gusta

Origin blog.51cto.com/15077536/2608544
Recomendado
Clasificación