SpringAop

近期打算把Spring源码系统性的刷一遍,话不多说,那就先从Aop开始吧~~~
一、动态代理:

1、cglib的动态代理


     UserService target =new UserService();

    // 通过cglib技术

    Enhancer enhancer =new Enhancer();

    enhancer.setSuperclass(UserService.class);

    // 定义额外逻辑,也就是代理逻辑

    enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {

    @Override

    public Objectintercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {

        System.out.println("before...");

        Object result = methodProxy.invoke(target, objects);

        System.out.println("after...");

        return result;

    }

}});

// 动态代理所创建出来的UserService对象

UserService userService = (UserService) enhancer.create();

//System.out.println(userService);

// 执行这个userService的test方法时,就会额外会执行一些其他逻辑

userService.test();

上面是通过cglib来实现的代理对象的创建,是基于父子类的,被代理类(UserService)是父类,代理类是子类,代理对象就是代理类的实例对象。

2、JDK的动态代理

        UserService target = new UserService();

        // UserInterface接口的代理对象
        Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("before...");
                Object result = method.invoke(target, args);
                System.out.println("after...");
                return result;
            }
        });

        UserInterface userService = (UserInterface) proxy;
        userService.test();

jdk的动态代理必须依赖接口,所以生产的代理对象和被代理对象是兄弟关系,再采用依赖注入时必须使用接口接收代理对象。

二、ProxyFactory
上面我们介绍了两种动态代理技术,那么在Spring中进行了封装,封装出来的类叫做ProxyFactory,表示是创建代理对象的一个工厂,使用起来会比上面的更加方便,比如:

        UserService target = new UserService();

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new MethodInterceptor(){

            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }

        });

        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();

通过ProxyFactory,我们可以不再关心到底是用cglib还是jdk动态代理了,ProxyFactory会帮我们去判断,如果UserService实现了接口,那么ProxyFactory底层就会用jdk动态代理,如果没有实现接口,就会用cglib技术,上面的代码,就是由于UserService实现了UserInterface接口,所以最后产生的代理对象是UserInterface类型。

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() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

同时我们也看一下Advice的接口定义

/**
 * Tag interface for Advice. Implementations can be any type
 * of advice, such as Interceptors.
 *
 * @author Rod Johnson
 * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
 */
public interface Advice {

}

三、Advisor
跟Advice类似的还有一个Advisor的概念,一个Advisor是有一个Pointcut和一个Advice组成的,通过Pointcut可以指定要需要被代理的逻辑,比如一个UserService类中有两个方法,按上面的例子,这两个方法都会被代理,被增强,那么我们现在可以通过Advisor,来控制到具体代理哪一个方法,比如:

        UserService target = new UserService();

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvisor(new PointcutAdvisor() {
            @Override
            public Pointcut getPointcut() {
                return new StaticMethodMatcherPointcut() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        return method.getName().equals("test");
                    }
                };
            }

            @Override
            public Advice getAdvice() {
                return new MethodInterceptor() {
                    @Override
                    public Object invoke(MethodInvocation invocation) throws Throwable {
                        System.out.println("before...");
                        Object result = invocation.proceed();
                        System.out.println("after...");
                        return result;
                    }
                };
            }

            @Override
            public boolean isPerInstance() {
                return false;
            }
        });

        UserInterface userService = (UserInterface) proxyFactory.getProxy();
        userService.test();

四、Spring中创建代理对象的方式
下面我们来看一下Spring中创建代理对象的方式,首先来看ProxyFactoryBean:

    @Bean
    public ProxyFactoryBean userServiceProxy(){
        UserService userService = new UserService();

        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        return proxyFactoryBean;
    }
    @Resource(name = "userServiceProxy")
    private UserInterface userInterface;

    @PostConstruct
    public void print(){
        userInterface.test();
    }

ProxyFactoryBean实现了FactoryBean接口。FactoryBean是Spring中一个比较重要的切入点,在bean的初始化过程中Spring会调用getObject()方法获取到代理对象,并放入bean容器,所以当我们通过@Resource(name = "userServiceProxy")注解拿到的其实是UserInterface的代理对象

         /**
     * 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.info("Using non-singleton proxies with singleton targets is often undesirable. " +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }

ProxyFactoryBean得自己指定被代理的对象,那么我们可以通过BeanNameAutoProxyCreator来通过指定某个bean的名字,来对该bean进行代理。

    @Bean
    public MethodInterceptor myAroundAdvise(){
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }

@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
   BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
   beanNameAutoProxyCreator.setBeanNames("userSe*");
   beanNameAutoProxyCreator.setInterceptorNames("myAroundAdvise");
   beanNameAutoProxyCreator.setProxyTargetClass(true);

    return beanNameAutoProxyCreator;
}

BeanNameAutoProxyCreator中实现了getAdvicesAndAdvisorsForBean()方法

protected Object[] getAdvicesAndAdvisorsForBean(
            Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

        if (this.beanNames != null) {
            for (String mappedName : this.beanNames) {
                if (FactoryBean.class.isAssignableFrom(beanClass)) {
                    if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
                        continue;
                    }
                    mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
                }
                if (isMatch(beanName, mappedName)) {
                    return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
                }
                BeanFactory beanFactory = getBeanFactory();
                if (beanFactory != null) {
                    String[] aliases = beanFactory.getAliases(beanName);
                    for (String alias : aliases) {
                        if (isMatch(alias, mappedName)) {
                            return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
                        }
                    }
                }
            }
        }
        return DO_NOT_PROXY;
    }

该方法就会根据beanName找到对应的Interceptors,而BeanNameAutoProxyCreator本身继承于AbstractAutoProxyCreator,AbstractAutoProxyCreator作为BeanPostProcessor就会在bean初始化后postProcessAfterInitialization()方法中创建该bean的代理对象放入bean容器。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

细节在wrapIfNecessary中,此时就会调用BeanNameAutoProxyCreator.getAdvicesAndAdvisorsForBean()方法

  protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && 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.
        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;
    }  

通过BeanNameAutoProxyCreator可以对批量的Bean进行AOP,并且指定了代理逻辑,指定了一个InterceptorName,也就是一个Advise,前提条件是这个Advise也得是一个Bean,这样Spring才能找到的,但是BeanNameAutoProxyCreator的缺点很明显,它只能根据beanName来指定想要代理的Bean。
而通过DefaultAdvisorAutoProxyCreator会直接去找所有Advisor类型的Bean,根据Advisor中的PointCut和Advice信息,确定要代理的Bean以及代理逻辑。

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor(){
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("test");

        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(pointcut);
        defaultPointcutAdvisor.setAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });

        return defaultPointcutAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        return defaultAdvisorAutoProxyCreator;
    }

当使用DefaultAdvisorAutoProxyCreator时,AbstractAutoProxyCreator.wrapIfNecessary方法中,就会调用DefaultAdvisorAutoProxyCreator的父类AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean()方法

protected Object[] getAdvicesAndAdvisorsForBean(
            Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

进入findEligibleAdvisors方法,我们就可以看到此时会先找到所有的Advisor bean,然后再去和beanClass匹配,最后得到满足条件的Advisor,并排序:

         /**
     * Find all eligible Advisors for auto-proxying this class.
     * @param beanClass the clazz to find advisors for
     * @param beanName the name of the currently proxied bean
     * @return the empty List, not {@code null},
     * if there are no pointcuts or interceptors
     * @see #findCandidateAdvisors
     * @see #sortAdvisors
     * @see #extendAdvisors
     */
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

五、Spring中创建代理对象的细节
当我们进入AbstractAutoProxyCreator.wrapIfNecessary()方法,最后就会看到createAopProxy().getProxy(classLoader)方法,getProxy方法分别对应JDK和cglib两种实现,首先来看JDK的实现,Spring中JdkDynamicAopProxy类封装了JDK的实现细节,并且实现了InvocationHandler接口

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

在Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)时将当前JdkDynamicAopProxy对象传入,这样实际执行的就是JdkDynamicAopProxy.invoke方法,这里使用了典型的策略模式

        public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

这里的关键逻辑就是拿到方法的拦截器链,List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);然后递归调用MethodInterceptor.invoke方法,invoke方法比较长,这里只截取关键的几行:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              ...
                        // 根据代理对象和方法找到拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            
            if (chain.isEmpty()) {
                    //如果chain为空,直接将target传入,通过反射执行被代理对象的方法
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                //构建MethodInvocation
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }
        ...
    }

进入invocation.proceed()

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;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, 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 {
            //普通拦截器
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

通常我们定义的都是普通拦截器,进入((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)会发现有很多的实现,我们以AfterReturningAdviceInterceptor为例,注意这里传入了this

public Object invoke(MethodInvocation mi) throws Throwable {
        //这里其实仍然执行的是ReflectiveMethodInvocation.proceed()
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

到这里其实就十分清晰了,正是通过递归的方式来执行多个MethodInterceptor
六、AnnotationAwareAspectJAutoProxyCreator
在我们实际使用中,很少直接创建AdvisorBean,更多是通过@Aspect来使用的,并且通过引入@EnableAspectJAutoProxy来获得Spring对注解@Aspect的支持,这里其实就用到了AnnotationAwareAspectJAutoProxyCreator

//通过@Import引入AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

进入AspectJAutoProxyRegistrar:

public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                //在此处注册了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        AnnotationAttributes enableAspectJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

AnnotationAwareAspectJAutoProxyCreator重写了findCandidateAdvisors方法,增加了对@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.
        if (this.aspectJAdvisorsBuilder != null) {
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }

七、SpringAop关键类的继承关系


image.png

AnnotationAwareAspectJAutoProxyCreator继承了AbstractAdvisorAutoProxyCreator,重写了findCandidateAdvisors()方法,AbstractAdvisorAutoProxyCreator只能找到所有Advisor类型的Bean对象,但是AnnotationAwareAspectJAutoProxyCreator除开可以找到所有Advisor类型的Bean对象,还能把@Aspect注解所标注的Bean中的@Before等注解及方法进行解析,并生成对应的Advisor对象。

八、最后我们来总结一下,SpringAop其实就是通过BeanPostProcessor结合JDK或者cglib的动态代理来实现对bean的增强,结合使用了工厂模式、策略模式、责任链模式等,对使用者屏蔽掉了底层实现,可见设计者的深厚功力。所以说多刷源码真的涨见识~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容