Spring AOP概念理解

Aspect(切面):AOP基本单元,类似于面向对象基本单元是类
Joinpoint(连接点):方法执行点
Advice:切点处执行的逻辑(增强处理)

很多时候你不知不觉就使用了AOP:在@Component类中,你在方法上加了@Transactional注解之后,方法执行前会开始事务,方法执行之后结束事务,方法发生异常之后回退事务;加上@Async注解之后,方法最终被调用的时候是异步的;加上@Cacheable注解之后,方法的返回值会被缓存起来,下次调用的时候直接返回缓存值。这些都是框架提供给你的,你只要加个注解声明一下就能用。

同时你也可以编写AOP代码来实现自己需求,比如在方法执行之前开始计时,在方法结束之后停止计时,来得到方法的运行时间;比如在业务的关键地方加上log;比如权限控制、懒加载等等。使用AOP的特点就是侵入性比较小,你的业务代码不用动,降低耦合度,方便团队分工。

Advisor是什么

Spring AOP范畴概念

package org.springframework.aop;

import org.aopalliance.aop.Advice;

/**
 * Base interface holding AOP <b>advice</b> (action to take at a joinpoint)
 * and a filter determining the applicability of the advice (such as
 * a pointcut). <i>This interface is not for use by Spring users, but to
 * allow for commonality in support for different types of advice.</i>
 *
 * <p>Spring AOP is based around <b>around advice</b> delivered via method
 * <b>interception</b>, compliant with the AOP Alliance interception API.
 * The Advisor interface allows support for different types of advice,
 * such as <b>before</b> and <b>after</b> advice, which need not be
 * implemented using interception.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
public interface Advisor {

    /**
     * Common placeholder for an empty {@code Advice} to be returned from
     * {@link #getAdvice()} if no proper advice has been configured (yet).
     * @since 5.0
     */
    Advice EMPTY_ADVICE = new Advice() {};


    /**
     * Return the advice part of this aspect. An advice may be an
     * interceptor, a before advice, a throws advice, etc.
     * @return the advice that should apply if the pointcut matches
     * @see org.aopalliance.intercept.MethodInterceptor
     * @see BeforeAdvice
     * @see ThrowsAdvice
     * @see AfterReturningAdvice
     */
    Advice getAdvice();

    /**
     * Return whether this advice is associated with a particular instance
     * (for example, creating a mixin) or shared with all instances of
     * the advised class obtained from the same Spring bean factory.
     * <p><b>Note that this method is not currently used by the framework.</b>
     * Typical Advisor implementations always return {@code true}.
     * Use singleton/prototype bean definitions or appropriate programmatic
     * proxy creation to ensure that Advisors have the correct lifecycle model.
     * @return whether this advice is associated with a particular target instance
     */
    boolean isPerInstance();
}

Intercepter

接口继承自Advice,以事务拦截器TransactionInterceptor说明

image.png

MethodInvocation

截屏2022-04-17 下午12.22.52.png

ReflectiveMethodInvocation

InvocationHandler
Java 反射中概念

package java.lang.reflect;

/**
 * {@code InvocationHandler} is the interface implemented by
 * the <i>invocation handler</i> of a proxy instance.
 *
 * <p>Each proxy instance has an associated invocation handler.
 * When a method is invoked on a proxy instance, the method
 * invocation is encoded and dispatched to the {@code invoke}
 * method of its invocation handler.
 *
 * @author      Peter Jones
 * @see         Proxy
 * @since       1.3
 */
public interface InvocationHandler {

   
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

Spring AOP 处理过程

1.@EnableAspectJAutoProxy注解会开启AOP功能
2.具体过程@EnableAspectJAutoProxy 会给IOC容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
3.AnnotationAwareAspectJAutoProxyCreator我们一直往上扒其父类会发现,它是一个后置处理器
4.然后在IOC容器创建过程中会有个registerBeanPostProcessors方法用来注册后置处理器,创建AnnotationAwareAspectJAutoProxyCreator对象
5.注册完后,IOC创建过程中还有另一个方法finishBeanFactoryInitialization(),它的作用是初始化剩下的单实例bean(省略了很多步骤)
6.在这个方法里,AnnotationAwareAspectJAutoProxyCreator会拦截bean的创建过程,去判断业务bean是不是要增强?(是不是切点)
7.是的话,就会包装增强器(Advisor),给业务bean创建一个代理对象(cglib)(我们今天不聊jdk代理)
8.然后等这个IOC容器创建完成,真正执行方法是时候,去执行方法的就是cglib代理对象
9.这个代理对象里面保存了详细信息(比如增强器,目标对象,等等),最后的执行者是CglibAopProxy.DynamicAdvisedInterceptor.intercept()
10.它会得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
11.利用拦截器的链式机制,依次进入每一个拦截器进行执行:

https://blog.csdn.net/aaa_bbb...

Spring创建代理对象

Spring代理对象生成入口在AbstractAutowireCapableBeanFactory#initializeBean方法,Bean在完成实例化、属性填充和初始化处理之后,通过调用Bean后置处理器(AnnotationAwareAspectJAutoProxyCreator)创建代理对象

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        } else {
            //调用Bean定制实现的XXXAware接口方法
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 调用Bean初始化前的后置处理器
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // Bean初始化方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
        // 调用Bean初始化后的后置处理器
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

Proxy对象创建—> AnnotationAwareAspectJAutoProxyCreator.class(实现了BeanPostProcessor)

AbstractAutoProxyCreator#postProcessAfterInitialization方法

    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
    

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && 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;
        }

        // 获取方法拦截器(Advisor集合),如果Advisor不为空创建代理对象
        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;
    }

查找Advisor方法

public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the auto-proxy creator apply to them!
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
        if (advisorNames.length == 0) {
            return new ArrayList<>();
        }

        List<Advisor> advisors = new ArrayList<>();
        for (String name : advisorNames) {
            if (isEligibleBean(name)) {
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Skipping currently created advisor '" + name + "'");
                    }
                }
                else {
                    try {
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    }
                    catch (BeanCreationException ex) {
                        Throwable rootCause = ex.getMostSpecificCause();
                        if (rootCause instanceof BeanCurrentlyInCreationException) {
                            BeanCreationException bce = (BeanCreationException) rootCause;
                            String bceBeanName = bce.getBeanName();
                            if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                                if (logger.isTraceEnabled()) {
                                    logger.trace("Skipping advisor '" + name +
                                            "' with dependency on currently created bean: " + ex.getMessage());
                                }
                                // Ignore: indicates a reference back to the bean we're trying to advise.
                                // We want to find advisors other than the currently created bean itself.
                                continue;
                            }
                        }
                        throw ex;
                    }
                }
            }
        }
        return advisors;
    }

Spring Aop创建代理对象并织入切面逻辑的入口方法是AbstractAutoProxyCreator#createProxy()

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 (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }
        // 将需要织入的切面逻辑都转换为Advisor对象
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        // 提供的hook方法,供子类实现以实现对代理工厂的定制
        customizeProxyFactory(proxyFactory);
    
        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
        // 生成代理类
        return proxyFactory.getProxy(getProxyClassLoader());
    }
public Object getProxy(@Nullable ClassLoader classLoader) {
    // 首先获取AopProxy对象,其主要有两个实现:JdkDynamicAopProxy和ObjenesisCglibAopProxy,
    // 分别用于Jdk和Cglib代理类的生成,其getProxy()方法则用于获取具体的代理对象
    return createAopProxy().getProxy(classLoader);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 判断当前类是否需要进行运行时优化,或者是指定了使用Cglib代理的方式,再或者是目标类没有用户提供的
    // 相关接口,则使用Cglib代理实现代理逻辑的织入
    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.");
        }
        // 如果被代理的类是一个接口,或者被代理的类是使用Jdk代理生成的类,此时还是使用Jdk代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        
        // 返回Cglib代理织入类对象
        return new ObjenesisCglibAopProxy(config);
    } else {
        // 返回Jdk代理织入类对象
        return new JdkDynamicAopProxy(config);
    }
}

以下主要分析使用Cglib方式生成代理实现代理逻辑的织入

public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating CGLIB proxy: target source is " 
            + this.advised.getTargetSource());
    }

    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, 
                     "Target class must be available for creating a CGLIB proxy");

        // 判断当前类是否是已经通过Cglib代理生成的类,如果是的,则获取其原始父类,
        // 并将其接口设置到需要代理的接口中
        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            // 获取父类
            proxySuperClass = rootClass.getSuperclass();
            // 获取父类实现的接口,并将其设置到需要代理的接口中
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // 对目标类进行检查,主要检查点有三个:
        // 1. 目标方法不能使用final修饰;
        // 2. 目标方法不能是private类型的;
        // 3. 目标方法不能是包访问权限的;
        // 这三个点满足任何一个,当前方法就不能被代理,此时该方法就会被略过
        validateClassIfNecessary(proxySuperClass, classLoader);

        // 创建Enhancer对象,并且设置ClassLoader
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        // 这里AopProxyUtils.completeProxiedInterfaces()方法的主要目的是为要生成的代理类
        // 增加SpringProxy,Advised,DecoratingProxy三个需要实现的接口。这里三个接口的作用如下:
        // 1. SpringProxy:是一个空接口,用于标记当前生成的代理类是Spring生成的代理类;
        // 2. Advised:Spring生成代理类所使用的属性都保存在该接口中,
        //    包括Advisor,Advice和其他相关属性;
        // 3. DecoratingProxy:该接口用于获取当前代理对象所代理的目标对象的Class类型。
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new 
            ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        // 获取当前需要织入到代理类中的逻辑
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }

        // 设置代理类中各个方法将要使用的切面逻辑,这里ProxyCallbackFilter.accept()方法返回
        // 的整型值正好一一对应上面Callback数组中各个切面逻辑的下标,也就是说这里的CallbackFilter
        // 的作用正好指定了代理类中各个方法将要使用Callback数组中的哪个或哪几个切面逻辑
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, 
            this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // 生成代理对象
        return createProxyClassAndInstance(enhancer, callbacks);
    } catch (CodeGenerationException | IllegalArgumentException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of class [" 
            + this.advised.getTargetClass() + "]: Common causes of this problem "  
            + "include using a final class or a non-visible class", ex);
    } catch (Throwable ex) {
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

Spring AOP可能遇到的问题

https://www.liaoxuefeng.com/w...

springboot默认cglib

springboot 为什么将默认的代理改成了cglib,这会导致什么问题?如果我们想要事务走JDK动态代理,该如何做?
springboot团队之所以默认的代理模式设置成cglib代理,看看spring的官方团队是怎么解释的

This was changed in 1.4 (see 5423). We’ve generally found cglib proxies less likely to cause unexpected cast exceptions.

他们认为使用cglib更不容易出现转换错误。springboot 默认的配置文件的位置在

/org/springframework/boot/spring-boot-autoconfigure/2.1.7.RELEASE/spring-boot-autoconfigure-2.1.7.RELEASE.jar!/META-INF/spring-configuration-metadata.json
{
      "name": "spring.aop.proxy-target-class",
      "type": "java.lang.Boolean",
      "description": "Whether subclass-based (CGLIB) proxies are to be created (true), as opposed to standard Java interface-based proxies (false).",
      "defaultValue": true
    },

如果偏要springboot 走JDK动态代理,那么需要在application.properties里面配置

spring.aop.proxy-target-class=false

Cglib代理FastClass机制
https://www.cnblogs.com/monke...


粥于于
9 声望1 粉丝

代码搬运工


« 上一篇
Mybatis基础
下一篇 »
Redis集群搭建