spring aop源码分析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: spring aop源码分析

1. AOP 概念

AOP(Aspect Oriented Programming),即面向切面编程。

  • 连接点(JoinPoint)
    程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些点中的特定点就称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点植入增强。
  • 切点(Pointcut)
    每个类具有多个连接点,如果一个类拥有15个方法,那么这些方法都是连接点,连接点相当于数据库中的记录,而切点相当于查询条件。切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责切点所设定的查询条件,找到对应的连接点。其实确切地说,不能称之为查询连接点,因为连接点是方法执行前、执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,所以如果希望定位到具体连接点上,还需要提供方位信息。
  • 增强(Advice)
    增强是植入到目标类连接点上的一段程序代码,在Spring中,增强除用于描述一段程序代码外,还拥有另一个和连接点相关的信息,这便是执行点的方位。结合执行点方位信息切点信息,我们就可以找到特定的连接点。
  • 通知器(Advisor)
    当我们完成切面增强设计(Advice)和切入点的设计(Pointcut),需要一个对象把他们结合起来,Advisor 就是起到这个作用,通过Advisor ,可以确定在哪个Pointcut 使用哪个Advice。所以一个Advisor包含一个Advice 和 一个Pointcut 信息。


我们先来了解一下,bean实例化过程,便于我们后续理解aop。

下面有很简单的一段代码可以作为Spring代码加载的入口:

 ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
 ac.getBean(XXX.class);


ClassPathXmlApplicationContext用于加载CLASSPATH下的Spring配置文件,可以看到,第二行就已经可以获取到Bean的实例了,那么必然第一行就已经完成了对所有Bean实例的加载,因此可以通过ClassPathXmlApplicationContext作为入口。为了后面便于代码阅读,先给出一下ClassPathXmlApplicationContext这个类的继承关系:




ClassPathXmlApplicationContext存储内容

为了更理解ApplicationContext,拿一个实例ClassPathXmlApplicationContext举例,看一下里面存储的内容,加深对ApplicationContext的认识,以表格形式展现:

对象名 类  型 作  用 归属类
configResources Resource[] 配置文件资源对象数组 ClassPathXmlApplicationContext
configLocations String[] 配置文件字符串数组,存储配置文件路径 AbstractRefreshableConfigApplicationContext
beanFactory DefaultListableBeanFactory 上下文使用的Bean工厂 AbstractRefreshableApplicationContext
beanFactoryMonitor Object Bean工厂使用的同步监视器 AbstractRefreshableApplicationContext
id String 上下文使用的唯一Id,标识此ApplicationContext AbstractApplicationContext
parent ApplicationContext 父级ApplicationContext AbstractApplicationContext
beanFactoryPostProcessors List<BeanFactoryPostProcessor> 存储BeanFactoryPostProcessor接口,Spring提供的一个扩展点 AbstractApplicationContext
startupShutdownMonitor Object refresh方法和destory方法公用的一个监视器,避免两个方法同时执行 AbstractApplicationContext
shutdownHook Thread Spring提供的一个钩子,JVM停止执行时会运行Thread里面的方法 AbstractApplicationContext
resourcePatternResolver ResourcePatternResolver 上下文使用的资源格式解析器 AbstractApplicationContext
lifecycleProcessor LifecycleProcessor 用于管理Bean生命周期的生命周期处理器接口 AbstractApplicationContext
messageSource MessageSource 用于实现国际化的一个接口 AbstractApplicationContext
applicationEventMulticaster ApplicationEventMulticaster Spring提供的事件管理机制中的事件多播器接口 AbstractApplicationContext
applicationListeners Set<ApplicationListener> Spring提供的事件管理机制中的应用监听器 AbstractApplicationContext

 

ClassPathXmlApplicationContext构造函数

看下ClassPathXmlApplicationContext的构造函数:

 public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
     this(new String[] {configLocation}, true, null);
 } public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
         throws BeansException {
     super(parent);
     setConfigLocations(configLocations);
     if (refresh) {
         refresh();
     }
 }


从第二段代码看,总共就做了三件事:

  1、super(parent)

    没什么太大的作用,设置一下父级ApplicationContext,这里是null

  2、setConfigLocations(configLocations)

    代码就不贴了,一看就知道,里面做了两件事情:

    (1)将指定的Spring配置文件的路径存储到本地

    (2)解析Spring配置文件路径中的${PlaceHolder}占位符,替换为系统变量中PlaceHolder对应的Value值,System本身就自带一些系统变量比如class.path、os.name、user.dir等,也可以通过System.setProperty()方法设置自己需要的系统变量

  3、refresh()

    这个就是整个Spring Bean加载的核心了,它是ClassPathXmlApplicationContext的父类AbstractApplicationContext的一个方法,顾名思义,用于刷新整个Spring上下文信息,定义了整个Spring上下文加载的流程。


了解完,bean的加载流程,接下来,我们正式开始AOP的学习了

 有关于AOP,我们在面试中也被无数次问到,AOP是什么?AOP有什么作用与优势?AOP在项目中是如何用到的?


   这些还都是比较简单的,有些可能会问你AOP的实现是怎样的?


   哪怕没有看过源码的同学也应该知道,AOP是通过动态代理实现的,动态代理又分为两个部分:JDK动态代理和CGLIB动态代理


   确实,Spring也就是通过这两种方式来实现AOP相关功能,下面就通过源码来简单求证下

1.AOP功能简单实现

   1)引入maven依赖(笔者使用SpringBoot开发)

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.3.RELEASE</version>
</parent>     
<dependency>      
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-aop</artifactId>  
</dependency>

  2)创建接口及其实现类

public interface Person {
  void say();
}
public class Student implements Person{
  public void say(){
    System.out.println("这是一个苦逼的程序员");
  }
}

3)创建切面类

@Aspect
public class AspectJTest {
  @Pointcut("execution(* *.say(..))")
  public void test(){}
  @Before("test()")
  public void before(){
    System.out.println("before test..");
  }
  @After("test()")
  public void after(){
    System.out.println("after test..");
  }
  @Around("test()")
  public Object around(ProceedingJoinPoint p){
    System.out.println("before1");
    Object o = null;
    try {
      o = p.proceed();
    } catch (Throwable e) {
      e.printStackTrace();
    }
    System.out.println("after1");
    return o;
  }
}

 4)创建beans.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.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  <aop:aspectj-autoproxy/>
    <bean id="student" class="test.Student"/>
  <bean class="test.AspectJTest"/>
</beans>

5)测试类

public class Test {
  public static void main(String[] args) {
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
    Person bean2 = (Person)ac.getBean("student");
    bean2.say();
  }
    // 结果如下:
    before1
    before test..
    这是一个苦逼的程序员
    after1
    after test..

总结:AOP功能的使用还是比较简单的,把相关bean注入到Spring容器中,编写好相应的Aspect类即可


   1)在使用ApplicationContext相关实现类加载bean的时候,会针对所有单例且非懒加载的bean,在构造ApplicationContext的时候就会创建好这些bean,而不会等到使用的时候才去创建。这也就是单例bean默认非懒加载的应用


   2)读者需要了解BeanPostProcessor的相关使用,所有实现BeanPostProcessor接口的类,在初始化bean的时候都会调用这些类的方法,一般用于在bean初始化前或后对bean做一些修改。而AOP的功能实现正式基于此,在bean初始化后创建针对该bean的proxy,然后返回给用户该proxy


 


   3)结合以上两点,被代理后的bean,实际在ApplicationContext构造完成之后就已经被创建完成,getBean()的操作直接从singletonObjects中获取即可



3.AOP源码架构分析

   1)寻找 <aop:aspectj-autoproxy/> 注解对应的解析器

     但凡注解都有对应的解析器,以用来解析该注解的行为。全局搜索之后可发现。

org.springframework.aop.config.AopNamespaceHandler类中有对应的解析行为,代码如下:
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());
  }
}

 2)了解AspectJAutoProxyBeanDefinitionParser对应的行为

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
  @Override
  public BeanDefinition parse(Element element, ParserContext parserContext) {
        // 1.注册proxy creator
    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    extendBeanDefinition(element, parserContext);
    return null;
  }
    ...
    // registerAspectJAnnotationAutoProxyCreatorIfNecessary()
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      ParserContext parserContext, Element sourceElement) {
        // 注册行为主要内容
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext);
  }
    // registerAspectJAnnotationAutoProxyCreatorIfNecessary()
  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;
    }
        // 类似于我们在使用BeanFactory.getBean()时候的操作,生成一个RootBeanDefinition,然后放入map中
    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;
  }

 总结:通过以上的代码分析,可知,AspectJAutoProxyBeanDefinitionParser主要的功能就是将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中,把bean交给Spring去托管。


   AnnotationAwareAspectJAutoProxyCreator的功能我们大胆猜测一下:应该也就是生成对象的代理类的相关功能,这个我们接下来再看。


   


   问题:


   那么问题来了,我们最开始的类AopNamespaceHandler.init()方法是在什么时候被调用的呢?什么时候生效的?这个决定了我们注册到Spring的AnnotationAwareAspectJAutoProxyCreator的生效时间?读者可自行思考下。


 


   3)分析AnnotationAwareAspectJAutoProxyCreator主要行为

       通过查看AnnotationAwareAspectJAutoProxyCreator的类层次结构,可知,其实现了BeanPostProcessor接口,实现类为AbstractAutoProxyCreator


       类层次结构如下:

  4)AbstractAutoProxyCreator主要方法

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) {
    return bean;
  }
    // 主要看这个方法,在bean初始化之后对生产出的bean进行包装
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
        return wrapIfNecessary(bean, beanName, cacheKey);
      }
    }
    return bean;
  }
    // wrapIfNecessary
  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.
        // 意思就是如果该类有advice则创建proxy,
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 1.通过方法名也能简单猜测到,这个方法就是把bean包装为proxy的主要方法,
      Object proxy = createProxy(
          bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
            // 2.返回该proxy代替原来的bean
      return proxy;
    }
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
  }

总结:


   1)通过AspectJAutoProxyBeanDefinitionParser类将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中


   2)AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法将所有有advice的bean重新包装成proxy


 


 


4.创建proxy过程分析

   通过之前的代码结构分析,我们知道,所有的bean在返回给用户使用之前都需要经过AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法,而该方法的主要作用也就是将所有拥有advice的bean重新包装为proxy,那么我们接下来直接分析这个包装为proxy的方法即可,看一下bean如何被包装为proxy,proxy在被调用方法时,是具体如何执行的


 


   以下是AbstractAutoProxyCreator.wrapIfNecessary(Object bean, String beanName, Object cacheKey)中的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);
    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)创建何种类型的Proxy?JDKProxy还是CGLIBProxy?

    // getProxy()方法
  public Object getProxy(ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
  }
    // createAopProxy()方法就是决定究竟创建何种类型的proxy
  protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
      activate();
    }
        // 关键方法createAopProxy()
    return getAopProxyFactory().createAopProxy(this);
  }
    // createAopProxy()
  public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 1.config.isOptimize()是否使用优化的代理策略,目前使用与CGLIB
        // config.isProxyTargetClass() 是否目标类本身被代理而不是目标类的接口
        // hasNoUserSuppliedProxyInterfaces()是否存在代理接口
    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.");
      }
            // 2.如果目标类是接口或者是代理类,则直接使用JDKproxy
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
        return new JdkDynamicAopProxy(config);
      }
            // 3.其他情况则使用CGLIBproxy
      return new ObjenesisCglibAopProxy(config);
    }
    else {
      return new JdkDynamicAopProxy(config);
    }
  }

2)getProxy()方法

   由1)可知,通过createAopProxy()方法来确定具体使用何种类型的Proxy

   针对于该示例,我们具体使用的为JdkDynamicAopProxy,下面来看下JdkDynamicAopProxy.getProxy()方法

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable// JdkDynamicAopProxy类结构,由此可知,其实现了InvocationHandler,则必定有invoke方法,来被调用,也就是用户调用bean相关方法时,此invoke()被真正调用
    // getProxy()
    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, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        // JDK proxy 动态代理的标准用法
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  }

  3)invoke()方法

   以上的代码模式可以很明确的看出来,使用了JDK动态代理模式,真正的方法执行在invoke()方法里,下面我们来看下该方法,来看下bean方法如何被代理执行的

  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 {
            // 1.以下的几个判断,主要是为了判断method是否为equals、hashCode等Object的方法
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
        // The target does not implement the equals(Object) method itself.
        return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
        // The target does not implement the hashCode() method itself.
        return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
        // There is only getDecoratedClass() declared -> dispatch to proxy config.
        return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
          method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        // Service invocations on ProxyConfig with the proxy config...
        return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }
      Object retVal;
      if (this.advised.exposeProxy) {
        // Make invocation available if necessary.
        oldProxy = AopContext.setCurrentProxy(proxy);
        setProxyContext = true;
      }
      // May be null. Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
      target = targetSource.getTarget();
      if (target != null) {
        targetClass = target.getClass();
      }
      // 2.获取当前bean被拦截方法链表
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      // 3.如果为空,则直接调用target的method
      if (chain.isEmpty()) {
        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
            // 4.不为空,则逐一调用chain中的每一个拦截方法的proceed
      else {
        // We need to create a method invocation...
        invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        // Proceed to the joinpoint through the interceptor chain.
        retVal = invocation.proceed();
      }
      ...
      return retVal;
    }
    ...
  }

    4)拦截方法真正被执行调用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;
      if (dm.methodMatcher.matches(this.method, this.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 {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
  }

总结4:依次遍历拦截器链的每个元素,然后调用其实现,将真正调用工作委托给各个增强器


 


   


   总结:


   纵观以上过程可知:实际就是为bean创建一个proxy,JDKproxy或者CGLIBproxy,然后在调用bean的方法时,会通过proxy来调用bean方法


   重点过程可分为:


   1)通过AspectJAutoProxyBeanDefinitionParser类将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中


   2)AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法将所有有advice的bean重新包装成proxy


   3)调用bean方法时通过proxy来调用,proxy依次调用增强器的相关方法,来实现方法切入


目录
相关文章
|
15天前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
42 1
|
21天前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
41 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
26天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
30 1
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
31 1
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
28 1
|
2月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
22天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
31 0
|
3月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
2月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
88 2