spring 源码 aop 准备(一)

1 概念

切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。
连接点(Joinpoint) :程序执行过程中的某一行为。
通知(Advice) :“切面”对于某个“连接点”所产生的动作。
切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。
目标对象(Target Object) :被一个或者多个切面所通知的对象。
AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。

spring-aop 使用
在分析源码之前,最好是先看一下怎么去使用,然后才好入手,下面是依赖配置信息
这里写图片描述
spring aop 使用有三种方式,下面主要是介绍其中两种


2 注解方式

@Aspect
public class AspectJTest {
  @Pointcut("execution(* *.test*(..))")
  public void test(){

  }

  @Before("test()")
  public void beforeTest(){
    System.out.println("before test");
  }

  @After("test()")
  public void afterTest(){
    System.out.println("after test");
  }
}
/**
 *被测试的类
 */
public class TestService {

  public void testAAAA(){
    System.out.println("test print....");
  }
}
  public static void main(String[] args){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");

    TestService testService = (TestService) context.getBean("testService");
    testService.testAAAA();
    System.out.println(testService);
  }
xml 配置
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
  <!--开启注解aop-->
  <aop:aspectj-autoproxy proxy-target-class="false"/>
  <bean id="testService" class="com.xie.java.aop.annotation.TestService"/>
  <bean id="aspectJTest" class="com.xie.java.aop.annotation.AspectJTest"/>
</beans>

3 xml配置方式

测试代码

public interface HelloWorld {
    void printHelloWorld();

    void doPrint();
}

public class HelloWorldImpl1 implements HelloWorld {
    public void printHelloWorld() {
        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
    }

    public void doPrint() {
        System.out.println("Enter HelloWorldImpl1.doPrint()");
        return;
    }
}

public class HelloWorldImpl2 implements HelloWorld {
    public void printHelloWorld() {
        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
    }

    public void doPrint() {
        System.out.println("Enter HelloWorldImpl2.doPrint()");
        return;
    }
}

/**
 * 通知类
 */
public class LogHandler {
    public void LogBefore() {
        System.out.println("方法前日志");
    }

    public void LogAfter() {
        System.out.println("方法后日志");
    }
}

/**
 * 通知类
 */
public class TimeHandler {
    public void printTime() {
        System.out.println("方法前后打印时间 CurrentTime = " + System.currentTimeMillis());
    }
}

xml配置文件

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
            http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
  <bean id="helloWorldImpl1" class="com.xie.java.aop.xmlconfig.HelloWorldImpl1" />
  <bean id="helloWorldImpl2" class="com.xie.java.aop.xmlconfig.HelloWorldImpl1" />

  <bean id="timeHandler" class="com.xie.java.aop.xmlconfig.TimeHandler" />
  <bean id="logHandler" class="com.xie.java.aop.xmlconfig.LogHandler" />

<!--配置两个切面-->
  <aop:config>
    <!--order 指定切面执行顺序-->
    <aop:aspect id="time" ref="timeHandler" order="1">
      <aop:pointcut id="addTime" expression="execution(* com.xie.java.aop.xmlconfig.HelloWorld.*(..))" />
      <aop:before method="printTime" pointcut-ref="addTime" />
      <aop:after method="printTime" pointcut-ref="addTime" />
    </aop:aspect>

    <aop:aspect id="log" ref="logHandler" order="2">
      <aop:pointcut id="printLog" expression="execution(* com.xie.java.aop.xmlconfig.HelloWorld.*(..))" />
      <aop:before method="LogBefore" pointcut-ref="printLog" />
      <aop:after method="LogAfter" pointcut-ref="printLog" />
    </aop:aspect>
  </aop:config>
</beans>

4 aop:aspectj-autoproxy标签解释

以之前几编spring的经验,我们可以得知aop的标签是spring自定义标签,那就得从NameSpaceHandler入手:AopNameSpaceHandler 是spring aop标签的处理器,当spring 遇到aop标签时,自动会找到AopNameSpaceHandler,再通过标签名找到对应的BeanDefinitionParser 进行处理;下面是源码入口,在此先对aspectj-autoproxy 标签进行分析

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    /**
     * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
     * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
     * and '{@code scoped-proxy}' tags.
     */
    @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());
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

}

从上面可以看到aop就四种标签,在这里先对aspectj-autoproxy 进行分析AspectJAutoProxyBeanDefinitionParser.parse

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) { 
    //通过AopNamespaceUtils实现aop处理类的beandefinitions 注册
    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        extendBeanDefinition(element, parserContext);
        return null;
    }

AopNamespaceUtils

    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {
        //创建 AnnotationAwareAspectJAutoProxyCreator对应的beandefinition,之类是aop的一个核类,接下来会对其进行详细分析
        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        //处理使用的代码方式
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }

    private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
        if (sourceElement != null) {
            boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                //获取代理生成方式(jdk,或cglib)
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

    private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
        if (beanDefinition != null) {
            BeanComponentDefinition componentDefinition =
                    new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
            parserContext.registerComponent(componentDefinition);
        }
    }

AopConfigUtils

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
        //注册AnnotationAwareAspectJAutoProxyCreator 
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        //判断是否已注册过
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }
            return null;
        }
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        //设置为最高的执行优先级
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
}

5 aop:config标签解释

回到AopNamespaceHandler,查看config解释过程

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    /**
     * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
     * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
     * and '{@code scoped-proxy}' tags.
     */
    @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());
    }

}

ConfigBeanDefinitionParser

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
    parserContext.pushContainingComponent(compositeDef);
    //注册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);
        }
        //advisor元素
        else if (ADVISOR.equals(localName)) {
            parseAdvisor(elt, parserContext);
        }
        //切面元素
        else if (ASPECT.equals(localName)) {
            parseAspect(elt, parserContext);
        }
    }

    parserContext.popAndRegisterContainingComponent();
    return null;
}

pointcut解释

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

advisor解释

    private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
        AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
        String id = advisorElement.getAttribute(ID);

        try {
            this.parseState.push(new AdvisorEntry(id));
            String advisorBeanName = id;
            if (StringUtils.hasText(advisorBeanName)) {
                parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
            }
            else {
                advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
            }
            //获取pointcut信息
            Object pointcut = parsePointcutProperty(advisorElement, parserContext);
            if (pointcut instanceof BeanDefinition) {
                advisorDef.getPropertyValues().add(POINTCUT, pointcut);
                parserContext.registerComponent(
                        new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
            }
            else if (pointcut instanceof String) {
                advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
                parserContext.registerComponent(
                        new AdvisorComponentDefinition(advisorBeanName, advisorDef));
            }
        }
        finally {
            this.parseState.pop();
        }
    }
    //解释pointcut详细信息
    private Object parsePointcutProperty(Element element, ParserContext parserContext) {
        if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
            parserContext.getReaderContext().error(
                    "Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
                    element, this.parseState.snapshot());
            return null;
        }
        else if (element.hasAttribute(POINTCUT)) {
            // Create a pointcut for the anonymous pc and register it.
            String expression = element.getAttribute(POINTCUT);
            AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
            pointcutDefinition.setSource(parserContext.extractSource(element));
            return pointcutDefinition;
        }
        else if (element.hasAttribute(POINTCUT_REF)) {
            String pointcutRef = element.getAttribute(POINTCUT_REF);
            if (!StringUtils.hasText(pointcutRef)) {
                parserContext.getReaderContext().error(
                        "'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
                return null;
            }
            return pointcutRef;
        }
        else {
            parserContext.getReaderContext().error(
                    "Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
                    element, this.parseState.snapshot());
            return null;
        }
    }

aspect 切面解释

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

            // We have to parse "advice" and all the advice kinds in one loop, to get the
            // ordering semantics right.
            NodeList nodeList = aspectElement.getChildNodes();
            boolean adviceFoundAlready = false;
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                //判断是否为advice 
                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) {
                //解释pointcut
                parsePointcut(pointcutElement, parserContext);
            }

            parserContext.popAndRegisterContainingComponent();
        }
        finally {
            this.parseState.pop();
        }
    }
//判断是否为advice节点
    private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
        if (!(aNode instanceof Element)) {
            return false;
        }
        else {
            String name = parserContext.getDelegate().getLocalName(aNode);
            return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
                    AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
        }
    }

到这里aop解释也差不多了 ,但这都只是aop实现的准备阶段,下一编将会详细介绍aop怎么实现并执行的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值