美文网首页java
0x09.动态代理和Spring AOP原理简介

0x09.动态代理和Spring AOP原理简介

作者: 0x70e8 | 来源:发表于2018-08-14 14:10 被阅读54次

[TOC]

动态代理

JDK的动态代理是通过实现目标类的接口来创建代理类,借助里式替换原则通过聚合目标类,在接口方法内部委托目标类的接口方法来达到控制对目标方法的访问的目的。

CGLIB则是通过继承来实现代理,具体逻辑是继承目标类创建一个子类,然后重写目标方法,在内部调用父类方法来达到代理的目的。

CGLIB示例

  • 目标类:
public class MyClass {
    public void method() {
        System.out.println("MyClass.method()");
    }
}
  • Testcase
package aop.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class Main {

    @Test
    public void testCGLIB() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyClass.class);
        enhancer.setCallback(new MethodInterceptor() {

            @Override
            public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)
                                                                                 throws Throwable {
                System.out.println("before");
                System.out.println("method Name:" + method.getName());
                // 调用父类方法来完成实际业务逻辑
                proxy.invokeSuper(target, args);
                System.out.println("after");
                return null;
            }
        });
        MyClass my = (MyClass) enhancer.create();
        my.method();
    }

    
}

JDK动态代理示例

  • 实现接口的目标类
public interface MyInterface {
    void method();

}

public class MyClassWithInterface implements MyInterface {
    @Override
    public void method() {
        System.out.println("MyClassWithInterface.method()");
    }
}

  • TestCase
    @Test
    public void testJDKProxy() {
        final MyClassWithInterface target = new MyClassWithInterface();
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("before");
                        // 实际的业务逻辑还是委托给目标类的
                        method.invoke(target, args);
                        System.out.println("after");
                        return null;
                    }
                });
        proxy.method();
    }

Spring AOP

Spring AOP是基于动态代理的,代理方式包括以上两种,所以只能拦截方法,且不能拦截未实现接口的final class。

AOP生成代理的入口

在Spring中,bean的创建是交给IOC容器的,从上面动态代理的使用来看,基于接口的JDK代理的代理对象的生成是需要持有目标对象的。AOP是基于BeanPostProcessor在createBean逻辑中的回调,涉及的主要后处理器为org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator,调用时机是在目标bean实例化之后,执行initializeBean()初始化内部中执行postProcessAfterInitialization()回调。

调用栈为:doCreateBean()->initializeBean()->applyBeanPostProcessorsAfterInitialization()->org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization()->wrapIfNecessary()->createProxy.

  • wrapIfNecessary

开启了AOP自动代理之后,所有bean的创建都会进入这一步判断是否需要wrap,因为BeanPostProcessor是全局的。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // Create proxy if we have advice. // 判断当前的Bean是否有相关的切面
        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;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

判断Bean是否需要代理

是否需要代理的的依据就是wrapIfNecessary方法中的getAdvicesAndAdvisorsForBean(),通过检查本bean是否有关联切面来判断是否需要代理。判断切面关联的逻辑:

    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

重点在于查找和当前bean相关的aspect,如何查找的?

    protected List<Advisor> findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        // 内部逻辑是检查所有注册的Aspect bean,取到其中的Advice定义,封装到Advisor中(InstantiationModelAwarePointcutAdvisor)
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }

findCandidateAdvisors返回所有备选的advisor,下一步进行筛选:findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName),最后进行其他处理,返回合格的advisor,继续下一步的代理创建。

生成代理

代理对象的生成入口Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));,详细生成过程是通过ProxyFactory工厂对象生成。

protected Object createProxy(
            Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (Advisor advisor : advisors) {
            proxyFactory.addAdvisor(advisor);
        }

        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }

        return proxyFactory.getProxy(getProxyClassLoader());
    }

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

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface()) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

具体的生成策略有两种:JdkDynamicAopProxyObjenesisCglibAopProxy,就是前述的两种动态代理方式。

  • cglib
public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
        }

        try {
            Class<?> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

            Class<?> proxySuperClass = rootClass;
            if (ClassUtils.isCglibProxyClass(rootClass)) {
                proxySuperClass = rootClass.getSuperclass();
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }

            // Validate the class, writing log messages as necessary.
            validateClassIfNecessary(proxySuperClass, classLoader);

            // Configure CGLIB Enhancer...
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                if (classLoader instanceof SmartClassLoader &&
                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));

            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // fixedInterceptorMap only populated at this point, after getCallbacks call above
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);

            // Generate the proxy class and create a proxy instance.
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        catch (CodeGenerationException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (IllegalArgumentException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                    this.advised.getTargetClass() + "]: " +
                    "Common causes of this problem include using a final class or a non-visible class",
                    ex);
        }
        catch (Exception ex) {
            // TargetSource.getTarget() failed
            throw new AopConfigException("Unexpected AOP exception", ex);
        }
    }
  • jdk
    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);
    }

相关文章

  • Spring AOP 实现原理

    Spring AOP 实现原理 静态代理 众所周知 Spring 的 AOP 是基于动态代理实现的,谈到动态代理就...

  • Spring学习系列--3.AOP

    Spring Aop Aop面向切面编程 Aop入门动态代理 动态代理,其实与Aop的原理有些相似,可以用动态代理...

  • 2018-01-31

    spring aop @(iJava)[spring framework] [toc] aop底层原理采用动态代理...

  • SSH框架之Spring进阶AOP面向切面编程(三)

    第一节:AOP简介 第二节:AOP的作用 第三节:Spring底层的AOP实现原理 动态代理: JDK动态代理:只...

  • 0x09.动态代理和Spring AOP原理简介

    [TOC] 动态代理 JDK的动态代理是通过实现目标类的接口来创建代理类,借助里式替换原则通过聚合目标类,在接口方...

  • Spring AOP内部调用失效问题

    Spring AOP基本原理 Spring AOP是基于动态代理机制实现的,通过动态代理机制生成目标对象的代理对象...

  • Spring之使用XML配置Spring AOP

    1.aop的原理 Spring AOP底层主要使用了JDK动态代理和cglib动态代理。具体可看文章设计模式之代理...

  • java动态代理

    目录: 简介 jdk动态代理 cglib动态代理 jdk动态代理与cglib的区别 应用spring的aop 简介...

  • 2018-09-16

    AOP的XML配置: AOP的先关术语: Spring底层的AOP实现原理 动态代理: JDK动态代理:只能对实现...

  • Spring AOP(一)

    Spring AOP实现原理 动态代理: 利用核心类Proxy和接口InvocationHandler(基于代理模...

网友评论

    本文标题:0x09.动态代理和Spring AOP原理简介

    本文链接:https://www.haomeiwen.com/subject/twfvbftx.html