spring 切面增强简单流程

spring 对于aop编程进行了抽象

本片文章讨论aop在spring里的处理流程;
首先编写代码

  • 编写增强类
/**
 * 声明切入点和增强类
 */
@Component
@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");
  }
}
  • 被增强类
@Component
public class TestBean {

  public void test(){
    System.out.println("test print....");
  }
}
  • 启动类
@ComponentScan
// 开启aop
@EnableAspectJAutoProxy 
public class AnnotationAopTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationAopTest.class);
        TestBean testBean = applicationContext.getBean(TestBean.class);
        testBean.test();
    }
}

调试spring代码,关键类和方法
AbstractAutoProxyCreator 类,该类是SmartInstantiationAwareBeanPostProcessor实现,就是说在bean的实例化前,初始化前,初始化后三个过程都会触发该类的方法。
其中有两个方法会根据条件触发是否生成代理

  • postProcessBeforeInstantiation 方法, 在bean实例化前触发,如果此时bean已经被其他方式完成了初始化,则在此进行代理判断.
@Override
    public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        // Create proxy here if we have a custom TargetSource.
        // Suppresses unnecessary default instantiation of the target bean:
        // The TargetSource will handle target instances in a custom fashion.
        if (beanName != null) {
            // 获取自定义原始对象
            // 这里相当于提供一个机会给 用户自己定义被代理对象的实例化过程
            // 否在被代理对象将在spring容器初始化完成后在被代理
            TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) {
                this.targetSourcedBeans.add(beanName);
                Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
                Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
        }

        return null;
    }
  • postProcessAfterInitialization 方法,在bean初始化完成后触发。在这里spring对bean对象进行了包装
/**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     * @see #getAdvicesAndAdvisorsForBean
     */
    @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;
    }
/**
     * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
     * @param bean the raw bean instance
     * @param beanName the name of the bean
     * @param cacheKey the cache key for metadata access
     * @return a proxy wrapping the bean, or the raw bean instance as-is
     */
    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;
        }
        //  判断是否是spring内部aop类, 或者定义需要跳过的类
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
        // 根据bean查询增强点
        // 方式是遍历beanFactory的所有bean,如果是AspectJ类型则存储下来.
        // 后根据切入点是否匹配进行过滤,  如果过滤后还有匹配的数据则创建代理
        // 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;
    }

关键就是Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 根据bean类查找有无对应的增强点

/**
     * 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 findEligibleAdvisors(Class beanClass, String beanName) {
                // 查询出所有的增强点
        List candidateAdvisors = findCandidateAdvisors();
                // 匹配增强点和beanClass是否匹配
        List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
                        // 根据order排序
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

查找出增强点,并根据order排序;
根据增强点集合,生成代理工厂对象, 代理工厂根据配置生成真实代理类

/**
     * Create an AOP proxy for the given bean.
     * @param beanClass the class of the bean
     * @param beanName the name of the bean
     * @param specificInterceptors the set of interceptors that is
     * specific to this bean (may be empty, but not null)
     * @param targetSource the TargetSource for the proxy,
     * already pre-configured to access the bean
     * @return the AOP proxy for the bean
     * @see #buildAdvisors
     */
    protected Object createProxy(
            Class beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

        if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
  // 暴露代理对象
            AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
        }

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);
         // 判断是类代理还是接口代理
        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }
        // 创建增强链
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        // 保存关联的原始被代理对象
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

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

        return proxyFactory.getProxy(getProxyClassLoader());
    }

最终代理的创建委托到 DefaultAopProxyFactory类的createAopProxy方法

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

整个创建代理的流程就算完成了。

总结

总结一下,spring aop 没有在beanDefinition里指定bean是不是需要代理. 而是在bean真正实例化前或者初始化完成后,通过BeanPostProcessor查询当前bean有无增强点,有则进行代理。
被代理对象(targetSource)可以自定义,也可以是spring容器初始化;
只要创建TargetSource对象,并向AbstractAutoProxyCreator注册,即可以自定义被代理对象.

spring 切面增强简单流程_第1张图片
image.png

你可能感兴趣的:(spring 切面增强简单流程)