spring aop

源码大约分两步分,第一部分是在spring ioc初始化过程中加载所有aop标签到容器中,绑定代理类生成器AspectJAwareAdvisorAutoProxyCreator。
第二部分是在调用getBean实例化bean后,通过BeanPostProcessor的回调机制生成代理类。

如何使用

@Aspect
public class VocalConcert {

//定义一个切点,下面通知中可以直接使用,避免重复代码
    @Pointcut("execution(* com.aop.test1.Song.song(..))")
    public void doing() {
    }

    @Before("doing()")
    public void checking() {
        System.out.println("检票之后,找位子坐下");
    }

    @AfterReturning("doing()")
    public void beautiful() {
        System.out.println("演唱会进入精彩部分的时候,鼓掌!");
    }

    @AfterReturning("doing()")
    public void leave() {
        System.out.println("结束后,我们离开场地");
    }
}

结合上面代码分析什么叫切面、切点、通知、引入?
切面:被声明为@Aspect的整个类VocalConcert叫做切面。
切点:@Pointcut该注解定义切点,用来指明要拦截的目标类的方法
通知:切面中定义的那些before、after等等逻辑可以叫做通知。
引入:上面涉及到所有的都是对类中方法的增加,引入是对类的增强
通知:通知包括以下几种:
1、前置通知
2、后置通知 在目标方法执行完之后执行
3、返回通知 在目标方法正常返回后执行,如果发生异常,目标方法没有返回,则不执行
4、异常通知
5、环绕通知 前置通知+后置通知

spring支持的4种aop类型:
1、经典spring aop:不在使用
2、AspectJ切面:和spring没有什么关系,AspectJ框架。可以对字段构造器等进行增强。不做深入学习。
3、纯pojo切面:基于aop的命名空间, 在xml中定义切面
4、注解驱动的切面:对纯pojo切面进行改进,不在xml中定义切面,通过声明切面类+注解
关注的是3和4,就是spring中传统的xml和注解两种方式。

纯pojo切面(xml)

1、定义切面类

 public class SleepAspect {
        public void before(){
            System.out.println("睡觉之前拖衣服");
        }
        public void afterReturning(){
            System.out.println("睡觉");
        }
        public void afterThrowing(Exception ex) throws Exception {
            System.out.println("出大事了,有bug");
            System.out.println(ex.getMessage());
        }
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            Object proceed =null;
            if (!"".equals("admin")){
                System.out.println("核心方法被执行");
                proceed = pjp.proceed(pjp.getArgs());
                System.out.println("核心方法执行完");
            }
            return proceed;
        }
    }

2、声明目标类
3、xml中声明切面

<!--将切面类和目标类都交给spring容器-->
    <bean id="sleep" class="com.yztc.pojo.SleepDaoImpl"/>
    <bean id="sleepAspect" class="com.yztc.pojo.SleepAspect"/>

    <!--配置AOP-->
    <aop:config>
        <!--切面-->
        <aop:aspect id="aspect" ref="sleepAspect">
            <!--切入点的配置-->
            <aop:pointcut id="pointcut" expression="execution(* com.yztc.pojo.*.Sleep.*(..))"/>

            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="pointcut"/>
            <aop:around method="around" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

注解驱动的切面

这种方式就是在纯pojo切面基础上通过注解进行改进,不用在xml中声明切面。
1、定义一个切面

@Aspect
public class VocalConcert {

//定义一个切点,下面通知中可以直接使用,避免重复代码
    @Pointcut("execution(* com.aop.test1.Song.song(..))")
    public void doing() {
    }

    @Before("doing()")
    public void checking() {
        System.out.println("检票之后,找位子坐下");
    }

    @AfterReturning("doing()")
    public void beautiful() {
        System.out.println("演唱会进入精彩部分的时候,鼓掌!");
    }

    @AfterReturning("doing()")
    public void leave() {
        System.out.println("结束后,我们离开场地");
    }
}

2、开启切面功能

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"   //这里引入aop命名空间
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.aop.test1"/>

    <bean class="com.aop.test1.VocalConcert" id="concert"/>
    
    <aop:aspectj-autoproxy/>   //开启spring切面功能

</beans>

返回顶部

AopNamespaceHandler

aop自定义标签解析器,用来解析aop自定义标签。
AopNamespaceHandler和aop标签是如何映射的?
xml中aop的命名空间 -- spring aop jar包下的META-INF下的spring.handlers。
AopNamespaceHandler :该类的init方法中绑定了几种aop标签对应的parser

public class AopNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());// 
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
 
		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}
}

aop标签包含好几种,每一种都对应自己的parser,这种映射关系在上面AopNamespaceHandler的init方法中指定。具体标签包括哪些呢?

<aop:config>
        <!--切面-->
        <aop:aspect id="aspect" ref="sleepAspect">
            <!--切入点的配置-->
            <aop:pointcut id="pointcut" expression="execution(* com.yztc.pojo.*.Sleep.*(..))"/>

            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="pointcut"/>
            <aop:around method="around" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

上面代码中:config、aspect等都属于aop标签。

返回顶部

获取标签解析器

回顾ioc初始化流程,
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {//循环解析所有标签
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);//默认标签
                    }
                    else {
                        delegate.parseCustomElement(ele);//自定义标签
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }


//BeanDefinitionParserDelegate
public BeanDefinition parseCustomElement(Element ele) {
        return parseCustomElement(ele, null);
    }
    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }


//NamespaceHandlerSupport
@Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return findParserForElement(element, parserContext).parse(element, parserContext);
    }



private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
		String localName = parserContext.getDelegate().getLocalName(element);
		BeanDefinitionParser parser = this.parsers.get(localName);
		if (parser == null) {
			parserContext.getReaderContext().fatal(
					"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
		}
		return parser;
	}

首先获取标签解析器

因为aop最外层标签是config标签,所以先看下ConfigBeanDefinitionParser的parse方法
ConfigBeanDefinitionParser.parse:

 public BeanDefinition parse(Element element, ParserContext parserContext) {
        CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
        parserContext.pushContainingComponent(compositeDef);

        //向spring容器注册AspectJAwareAdvisorAutoProxyCreator
        configureAutoProxyCreator(parserContext, element);

        List<Element> childElts = DomUtils.getChildElements(element);
        for (Element elt: childElts) {
            String localName = parserContext.getDelegate().getLocalName(elt);
            if (POINTCUT.equals(localName)) {//切点
                parsePointcut(elt, parserContext);
            }
            else if (ADVISOR.equals(localName)) {//通知
                parseAdvisor(elt, parserContext);
            }
            else if (ASPECT.equals(localName)) {//切面
                parseAspect(elt, parserContext);
            }
        }

        parserContext.popAndRegisterContainingComponent();
        return null;
    }

1、向spring容器注册代理类生产器AspectJAwareAdvisorAutoProxyCreator
2、遍历所有aop标签下的所有子节点,分别定义三个入口,切面、切点、通知

返回顶部

解析切面

接下来该解析切面,注意,切面里边包含通知和切点,所以这个方法也包含了通知和切点的解析
ConfigBeanDefinitionParser.parseAspect:遍历所有aop标签,解析相应的通知和切点

 private void parseAspect(Element aspectElement, ParserContext parserContext) {
        String aspectId = aspectElement.getAttribute(ID);
        String aspectName = aspectElement.getAttribute(REF);

        try {
            this.parseState.push(new AspectEntry(aspectId, aspectName));
            List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
            List<BeanReference> beanReferences = new ArrayList<BeanReference>();

            List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
            for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
                Element declareParentsElement = declareParents.get(i);
                beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
            }

            //获取切面所有子节点进行遍历
            NodeList nodeList = aspectElement.getChildNodes();
            boolean adviceFoundAlready = false;
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (isAdviceNode(node, parserContext)) {
                    if (!adviceFoundAlready) {
                        adviceFoundAlready = true;
                        if (!StringUtils.hasText(aspectName)) {
                            parserContext.getReaderContext().error(
                                    "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
                                    aspectElement, this.parseState.snapshot());
                            return;
                        }
                        beanReferences.add(new RuntimeBeanReference(aspectName));
                    }
                    //如果标签是通知,进入解析通知标签方法
                    AbstractBeanDefinition advisorDefinition = parseAdvice(
                            aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
                    beanDefinitions.add(advisorDefinition);
                }
            }

            AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
                    aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
            parserContext.pushContainingComponent(aspectComponentDefinition);

            List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
            for (Element pointcutElement : pointcuts) {//获取切面下所有切点标签进行解析
                //进入切点标签的解析方法入口
                parsePointcut(pointcutElement, parserContext);
            }

            parserContext.popAndRegisterContainingComponent();
        }
        finally {
            this.parseState.pop();
        }
    }

该方法拿到切面下所有的切点和通知标签进行遍历解析。切点调用parsePointcut解析,通知调用parseAdvice解析。

解析通知

//ConfigBeanDefinitionParser
 private AbstractBeanDefinition parseAdvice(
            String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
            List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

        try {
            this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

            // create the method factory bean
            RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
            methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
            methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
            methodDefinition.setSynthetic(true);

            // create instance factory definition
            RootBeanDefinition aspectFactoryDef =
                    new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
            aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
            aspectFactoryDef.setSynthetic(true);

            // 声明通知为BeanDefinition
            AbstractBeanDefinition adviceDef = createAdviceDefinition( //入口
                    adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
                    beanDefinitions, beanReferences);

            // 对上面创建的BeanDefinition包装一下
            RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
            advisorDefinition.setSource(parserContext.extractSource(adviceElement));
            advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
            if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
                advisorDefinition.getPropertyValues().add(
                        ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
            }

            // register the final advisor
            parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

            return advisorDefinition;
        }
        finally {
            this.parseState.pop();
        }
    }



 private AbstractBeanDefinition createAdviceDefinition(
            Element adviceElement, ParserContext parserContext, String aspectName, int order,
            RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
            List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

        //入口
        RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
        adviceDefinition.setSource(parserContext.extractSource(adviceElement));

        adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
        adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);

        if (adviceElement.hasAttribute(RETURNING)) {
            adviceDefinition.getPropertyValues().add(
                    RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
        }
        if (adviceElement.hasAttribute(THROWING)) {
            adviceDefinition.getPropertyValues().add(
                    THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
        }
        if (adviceElement.hasAttribute(ARG_NAMES)) {
            adviceDefinition.getPropertyValues().add(
                    ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
        }

        ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
        cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

        Object pointcut = parsePointcutProperty(adviceElement, parserContext);
        if (pointcut instanceof BeanDefinition) {
            cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
            beanDefinitions.add((BeanDefinition) pointcut);
        }
        else if (pointcut instanceof String) {
            RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
            cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
            beanReferences.add(pointcutRef);
        }

        cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

        return adviceDefinition;
    }

    private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
        String elementName = parserContext.getDelegate().getLocalName(adviceElement);
        if (BEFORE.equals(elementName)) {
            return AspectJMethodBeforeAdvice.class;
        }
        else if (AFTER.equals(elementName)) {
            return AspectJAfterAdvice.class;
        }
        else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
            return AspectJAfterReturningAdvice.class;
        }
        else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
            return AspectJAfterThrowingAdvice.class;
        }
        else if (AROUND.equals(elementName)) {
            return AspectJAroundAdvice.class;
        }
        else {
            throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
        }
    }

该方法为每个通知实例化一个bean到spring容器。
不同类型的通知生成的RootBeanDifination的class属性不同

返回顶部

解析切点

//ConfigBeanDefinitionParser
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
        String id = pointcutElement.getAttribute(ID);
        String expression = pointcutElement.getAttribute(EXPRESSION);

        AbstractBeanDefinition pointcutDefinition = null;

        try {
            this.parseState.push(new PointcutEntry(id));
            //将pointcut创建成一个BeanDefinition
            pointcutDefinition = createPointcutDefinition(expression);//入口
            pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

            String pointcutBeanName = id;
            if (StringUtils.hasText(pointcutBeanName)) {
                parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
            }
            else {
                pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
            }

            parserContext.registerComponent(
                    new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
        }
        finally {
            this.parseState.pop();
        }

        return pointcutDefinition;
    }
    protected AbstractBeanDefinition createPointcutDefinition(String expression) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
        beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        beanDefinition.setSynthetic(true);
        beanDefinition.getPropertyValues().add(EXPRESSION, expression);
        return beanDefinition;
    }

为每个切点实例化一个bean到spring容器

返回顶部

代理类的创建

到这里,在ioc启动过程中,通过aop解析器把aop标签声明成BeanDefinition到spring容器中,已经完毕。
同时注意上面注册了一个类AspectJAwareAdvisorAutoProxyCreator,该类是BeanPostProcessor的下层类,同时封装了为普通bean生成代理类的方法。
这就意味着,在调用getBean获取bean实例之后,通过BeanPostProcessor的回调机制,通过spring容器中的相关aop标签和AspectJAwareAdvisorAutoProxyCreator类就可以创建代理类。

BeanPostProcessor回调为入口:

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

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;
        }

        //判断是否需要生成代理类
        //入口1
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(//入口2  生成代理的方法
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

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


@Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
        /***
         * findEligibleAdvisors方法是拿当前Advisor对应的expression做了两层判断:
         *
         * 目标类必须满足expression的匹配规则
         * 目标类中的方法必须满足expression的匹配规则,当然这里方法不是全部需要满足expression的匹配规则,有一个方法满足即可
         */
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }

1、根据bean名称去spring容器获取所有的asvisor,注意:这个advisor包含切面和通知
2、匹配切点规则是否满足这个类,如果满足调用createProxy创建代理类

接下来就是创建代理类的方法

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

        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
        }

        // 1.创建proxyFactory,proxy的生产主要就是在proxyFactory做的
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);

        //<aop:config>这个节点中proxy-target-class="false"或者proxy-target-class不配置,即不使用CGLIB生成代理。
        // 如果满足条件,进判断,获取当前Bean实现的所有接口,讲这些接口Class对象都添加到ProxyFactory中。
        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            } else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        // 2.将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到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);
        }

        // 3.调用getProxy获取bean对应的proxy
        return proxyFactory.getProxy(getProxyClassLoader());//入口
    }

1、创建代理类工厂
2、将所有满足条件的advisor bean添加到代理工厂中
3、通过代理工厂创建代理类

public Object getProxy(ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);//入口1 + 入口2
    }

1、通过createAopProxy选择是jdk还是cglib
2、通过getProxy创建代理类

  // createAopProxy()方法就是决定究竟创建何种类型的proxy
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 1.ProxyConfig的isOptimize方法为true,这表示让Spring自己去优化而不是用户指定
        // 2、ProxyConfig的isProxyTargetClass方法为true,这表示配置了proxy-target-class="true"
        // 3、ProxyConfig满足hasNoUserSuppliedProxyInterfaces方法执行结果为true,
        // 这表示<bean>对象没有实现任何接口或者实现的接口是SpringProxy接口
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();

            // 2.如果目标类是接口或者是代理类,则直接使用JDKproxy
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }

            // 3.其他情况则使用CGLIBproxy
            return new ObjenesisCglibAopProxy(config);
        } else {
            return new JdkDynamicAopProxy(config);
        }
    }

如果配置了就按照配置的选择,如果目标类是接口直接使用jdk代理

以jdk动态代理为例继续走下去。

public Object getProxy(ClassLoader classLoader) {
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

        // JDK proxy 动态代理的标准用法
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

jdk动态代理创建。

返回顶部

执行目标方法

我们知道,jdk动态代理通过代理类调用目标方法的时候,实际调用的是自定义拦截器的invoke方法,aop的自定义拦截器为JdkDynamicAopProxy。

//知道,jdk动态代理通
 @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)) {
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                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)) {
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);//入口1
            }

            Object retVal;

            if (this.advised.exposeProxy) {//将代理类暴漏到AopContext中
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // 获取目标对象
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

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

            if (chain.isEmpty()) {
                // 如果拦截器为空,那么直接调用目标对象的目标方法 进入该方法
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // 否则,需要先调用拦截器然后再调用目标方法,通过构造一个ReflectiveMethodInvocation来实现
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 沿着拦截器链前行 进入该方法
                retVal = invocation.proceed();//入口2
            }

            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                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;
        }
    }


    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable {
        ReflectionUtils.makeAccessible(method);
        // 通过反射的方式直接调用目标对象方法
        return method.invoke(target, args);
    }
     


@Override
    public Object proceed() throws Throwable {
        // 从索引为-1的拦截器开始调用,按顺序递增,直到没有拦截器了,然后开始调用目标对象的方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
        // 沿着定义好的拦截器链进行获取然后逐个处理
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // 这里是触发匹配判断的地方,如果和定义的pointcut匹配,那么这个advice将得到执行
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                return proceed();
            }
        }
        else {
            // 如果是一个interceptor,那么直接调用这个interceptor的invoke方法 进入此方法来分析通知(拦截器)是如何起作用的
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }


 @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class<?> targetClass) {
        // 所有的advistor在config中已经持有了,可以直接使用
        // This is somewhat tricky... We have to process introductions first,
        // but we need to preserve order in the ultimate list.
        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

        for (Advisor advisor : config.getAdvisors()) {
            if (advisor instanceof PointcutAdvisor) {
                // Add it conditionally.
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    //通过AdvisorAdapterRegistry注册器,把从config中获取的advistor进行适配,从而获得拦截器,再把它放入List中。这就是拦截器注册的过程。
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }

        return interceptorList;
    }
  1. 将所有的通知封装成一个拦截器链表,然后按顺序执行,最后通过反射调用目标方法
  2. AopContext内部通过ThreadLocal来存储了代理类,如果expose-proxy属性开启,这里还没将代理类放入到AopContext中。

返回顶部

posted @ 2020-03-29 22:27  平淡454  阅读(121)  评论(0编辑  收藏  举报