【Spring】AOP的代理过程


在这里插入图片描述

一、AOP 三大概念

Spring AOP 有三个重要的组成部分:Aspect、Pointcut、Advice。Advice 代表时间、Pointcut 代表位置,Aspect 代表代理方法

  • Advice(通知/增强):在特定的连接点执行的代码,如前置通知、后置通知、环绕通知等
  • Pointcut(切点):定义了通知应该在哪些连接点(方法)上生效
  • Aspect(切面):一个模块化的横切关注点,通常是一个类,包含通知和切点

二、AOP 的实现方式

Spring AOP 的实现依赖于代理模式和动态代理技术。Spring 提供了两种主要的 AOP 实现方式:

  • 基于 JDK 动态代理:适用于目标对象实现了接口的情况
  • 基于 CGLIB 动态代理:适用于目标对象没有实现接口的情况

三、AOP 代理创建流程

3.1、 Bean 初始化
当你在 Spring 配置类中使用 @EnableAspectJAutoProxy 注解时,Spring 会导入 AspectJAutoProxyRegistrar 然后注册 AnnotationAwareAspectJAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor 接口,我们知道 BeanPostProcessor 是一个 Bean 声明周期接口,所以在 Spring 生成 Bean 的时候会调用 AnnotationAwareAspectJAutoProxyCreator 的 postProcessBeforeInstantiation 方法来检查当前 Bean 是否需要被代理

    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                // 检查当前 Bean 是否需要被代理
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }

        return bean;
    }

3.2 wrapIfNecessary 方法
wrapIfNecessary 方法判断 Bean 是否需要创建代理。如果当前 Bean 有适用的增强器,则通过 createProxy 方法来实际创建代理对象

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            } else {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        } else {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    }

3.3 createProxy 方法
createProxy 方法会根据目标类是否实现了接口来决定使用 JDK 动态代理还是 CGLIB 动态代理,这样 Spring 生成的Bean 其实是经过 AOP 增强的 Bean

    protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable 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 (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
                Class[] var6 = beanClass.getInterfaces();
                int var7 = var6.length;

                for(int var8 = 0; var8 < var7; ++var8) {
                    Class<?> ifc = var6[var8];
                    proxyFactory.addInterface(ifc);
                }
            }
        } else if (this.shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            this.evaluateProxyInterfaces(beanClass, proxyFactory);
        }

        Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        this.customizeProxyFactory(proxyFactory);
        proxyFactory.setFrozen(this.freezeProxy);
        if (this.advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }

        ClassLoader classLoader = this.getProxyClassLoader();
        if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
            classLoader = ((SmartClassLoader)classLoader).getOriginalClassLoader();
        }

        return proxyFactory.getProxy(classLoader);
    }


四、学习交流

链接: Java-AI学习交流
一个人的精力是有限的,没有那么多的时间去探索新的事物,加入一个交流群就相当于增加了一个接触新事物、新想法、新机会的渠道,这就是交流群存在的意义,期待你的加入!

Spring AOP使用CGLIB作为默认的代理方式来实现动态代理代理过程中,首先需要定义一个被代理的目标对象或者叫做目标类。该目标对象可以是任何一个Java对象,它会在运行时被代理创建。然后,通过Spring的配置文件或者注解,将该目标对象注入到Spring容器中。 接下来,需要定义一个切面类,该类中包含了代理的具体操作和条件。这些操作和条件可以是在目标对象的方法执行前后增加日志、事务控制、权限验证等。切面类通常会实现Advice接口或者继承AbstractAspectJAdvice类。 在Spring容器启动时,会根据配置文件或者注解自动扫描到切面类,并且生成代理对象。生成代理对象的方式有两种:JDK动态代理和CGLIB动态代理。在Spring AOP中,默认使用CGLIB动态代理方式,因为CGLIB可以代理没有实现接口的目标类。 当目标对象的方法被调用时,代理对象会先调用切面类的相应方法,然后再调用目标对象的方法。这样,代理对象就可以在目标对象方法执行前后,添加自己的逻辑。 CGLIB是一个强大的第三方类库,它通过继承的方式创建代理对象。通过修改字节码,可以在目标类中创建子类,并将代理逻辑插入到子类的方法中,从而实现代理的功能。 总之,Spring AOP使用CGLIB作为默认的代理方式来实现动态代理代理过程中,首先需要定义目标对象和切面类,然后通过配置文件或者注解将它们注入到Spring容器中。在运行时,Spring容器会自动生成代理对象,并在方法执行前后执行切面逻辑,实现代理的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值