美文网首页
spring 切面增强简单流程

spring 切面增强简单流程

作者: 何德何能者 | 来源:发表于2020-12-26 18:27 被阅读0次

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<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
                // 查询出所有的增强点
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
                // 匹配增强点和beanClass是否匹配
        List<Advisor> 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注册,即可以自定义被代理对象.

image.png

相关文章

  • spring 切面增强简单流程

    spring 对于aop编程进行了抽象 本片文章讨论aop在spring里的处理流程;首先编写代码 编写增强类 被...

  • Spring AOP

    Spring AOP 一、面向切面编程 1. AOP术语 1.1 ADVICE(增强) Spring提供了以下几种...

  • SpringBoot自定义注解的简单实现

    在spring中,AOP和IOC都是spring非常重要的特性,而在web开发中,定义切面、增强方法也是比较常见的...

  • 自学Java第124天

    学了切面编程的实现步骤传统的spring配置和Aspectj配置 无外乎都是核心三步骤:确定要增强谁?确定增强什么...

  • Spring AOP实现方式

    AOP主要是它以横切面的方式,将增强的代码插入到主流程中。 切面织入的方法:1、编译期织入---->Aspectj...

  • Spring事务什么时候会失效

    Spring事务什么时候会失效? Spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不...

  • spring aop配置总结

    引言 Spring aop支持@AspectJ注解的方式来配置切面,相比于手动配置xml且手动实现增强、切点的方式...

  • SPRING AOP整理

    AspectJ 一套独立的面向切面编程解决方案使用的是编译时增强,相比spring AOP使用的是运行时增强性能更...

  • Spring AOP

    Spring的AOPAOP的基本概念基于注解的“零配置”方式定义切面Bean定义Before增强处理定义After...

  • spring切面使用bean和接口请求参数

    效果: 1、注解 2、切面 3、ApplicationContextAware 一个简单的使用 spring 容器...

网友评论

      本文标题:spring 切面增强简单流程

      本文链接:https://www.haomeiwen.com/subject/bkpgnktx.html