Spring源码深度解析二(AOP)

news2024/12/26 23:29:53

书接上文

9. AOP源码深度剖析

概述

  1. AOP(Aspect Orient Programming):面向切面编程;

  2. 用途:用于系统中的横切关注点,比如日志管理,事务管理;

  3. 实现:利用代理模式,通过代理对象对被代理的对象增加功能。

    所以,关键在于AOP框架自动创建AOP代理对象,代理模式分为静态代理和动态代理;

  4. 框架: AspectJ使用静态代理,编译时增强,在编译期生成代理对象;

    SpringAOP使用动态代理,运行时增强,在运行时,动态生成代理对象;

Spring AOP的前世今生

目前 Spring AOP 一共有三种配置方式,Spring 做到了很好地向下兼容,所以可以放心使用。

  • Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的
  • Spring 2.0 schema-based 配置:Spring 2.0 以后使用 XML 的方式来配置,使用 命名空间 <aop />
  • Spring 2.0 @AspectJ 配置:使用注解的方式来配置,这种方式感觉是最方便的,还有,这里虽然叫做 @AspectJ,但是这个和 AspectJ 其实没啥关系。

要说明的是,这里介绍的 Spring AOP 是纯的 Spring 代码,和 AspectJ 没什么关系,但是 Spring 延用了 AspectJ 中的概念,包括使用了 AspectJ 提供的 jar 包中的注解,但是不依赖于其实现功能。

如 @Aspect、@Pointcut、@Before、@After 等注解都是来自于 AspectJ,但是功能的实现是纯 Spring AOP 自己实现的。

实现机制

Spring AOP 底层实现机制目前有两种:JDK 动态代理、CGLIB 动态字节码生成。在阅读源码前对这两种机制的使用有个认识,有利于更好的理解源码。

JDK 动态代理

public class MyInvocationHandler implements InvocationHandler {

    private Object origin;

    public MyInvocationHandler(Object origin) {
        this.origin = origin;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke start");
        Object result = method.invoke(origin, args);
        System.out.println("invoke end");
        return result;
    }
}

public class JdkProxyTest {
    public static void main(String[] args) {
        UserService proxy = (UserService) Proxy.newProxyInstance(JdkProxyTest.class.getClassLoader(),
                new Class[]{UserService.class}, new MyInvocationHandler(new UserServiceImpl()));
        proxy.doSomething();
    }
}

CGLIB 代理

public class CglibInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("intercept start");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("intercept end");
        return result;
    }
}

public class CglibProxyTest {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibObject.class);
        enhancer.setCallback(new CglibInterceptor());
        CglibObject proxy = (CglibObject) enhancer.create();
        proxy.doSomething();
    }
}

AOP实例

UserService接口:

public interface UserService {

    public void findAll();
}

UserServiceImpl实现类:

@Service
public class UserServiceImpl implements UserService{

    public void findAll(){
        System.out.println("findAll...");
    }

}

AopAspect切面类:

@Component
@Aspect
public class AopAspect {

    @Pointcut("execution(* com.demo.service..*.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void before() {
        System.out.println("before");
    }

    @After("pointcut()")
    public void after() {
        System.out.println("after advice");
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws InterruptedException {
        System.out.println("around advice start");
        try {
            Object result = proceedingJoinPoint.proceed();
            System.out.println("result: " + result);
            System.out.println("around advice end");
            return result;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return null;
        }
    }

}

applicationContext-aop.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:component-scan base-package="com.demo"/>

    <aop:aspectj-autoproxy />

</beans>

源码剖析-AOP 注解的解析

当使用 <aop:aspectj-autoproxy /> 注解开启 AOP 功能时,解析aop标签会进行到parseCustomElement(root);

parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 1.默认命名空间的处理
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        // 遍历root的子节点列表
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    // 1.1 默认命名空间节点的处理,例如: <bean id="test" class="" />
                    parseDefaultElement(ele, delegate);
                }
                else {
                    // 1.2 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
                    delegate.parseCustomElement(ele);
                }
            }
        }
    } else {
        // 2.自定义命名空间的处理**** <aop:aspectj-autoproxy />进行解析
        delegate.parseCustomElement(root);
    }
}

parseCustomElement

public BeanDefinition parseCustomElement(Element ele) {
    return parseCustomElement(ele, null);
}

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    // 1.拿到节点ele的命名空间,例如常见的:
    // <context> 节点对应命名空间: http://www.springframework.org/schema/context
    // <aop> 节点对应命名空间: http://www.springframework.org/schema/aop
    String namespaceUri = getNamespaceURI(ele);
    // 2.拿到命名空间对应的的handler, 例如:http://www.springframework.org/schema/context 对应 ContextNameSpaceHandler
    // 2.1 getNamespaceHandlerResolver: 拿到namespaceHandlerResolver
    // 2.2 resolve: 使用namespaceHandlerResolver解析namespaceUri, 拿到namespaceUri对应的NamespaceHandler
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    // 3.使用拿到的handler解析节点(ParserContext用于存放解析需要的一些上下文信息)
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

Spring会从“META-INF/spring.handlers” 配置文件中拿到该注解对应的 NamespaceHandlerSupport:AopNamespaceHandler

'xxs'

在 AopNamespaceHandler 的 init 方法会给该注解注册对应的解析器,aspectj-autoproxy 对应的解析器是:AspectJAutoProxyBeanDefinitionParser。

当解析到 <aop:aspectj-autoproxy /> 注解时,会调用 AspectJAutoProxyBeanDefinitionParser 的 parse方法。

AspectJAutoProxyBeanDefinitionParser#parse

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    // 1.注册AspectJAnnotationAutoProxyCreator
    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    // 2.对于注解中子节点的处理
    extendBeanDefinition(element, parserContext);
    return null;
}

1.注册 AspectJAnnotationAutoProxyCreator,见代码块1。

代码块1:AopNamespaceUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        ParserContext parserContext, Element sourceElement) {
    // 1.注册AspectJAnnotationAutoProxyCreator
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    // 2.对于proxy-target-class以及expose-proxy属性的处理
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    // 3.注册组件并通知,便于监听器做进一步处理
    registerComponentIfNecessary(beanDefinition, parserContext);
}

1.注册 AspectJAnnotationAutoProxyCreator,见代码块2

2.对于 proxy-target-class 以及 expose-proxy 属性的处理,见代码块3

代码块2:AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    // 1.如果注册表中已经存在beanName=org.springframework.aop.config.internalAutoProxyCreator的bean,则按优先级进行选择。
    // beanName=org.springframework.aop.config.internalAutoProxyCreator,可能存在的beanClass有三种,按优先级排序如下:
    // InfrastructureAdvisorAutoProxyCreator、AspectJAwareAdvisorAutoProxyCreator、AnnotationAwareAspectJAutoProxyCreator
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        // 拿到已经存在的bean定义
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        // 如果已经存在的bean的className与当前要注册的bean的className不相同,则按优先级进行选择
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            // 拿到已经存在的bean的优先级
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            // 拿到当前要注册的bean的优先级
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {
                // 如果当前要注册的bean的优先级大于已经存在的bean的优先级,则将bean的className替换为当前要注册的bean的className,
                apcDefinition.setBeanClassName(cls.getName());
            }
            // 如果小于,则不做处理
        }
        // 如果已经存在的bean的className与当前要注册的bean的className相同,则无需进行任何处理
        return null;
    }
    // 2.如果注册表中还不存在,则新建一个Bean定义,并添加到注册表中
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    // 设置了order为最高优先级
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    // 注册BeanDefinition,beanName为org.springframework.aop.config.internalAutoProxyCreator
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}

org.springframework.aop.config.internalAutoProxyCreator 是内部管理的自动代理创建者的 bean 名称,可能对应的 beanClassName 有三种,对应的注解如下:

InfrastructureAdvisorAutoProxyCreator:<tx:annotation-driven />

AspectJAwareAdvisorAutoProxyCreator:<aop:config />

AnnotationAwareAspectJAutoProxyCreator:<aop:aspectj-autoproxy />

当同时存在多个注解时,会使用优先级最高的 beanClassName 来作为 org.springframework.aop.config.internalAutoProxyCreator 的 beanClassName。现在暂不考虑同时存在其他注解的情况,所以在这边会注册的 beanClassName 为:AnnotationAwareAspectJAutoProxyCreator。

代码块3:useClassProxyingIfNecessary

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
    if (sourceElement != null) {
        boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
        if (proxyTargetClass) {
            // 如果节点设置了proxy-target-class=true,则给beanName为org.springframework.aop.config.internalAutoProxyCreator
            // 的BeanDefinition添加proxyTargetClass=true的属性,之后创建代理的时候将强制使用Cglib代理
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
        boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
        if (exposeProxy) {
            // 如果节点设置了expose-proxy=true,则给beanName为org.springframework.aop.config.internalAutoProxyCreator
            // 的BeanDefinition添加exposeProxy=true的属性,之后创建拦截器时会根据该属性选择是否暴露代理类
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
        }
    }
}

总结

该部分最重要的内容就是注册了内部管理的自动代理创建者的 bean:AnnotationAwareAspectJAutoProxyCreator

源码剖析-创建 AOP 代理

AnnotationAwareAspectJAutoProxyCreator类图

AnnotationAwareAspectJAutoProxyCreator 实现了几个重要的扩展接口(可能是在父类中实现):

1)实现了 BeanPostProcessor 接口:实现了 postProcessAfterInitialization 方法。

2)实现了 InstantiationAwareBeanPostProcessor 接口:实现了 postProcessBeforeInstantiation 方法。

3)实现了 SmartInstantiationAwareBeanPostProcessor 接口:实现了 predictBeanType 方法、getEarlyBeanReference 方法。

4)实现了 BeanFactoryAware 接口,实现了 setBeanFactory 方法。

对于 AOP 来说,postProcessAfterInitialization 是我们重点分析的内容,因为在该方法中,会对 bean 进行代理,该方法由父类 AbstractAutoProxyCreator 实现。

AbstractAutoProxyCreator#postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 1.判断当前bean是否需要被代理,如果需要则进行封装
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

1.判断当前bean是否需要被代理,如果需要则进行封装,见代码块1。

代码块1:wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 1.判断当前bean是否在targetSourcedBeans缓存中存在(已经处理过),如果存在,则直接返回当前bean
    if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 2.在advisedBeans缓存中存在,并且value为false,则代表无需处理
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 3.bean的类是aop基础设施类 || bean应该跳过,则标记为无需处理,并返回
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 4.获取当前bean的Advices和Advisors
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 5.如果存在增强器则创建代理
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 5.1 创建代理对象:这边SingletonTargetSource的target属性存放的就是我们原来的bean实例(也就是被代理对象),
        // 用于最后增加逻辑执行完毕后,通过反射执行我们真正的方法时使用(method.invoke(bean, args))
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        // 5.2 创建完代理后,将cacheKey -> 代理类的class放到缓存
        this.proxyTypes.put(cacheKey, proxy.getClass());
        // 返回代理对象
        return proxy;
    }
    // 6.标记为无需处理
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

4.获取当前 bean 的 Advices 和 Advisors,见代码块2。

5.1 创建代理对象,见代码块14。

代码块2:getAdvicesAndAdvisorsForBean

@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
    // 1.找到符合条件的Advisor
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        // 2.如果没有符合条件的Advisor,则返回null
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

1.找到符合条件的 Advisor,见代码块3。

代码块3:findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 1.查找所有的候选Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 2.从所有候选的Advisor中找出符合条件的
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 3.扩展方法,留个子类实现
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // 4.对符合条件的Advisor进行排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

1.查找所有的候选 Advisor,见代码块4。

2.从所有候选的 Advisor 中找出符合条件的,见代码块13。

代码块4:findAdvisorBeans

@Override
protected List<Advisor> findCandidateAdvisors() {
    // 1.添加根据父类规则找到的所有advisor。
    List<Advisor> advisors = super.findCandidateAdvisors();
    // 2.为bean工厂中的所有AspectJ方面构建advisor
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}

1.添加根据父类规则找到的所有 advisor,见代码块5。

2.为 bean 工厂中的所有 AspectJ 方面构建 advisor,见代码块6。

代码块5:findCandidateAdvisors

protected List<Advisor> findCandidateAdvisors() {
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

public List<Advisor> findAdvisorBeans() {
    // 1.确认advisor的beanName列表,优先从缓存中拿
    String[] advisorNames = null;
    synchronized (this) {
        advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
            //  1.1 如果缓存为空,则获取class类型为Advisor的所有bean名称
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Advisor.class, true, false);
            this.cachedAdvisorBeanNames = advisorNames;
        }
    }
    if (advisorNames.length == 0) {
        return new LinkedList<Advisor>();
    }

    // 2.遍历处理advisorNames
    List<Advisor> advisors = new LinkedList<Advisor>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            // 2.1 跳过当前正在创建的advisor
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping currently created advisor '" + name + "'");
                }
            } else {
                try {
                    // 2.2 通过beanName获取对应的bean对象,并添加到advisors
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                } catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("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;
                }
            }
        }
    }
    // 3.返回符合条件的advisor列表
    return advisors;
}

代码块6:buildAspectJAdvisors

public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;
    // 1.如果aspectNames为空,则进行解析
    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new LinkedList<Advisor>();
                aspectNames = new LinkedList<String>();
                // 1.1 获取所有的beanName
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // 1.2 循环遍历所有的beanName,找出对应的增强方法
                for (String beanName : beanNames) {
                    // 1.3 不合法的beanName则跳过,默认返回true,子类可以覆盖实现,AnnotationAwareAspectJAutoProxyCreator
                    // 实现了自己的逻辑,支持使用includePatterns进行筛选
                    if (!isEligibleBean(beanName)) {
                        continue;
                    }
                    // We must be careful not to instantiate beans eagerly as in this case they
                    // would be cached by the Spring container but would not have been weaved.
                    // 获取beanName对应的bean的类型
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // 1.4 如果beanType存在Aspect注解则进行处理
                    if (this.advisorFactory.isAspect(beanType)) {
                        // 将存在Aspect注解的beanName添加到aspectNames列表
                        aspectNames.add(beanName);
                        // 新建切面元数据
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        // 获取per-clause的类型是SINGLETON
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            // 使用BeanFactory和beanName创建一个BeanFactoryAspectInstanceFactory,主要用来创建切面对象实例
                            MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // 1.5 解析标记AspectJ注解中的增强方法
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            // 1.6 放到缓存中
                            if (this.beanFactory.isSingleton(beanName)) {
                                // 如果beanName是单例则直接将解析的增强方法放到缓存
                                this.advisorsCache.put(beanName, classAdvisors);
                            } else {
                                // 如果不是单例,则将factory放到缓存,之后可以通过factory来解析增强方法
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            // 1.7 将解析的增强器添加到advisors
                            advisors.addAll(classAdvisors);
                        } else {
                            // 如果per-clause的类型不是SINGLETON
                            // Per target or per this.
                            if (this.beanFactory.isSingleton(beanName)) {
                                // 名称为beanName的Bean是单例,但切面实例化模型不是单例,则抛异常
                                throw new IllegalArgumentException("Bean with name '" + beanName +
                                        "' is a singleton, but aspect instantiation model is not singleton");
                            }
                            MetadataAwareAspectInstanceFactory factory =
                                    new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                            // 将factory放到缓存,之后可以通过factory来解析增强方法
                            this.aspectFactoryCache.put(beanName, factory);
                            // 解析标记AspectJ注解中的增强方法,并添加到advisors中
                            advisors.addAll(this.advisorFactory.getAdvisors(factory));
                        }
                    }
                }
                // 1.9 将解析出来的切面beanName放到缓存aspectBeanNames
                this.aspectBeanNames = aspectNames;
                // 1.10 最后返回解析出来的增强器
                return advisors;
            }
        }
    }
    // 2.如果aspectNames不为null,则代表已经解析过了,则无需再次解析
    // 2.1 如果aspectNames是空列表,则返回一个空列表。空列表也是解析过的,只要不是null都是解析过的。
    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }
    // 2.2 aspectNames不是空列表,则遍历处理
    List<Advisor> advisors = new LinkedList<Advisor>();
    for (String aspectName : aspectNames) {
        // 根据aspectName从缓存中获取增强器
        List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
        if (cachedAdvisors != null) {
            // 根据上面的解析,可以知道advisorsCache存的是已经解析好的增强器,直接添加到结果即可
            advisors.addAll(cachedAdvisors);
        } else {
            // 如果不存在于advisorsCache缓存,则代表存在于aspectFactoryCache中,
            // 从aspectFactoryCache中拿到缓存的factory,然后解析出增强器,添加到结果中
            MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
        }
    }
    // 返回增强器
    return advisors;
}

1.5 解析标记 AspectJ 注解中的增强方法,见代码块7。

代码块7:getAdvisors

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 1.前面我们将beanClass和beanName封装成了aspectInstanceFactory的AspectMetadata属性,
    // 这边可以通过AspectMetadata属性重新获取到当前处理的切面类
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 2.获取当前处理的切面类的名字
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    // 3.校验切面类
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    // 4.使用装饰器包装MetadataAwareAspectInstanceFactory,以便它只实例化一次。
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new LinkedList<Advisor>();
    // 5.获取切面类中的方法(也就是我们用来进行逻辑增强的方法,被@Around、@After等注解修饰的方法,使用@Pointcut的方法不处理)
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 6.处理method,获取增强器
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            // 7.如果增强器不为空,则添加到advisors
            advisors.add(advisor);
        }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // 8.如果寻找的增强器不为空而且又配置了增强延迟初始化,那么需要在首位加入同步实例化增强器(用以保证增强使用之前的实例化)
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    // 9.获取DeclareParents注解
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}

6.处理 method,获取增强器,见代码块8。

代码块8:getAdvisor

@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
                          int declarationOrderInAspect, String aspectName) {
    // 1.校验切面类
    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    // 2.AspectJ切点信息的获取(例如:表达式),就是指定注解的表达式信息的获取,如:@Around("execution(* com.demo.open.aop.*.*(..))")
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    // 3.如果expressionPointcut为null,则直接返回null
    if (expressionPointcut == null) {
        return null;
    }
    // 4.根据切点信息生成增强器
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

2.AspectJ 切点信息的获取,见代码块9。

4.根据切点信息生成增强器,见代码块11。

代码块9:getPointcut

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    // 1.查找并返回给定方法的第一个AspectJ注解(@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut)
    // 因为我们之前把@Pointcut注解的方法跳过了,所以这边必然不会获取到@Pointcut注解
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    // 2.如果方法没有使用AspectJ的注解,则返回null
    if (aspectJAnnotation == null) {
        return null;
    }
    // 3.使用AspectJExpressionPointcut实例封装获取的信息
    AspectJExpressionPointcut ajexp =
            new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
    // 提取得到的注解中的表达式,
    // 例如:@Around("execution(* com.demo.open.aop.*.*(..))"),得到:execution(* com.demo.open.aop.*.*(..))
    ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
    ajexp.setBeanFactory(this.beanFactory);
    return ajexp;
}

1.获取方法上的AspectJ注解,见代码块10。

代码块10:findAspectJAnnotationOnMethod

protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
    // 设置要查找的注解类
    Class<?>[] classesToLookFor = new Class<?>[]{
            Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
    for (Class<?> c : classesToLookFor) {
        // 查找方法上是否存在当前遍历的注解,如果有则返回
        AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
        if (foundAnnotation != null) {
            return foundAnnotation;
        }
    }
    return null;
}

代码块11:new InstantiationModelAwarePointcutAdvisorImpl

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
                                                  Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
                                                  MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    // 1.简单的将信息封装在类的实例中
    this.declaredPointcut = declaredPointcut;
    this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
    this.methodName = aspectJAdviceMethod.getName();
    this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
    // aspectJAdviceMethod保存的是我们用来进行逻辑增强的方法(@Around、@After等修饰的方法)
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    this.aspectInstanceFactory = aspectInstanceFactory;
    this.declarationOrder = declarationOrder;
    this.aspectName = aspectName;
    // 2.是否需要延迟实例化
    if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut = Pointcuts.union(
                aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

        // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
        // If it's not a dynamic pointcut, it may be optimized out
        // by the Spring AOP infrastructure after the first evaluation.
        this.pointcut = new PerTargetInstantiationModelPointcut(
                this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
        this.lazy = true;
    } else {
        // A singleton aspect.
        this.pointcut = this.declaredPointcut;
        this.lazy = false;
        // 3.实例化增强器:根据注解中的信息初始化对应的增强器
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}

3.实例化增强器:根据注解中的信息初始化对应的增强器,见代码块12。

代码块12:instantiateAdvice

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
    return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}

// ReflectiveAspectJAdvisorFactory.java
@Override
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
                        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
    // 1.获取切面类
    Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    // 2.校验切面类(重复校验第3次...)
    validate(candidateAspectClass);

    // 3.查找并返回方法的第一个AspectJ注解
    AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
    if (aspectJAnnotation == null) {
        return null;
    }

    // If we get here, we know we have an AspectJ method.
    // Check that it's an AspectJ-annotated class
    // 4.如果我们到这里,我们知道我们有一个AspectJ方法。检查切面类是否使用了AspectJ注解
    if (!isAspect(candidateAspectClass)) {
        throw new AopConfigException("Advice must be declared inside an aspect type: " +
                "Offending method '" + candidateAdviceMethod + "' in class [" +
                candidateAspectClass.getName() + "]");
    }

    if (logger.isDebugEnabled()) {
        logger.debug("Found AspectJ method: " + candidateAdviceMethod);
    }

    AbstractAspectJAdvice springAdvice;

    // 5.根据方法使用的aspectJ注解创建对应的增强器,例如最常见的@Around注解会创建AspectJAroundAdvice
    switch (aspectJAnnotation.getAnnotationType()) {
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
        case AtAround:
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
        case AtPointcut:
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            return null;
        default:
            throw new UnsupportedOperationException(
                    "Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // Now to configure the advice...
    // 6.配置增强器
    // 切面类的name,其实就是beanName
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    // 获取增强方法的参数
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        // 如果参数不为空,则赋值给springAdvice
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();
    // 最后,返回增强器
    return springAdvice;
}

代码块13:findAdvisorsThatCanApply

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
    // 1.首先处理引介增强(@DeclareParents)用的比较少可以忽略,有兴趣的参考:https://www.cnblogs.com/HigginCui/p/6322283.html
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
            eligibleAdvisors.add(candidate);
        }
    }
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    // 2.遍历所有的candidateAdvisors
    for (Advisor candidate : candidateAdvisors) {
        // 2.1 引介增强已经处理,直接跳过
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        // 2.2 正常增强处理,判断当前bean是否可以应用于当前遍历的增强器(bean是否包含在增强器的execution指定的表达式中)
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

2.2 正常增强处理,判断当前 bean 是否可以应用于当前遍历的增强器,这边表达式判断的逻辑比较复杂,可以简单的理解为:判断 bean 是否包含在增强器的 execution 指定的表达式中。

📌代码块14: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
    ProxyFactory proxyFactory = new ProxyFactory();
    // 从当前对象复制属性值
    proxyFactory.copyFrom(this);

    // 检查proxyTargetClass属性,判断对于给定的bean使用类代理还是接口代理,
    // proxyTargetClass值默认为false,可以通过proxy-target-class属性设置为true
    if (!proxyFactory.isProxyTargetClass()) {
        // 检查preserveTargetClass属性,判断beanClass是应该基于类代理还是基于接口代理
        if (shouldProxyTargetClass(beanClass, beanName)) {
            // 如果是基于类代理,则将proxyTargetClass赋值为true
            proxyFactory.setProxyTargetClass(true);
        } else {
            // 评估bean的代理接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }
    // 将拦截器封装为Advisor(advice持有者)
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 将advisors添加到proxyFactory
    proxyFactory.addAdvisors(advisors);
    // 设置要代理的类,将targetSource赋值给proxyFactory的targetSource属性,之后可以通过该属性拿到被代理的bean的实例
    proxyFactory.setTargetSource(targetSource);
    // 自定义ProxyFactory,空方法,留给子类实现
    customizeProxyFactory(proxyFactory);

    // 用来控制proxyFactory被配置之后,是否还允许修改通知。默认值为false(即在代理被配置之后,不允许修改代理类的配置)
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // 2.使用proxyFactory获取代理
    return proxyFactory.getProxy(getProxyClassLoader());
}

2.使用 proxyFactory 获取代理,见代码块15。

代码块15:getProxy

public Object getProxy(ClassLoader classLoader) {
    // 1.createAopProxy:创建AopProxy
    // 2.getProxy(classLoader):获取代理对象实例
    return createAopProxy().getProxy(classLoader);
}

1.createAopProxy:创建AopProxy,见代码块16。 2.getProxy(classLoader):获取代理对象实例,跟我们自己写的代理类似,JDK 动态代理见代码块18,CGLIB 代理见代码块19。

代码块16:createAopProxy

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        // 1.激活此代理配置
        activate();
    }
    // 2.创建AopProxy
    return getAopProxyFactory().createAopProxy(this);
}

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 1.判断使用JDK动态代理还是Cglib代理
    // optimize:用于控制通过cglib创建的代理是否使用激进的优化策略。除非完全了解AOP如何处理代理优化,
    // 否则不推荐使用这个配置,目前这个属性仅用于cglib代理,对jdk动态代理无效
    // proxyTargetClass:默认为false,设置为true时,强制使用cglib代理,设置方式:<aop:aspectj-autoproxy proxy-target-class="true" />
    // hasNoUserSuppliedProxyInterfaces:config是否存在代理接口或者只有SpringProxy一个接口
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        // 拿到要被代理的对象的类型
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            // TargetSource无法确定目标类:代理创建需要接口或目标。
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        // 要被代理的对象是接口 || targetClass是Proxy class
        // 当且仅当使用getProxyClass方法或newProxyInstance方法动态生成指定的类作为代理类时,才返回true。
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            // JDK动态代理,这边的入参config(AdvisedSupport)实际上是ProxyFactory对象
            // 具体为:AbstractAutoProxyCreator中的proxyFactory.getProxy发起的调用,在ProxyCreatorSupport使用了this作为参数,
            // 调用了的本方法,这边的this就是发起调用的proxyFactory对象,而proxyFactory对象中包含了要执行的的拦截器
            return new JdkDynamicAopProxy(config);
        }
        // Cglib代理
        return new ObjenesisCglibAopProxy(config);
    } else {
        // JDK动态代理
        return new JdkDynamicAopProxy(config);
    }
}

这边创建 AopProxy 的参数 config(AdvisedSupport)实际上是代码块14中的 proxyFactory 对象。

具体为:AbstractAutoProxyCreator 中的 proxyFactory.getProxy 发起的调用,在 ProxyCreatorSupport 使用了 this 作为参数调用了本方法,这边的 this 就是发起调用的 proxyFactory对象,而 proxyFactory 对象中包含了要执行的的拦截器(Advisor)。

无论是创建 JDK 动态代理还是 CGLIB 代理,都会传入 config 参数,该参数会被保存在 advised(AdvisedSupport)变量中,见代码块17。

代码块17:JDK 动态代理、CBLIB 代理构造函数

// JdkDynamicAopProxy.java
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
    Assert.notNull(config, "AdvisedSupport must not be null");
    if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
        throw new AopConfigException("No advisors and no TargetSource specified");
    }
    // config赋值给advised
    this.advised = config;
}

// ObjenesisCglibAopProxy.java
public ObjenesisCglibAopProxy(AdvisedSupport config) {
    super(config);
}

// CglibAopProxy.java
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
    Assert.notNull(config, "AdvisedSupport must not be null");
    if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
        throw new AopConfigException("No advisors and no TargetSource specified");
    }
    this.advised = config;
    this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}

代码块18:JdkDynamicAopProxy#getProxy

@Override
public Object getProxy(ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    }
    // 1.拿到要被代理对象的所有接口
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // 2.通过classLoader、接口、InvocationHandler实现类,来获取到代理对象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

最终,通过 JDK 动态代理的类被调用时,会走到 JdkDynamicAopProxy#invoke 方法。

代码块19:CglibAopProxy#getProxy

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

    try {
        // 1.拿到要代理目标类
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

        // proxySuperClass默认为rootClass
        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            // 如果rootClass是被Cglib代理过的,获取rootClass的父类作为proxySuperClass
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                // 将父类的接口也添加到advised的interfaces属性
                this.advised.addInterface(additionalInterface);
            }
        }

        // Validate the class, writing log messages as necessary.
        // 2.校验proxySuperClass,主要是校验方法是否用final修饰、跨ClassLoader的包可见方法,如果有将警告写入日志
        validateClassIfNecessary(proxySuperClass, classLoader);

        // Configure CGLIB Enhancer...
        // 3.创建和配置Cglib Enhancer
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        // superclass为被代理的目标类proxySuperClass,通过名字可以看出,生成的代理类实际上是继承了被代理类
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        // 4.获取所有要回调的拦截器
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        // fixedInterceptorMap only populated at this point, after getCallbacks call above
        // 在上面调用getCallbacks之后,此时仅填充fixedInterceptorMap
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // Generate the proxy class and create a proxy instance.
        // 5.生成代理类并创建代理实例,返回代理实例
        return createProxyClassAndInstance(enhancer, callbacks);
    } catch (CodeGenerationException 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 (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) {
        // TargetSource.getTarget() failed
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

4.获取所有要回调的拦截器,见代码块20。

代码块20:getCallbacks

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // Parameters used for optimization choices...
    // 1.用于优化选择的参数
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isFrozen = this.advised.isFrozen();
    boolean isStatic = this.advised.getTargetSource().isStatic();

    // Choose an "aop" interceptor (used for AOP calls).
    // 2.使用AdvisedSupport作为参数,创建一个DynamicAdvisedInterceptor(“aop”拦截器,用于AOP调用)
    // this.advised就是之前创建CglibAopProxy时传进来的ProxyFactory(ProxyCreatorSupport子类)
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

    // Choose a "straight to target" interceptor. (used for calls that are
    // unadvised but can return this). May be required to expose the proxy.
    Callback targetInterceptor;
    if (exposeProxy) {
        targetInterceptor = isStatic ?
                new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
    } else {
        targetInterceptor = isStatic ?
                new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
    }

    // Choose a "direct to target" dispatcher (used for
    // unadvised calls to static targets that cannot return this).
    Callback targetDispatcher = isStatic ?
            new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();

    // 3.将aop拦截器添加到mainCallbacks中
    Callback[] mainCallbacks = new Callback[]{
            aopInterceptor,  // for normal advice aop拦截器,因此当代理类被执行时,会走到该拦截器中
            targetInterceptor,  // invoke target without considering advice, if optimized
            new SerializableNoOp(),  // no override for methods mapped to this
            targetDispatcher, this.advisedDispatcher,
            new EqualsInterceptor(this.advised),    // 针对equals方法的拦截器
            new HashCodeInterceptor(this.advised)   // 针对hashcode方法的拦截器
    };

    Callback[] callbacks;

    // If the target is a static one and the advice chain is frozen,
    // then we can make some optimizations by sending the AOP calls
    // direct to the target using the fixed chain for that method.
    if (isStatic && isFrozen) {
        Method[] methods = rootClass.getMethods();
        Callback[] fixedCallbacks = new Callback[methods.length];
        this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);

        // TODO: small memory optimization here (can skip creation for methods with no advice)
        for (int x = 0; x < methods.length; x++) {
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
            fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                    chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
            this.fixedInterceptorMap.put(methods[x].toString(), x);
        }

        // Now copy both the callbacks from mainCallbacks
        // and fixedCallbacks into the callbacks array.
        callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
        System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
        System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
        this.fixedInterceptorOffset = mainCallbacks.length;
    } else {
        callbacks = mainCallbacks;
    }
    return callbacks;
}

最终,通过 CGLIB 代理的类被调用时,会走到 DynamicAdvisedInterceptor#intercept 方法

总结

至此,创建 AOP 代理对象完成

源码剖析-一次请求调用全流程

当我们调用了被 AOP 代理的方法时,使用 JDK 动态代理会走到 JdkDynamicAopProxy#invoke 方法,使用 CBLIB 代理会走到 DynamicAdvisedInterceptor#intercept 方法,两者的内容基本一样,这里就拿更常见的 JdkDynamicAopProxy#invoke 方法来介绍。

JdkDynamicAopProxy#invoke

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;

    // 1.advised就是proxyFactory,而targetSource持有被代理对象的引用
    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;

    try {
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            // 目标不实现equals(Object)方法本身。
            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.
            // 只有getDecoratedClass()声明 - > dispatch到代理配置。
            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...
            // ProxyConfig上的服务调用与代理配置...
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        // 有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理
        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // 2.拿到我们被代理的对象实例
        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }

        // Get the interception chain for this method.
        // 3.获取拦截器链:例如使用@Around注解时会找到AspectJAroundAdvice,还有ExposeInvocationInterceptor
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // 4.检查我们是否有任何拦截器(advice)。 如果没有,直接反射调用目标,并避免创建MethodInvocation。
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 5.不存在拦截器链,则直接进行反射调用
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        } else {
            // We need to create a method invocation...
            // 6.如果存在拦截器,则创建一个ReflectiveMethodInvocation:代理对象、被代理对象、方法、参数、
            // 被代理对象的Class、拦截器链作为参数创建ReflectiveMethodInvocation
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            // 7.触发ReflectiveMethodInvocation的执行方法
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        // 8.必要时转换返回值
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "th, targetClass);

        // 4.检查我们是否有任何拦截器(advice)。 如果没有,直接反射调用目标,并避免创建MethodInvocation。
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 5.不存在拦截器链,则直接进行反射调用
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        } else {
            // We need to create a method invocation...
            // 6.如果存在拦截器,则创建一个ReflectiveMethodInvocation:代理对象、被代理对象、方法、参数、
            // 被代理对象的Class、拦截器链作为参数创建ReflectiveMethodInvocation
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            // 7.触发ReflectiveMethodInvocation的执行方法
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        // 8.必要时转换返回值
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    } finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

3.获取拦截器链:使用 @Around 注解时会找到 AspectJAroundAdvice,还有 ExposeInvocationInterceptor,其中 ExposeInvocationInterceptor 在前,AspectJAroundAdvice 在后。

6.如果存在拦截器,则创建一个 ReflectiveMethodInvocation,代理对象、被代理对象、方法、参数、被代理对象的 Class、拦截器链作为参数。这边 ReflectiveMethodInvocation 已经持有了被代理对象、方法、参数,后续就可以直接使用反射来调用被代理的方法了,见代码块1。

7.触发 ReflectiveMethodInvocation 的执行方法,见代码块2。

代码块1:ReflectiveMethodInvocation 构造函数

protected ReflectiveMethodInvocation(
        Object proxy, Object target, Method method, Object[] arguments,
        Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {

    this.proxy = proxy;
    this.target = target;
    this.targetClass = targetClass;
    this.method = BridgeMethodResolver.findBridgedMethod(method);
    this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
    this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

⭐代码块2:ReflectiveMethodInvocation#proceed()

@Override
public Object proceed() throws Throwable {
    //  We start with an index of -1 and increment early.
    // 1.如果所有拦截器都执行完毕(index是从-1开始,所以跟size - 1比较),则直接使用反射调用连接点(也就是我们原本的方法)
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    // 2.每次调用时,将索引的值递增,并通过索引拿到要执行的拦截器
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // 3.判断拦截器是否为InterceptorAndDynamicMethodMatcher类型(动态方法匹配拦截器)
    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.
        // 4.只是一个普通的拦截器,则触发拦截器链责任链的调用,并且参数为ReflectiveMethodInvocation本身
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

该方法是一个责任链的方法,会按索引执行所有的拦截器。

1.如果所有拦截器都执行完毕(index是从-1开始,所以跟size - 1比较),则直接使用反射调用连接点(也就是我们原本的方法),见代码块3。

4.只是一个普通的拦截器,则直接调用它,参数为自己本身,在本文的例子,interceptorsAndDynamicMethodMatchers 有两个拦截器:ExposeInvocationInterceptor 在前,AspectJAroundAdvice 在后,因此首先会触发 ExposeInvocationInterceptor 的 invoke 方法,见代码块4。

代码块3:invokeJoinpoint()

protected Object invokeJoinpoint() throws Throwable {
    // 反射执行连接点,也就是原方法,target为被代理的对象实例、method为执行的方法、arguments为方法参数
    return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
        throws Throwable {

    // Use reflection to invoke the method.
    try {
        // 使用反射调用方法
        ReflectionUtils.makeAccessible(method);
        return method.invoke(target, args);
    } catch (InvocationTargetException ex) {
        // Invoked method threw a checked exception.
        // We must rethrow it. The client won't see the interceptor.
        throw ex.getTargetException();
    } catch (IllegalArgumentException ex) {
        throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                method + "] on target [" + target + "]", ex);
    } catch (IllegalAccessException ex) {
        throw new AopInvocationException("Could not access method [" + method + "]", ex);
    }
}

代码块4:ExposeInvocationInterceptor#invoke

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    MethodInvocation oldInvocation = invocation.get();
    // 1.设置为当前的MethodInvocation
    invocation.set(mi);
    try {
        // 2.继续进入链中的下一个拦截器。
        return mi.proceed();
    } finally {
        // 3.执行结束设置回原来的MethodInvocation
        invocation.set(oldInvocation);
    }
}

2.继续进入链中的下一个拦截器,该方法会回到代码块1,从而拿到下一个拦截器,并触发其 invoke 方法,在本例中也就是:AspectJAroundAdvice#invoke,见代码块5。

代码块5:AspectJAroundAdvice#invoke

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    // 1.这边的mi就是我们的ReflectiveMethodInvocation,
    // ReflectiveMethodInvocation实现了ProxyMethodInvocation接口,所以这边肯定通过校验
    if (!(mi instanceof ProxyMethodInvocation)) {
        throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    }
    // 2.将mi直接强转成ProxyMethodInvocation,mi持有代理类实例proxy、被代理类实例target、被代理的方法method等
    ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
    // 3.将pmi封装层MethodInvocationProceedingJoinPoint(直接持有入参mi,也就是ReflectiveMethodInvocation的引用)
    ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
    // 4.拿到pointcut的表达式
    JoinPointMatch jpm = getJoinPointMatch(pmi);
    // 5.调用增强方法
    return invokeAdviceMethod(pjp, jpm, null, null);
}

5.调用增强方法,见代码块6。

代码块6:invokeAdviceMethod

protected Object invokeAdviceMethod(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable t)
        throws Throwable {
    // 1.argBinding:获取方法执行连接点处的参数
    // 2.invokeAdviceMethodWithGivenArgs:使用给定的参数调用增强方法
    return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

1.获取方法执行连接点处的参数,见代码块7。

2.使用 argBinding 方法返回的参数调用增强方法,在本文给出的例子中,也就是 LogInterceptor 中被 @Around 修饰的 around(ProceedingJoinPoint pjp) 方法,见代码块8。

代码块7:argBinding

protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object returnValue, Throwable ex) {
    calculateArgumentBindings();

    // AMC start
    Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
    int numBound = 0;

    if (this.joinPointArgumentIndex != -1) {
        // 1.如果存在连接点参数,则将jp添加到调用参数
        // 当使用@Around时就有参数;使用@Before、@After时就没有参数
        adviceInvocationArgs[this.joinPointArgumentIndex] = jp;
        numBound++;
    } else if (this.joinPointStaticPartArgumentIndex != -1) {
        adviceInvocationArgs[this.joinPointStaticPartArgumentIndex] = jp.getStaticPart();
        numBound++;
    }

    if (!CollectionUtils.isEmpty(this.argumentBindings)) {
        // binding from pointcut match
        // 2.使用pointcut匹配绑定
        if (jpMatch != null) {
            PointcutParameter[] parameterBindings = jpMatch.getParameterBindings();
            for (PointcutParameter parameter : parameterBindings) {
                String name = parameter.getName();
                Integer index = this.argumentBindings.get(name);
                adviceInvocationArgs[index] = parameter.getBinding();
                numBound++;
            }
        }
        // binding from returning clause
        // 3.用于绑定@AfterReturing中的returning参数
        if (this.returningName != null) {
            Integer index = this.argumentBindings.get(this.returningName);
            adviceInvocationArgs[index] = returnValue;
            numBound++;
        }
        // binding from thrown exception
        // 4.用于绑定@AfterThrowing中的throwing参数
        if (this.throwingName != null) {
            Integer index = this.argumentBindings.get(this.throwingName);
            adviceInvocationArgs[index] = ex;
            numBound++;
        }
    }

    if (numBound != this.parameterTypes.length) {
        throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
                " arguments, but only bound " + numBound + " (JoinPointMatch " +
                (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
    }

    return adviceInvocationArgs;
}

1.如果存在连接点参数,则将 jp 添加到增强方法的参数数组,对于 @Around 来说,这边的 jp 就是代码块5中的入参 mi,也就是我们之前创建的 ReflectiveMethodInvocation 对象。所以,当使用 @Around 时,这边返回的增强方法的参数数组持有的是 ReflectiveMethodInvocation 对象。

代码块8:invokeAdviceMethodWithGivenArgs

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
    Object[] actualArgs = args;
    // 1.如果增强方法没有参数,则将actualArgs赋值为null
    if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
        actualArgs = null;
    }
    try {
        ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
        // TODO AopUtils.invokeJoinpointUsingReflection
        // 2.反射执行增强方法
        return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
    } catch (IllegalArgumentException ex) {
        throw new AopInvocationException("Mismatch on arguments to advice method [" +
                this.aspectJAdviceMethod + "]; pointcut expression [" +
                this.pointcut.getPointcutExpression() + "]", ex);
    } catch (InvocationTargetException ex) {
        throw ex.getTargetException();
    }
}

2.反射执行增强方法,对于本文给出的例子,这边会直接走到 LogInterceptor 中被 @Around 修饰的 around(ProceedingJoinPoint pjp) 方法,该方法会执行一些增强逻辑,最终执行 “Object result = pjp.proceed()”。

通过代码块6和代码块7我们知道,这边的 pjp 就是我们之前创建的 ReflectiveMethodInvocation 对象,所以这边会再次调用 ReflectiveMethodInvocation 对象的 process() 方法,也就是回到代码块2。此时我们的拦截器都已经执行完毕,因此会走到 invokeJoinpoint() 方法,通过反射执行我们被代理的方法,也就是 getName(String name) 方法。

至此,AOP 的一次调用流程就全部走通了。

总结

AspectJ 方式的 AOP 内容到此就介绍完毕了,核心流程如下。

1)解析 AOP 的注解,并注册对应的内部管理的自动代理创建者的 bean,对于本次介绍是:AnnotationAwareAspectJAutoProxyCreator,其他的还有 InfrastructureAdvisorAutoProxyCreator 和 AspectJAwareAdvisorAutoProxyCreator。

2)当我们的 bean 初始化完毕后,会触发所有 BeanPostProcessor 的 postProcessAfterInitialization 方法,此时就会调用我们的 AnnotationAwareAspectJAutoProxyCreator 的 postProcessAfterInitialization 方法。该方法会查找我们定义的切面类(使用 @Aspect 注解),创建切面类中定义的增强器(使用 @Before、@After、@Around 等注解),并根据 @Pointcut 的 execution 表达式筛选出适用于当前遍历的 bean 的增强器, 将适用于当前遍历的 bean 的增强器作为参数之一创建对应的 AOP 代理。

3)当调用到被 AOP 代理的方法时,会走到对应的代理方法:JdkDynamicAopProxy#invoke 或 DynamicAdvisedInterceptor#intercept,该方法会创建 ReflectiveMethodInvocation,通过责任链的方式来执行所有的增强器和被代理的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/899021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java面试题】线程中start方法和run方法的区别?

start start作用是启动一个新线程。 当用start()开始一个线程后&#xff0c;线程就进入就绪状态&#xff0c;使线程所代表的虚拟处理机处于可运行状态&#xff0c;这意味着它可以由JVM调度并执行。但是这并不意味着线程就会立即运行。只有当CPU分配时间片时&#xff0c;这个线…

05_bitmaphyperloglogGEO

Bitmap&hyperloglog&GEO 面试问 记录对集合中的数据进行统计在移动应用中&#xff0c;需要统计每天的新增用户数和第2天的留存用户数&#xff1b;在电商网站的商品评论中&#xff0c;需要统计评论列表中的最新评论&#xff1a;在签到打卡中&#xff0c;需要统计一个月内…

Learning to Super-resolve Dynamic Scenes for Neuromorphic Spike Camera论文笔记

摘要 脉冲相机使用了“integrate and fire”机制来生成连续的脉冲流&#xff0c;以极高的时间分辨率来记录动态光照强度。但是极高的时间分辨率导致了受限的空间分辨率&#xff0c;致使重建出的图像无法很好保留原始场景的细节。为了解决这个问题&#xff0c;这篇文章提出了Sp…

亚马逊产品排名关键因素解析,通过测评干预需要具备哪些条件

亚马逊产品排名的高低意味着分配的流量多少以及销量的高低。影响产品排名的因素主要包括以下四个方面&#xff1a; 1. 产品销量 产品销量是反映产品在同类产品销售情况的一个重要指标。它在产品Listing中展示&#xff0c;并且平台每小时会更新一次该排行榜。平台算法认为&…

设计模式之状态模式(State)的C++实现

1、状态模式的提出 在组件功能开发过程中&#xff0c;某些对象的状态经常面临变化&#xff0c;不同的状态&#xff0c;其对象的操作行为不同。比如根据状态写的if else条件情况&#xff0c;且这种条件变化是经常变化的&#xff0c;这样的代码不易维护。可以使用状态模式解决这…

用ceres实现lio-sam角点匹配

文章开始先扯一堆废话&#xff0c;lio-sam作者手推平面点和角点匹配&#xff0c;对于初学者&#xff0c;尤其数学不好者学习有一定难度&#xff0c;对于工程落地和后期优化而言难度较大。本文基于主流优化库实现角点匹配&#xff0c;以下内容均为原创和作者实测干货&#xff08…

学习笔记230802---vue项目手写css样式二次悬浮状态问题

问题描述 今天在开发页面时&#xff0c;遇到一个很棘手的问题&#xff0c;需求页面做一个卡片效果&#xff0c;鼠标悬浮在卡片上&#xff0c;出现一个选项卡&#xff0c;鼠标悬浮每一项&#xff0c;文字和图标都要变成选中状态的颜色。选项卡的每一项都是通过数据循环渲染来的…

Selenium自动化测试面试必备:高频面试题及答案整理

自动化测试已经成为现代软件测试中不可或缺的一部分。在自动化测试中&#xff0c;Selenium是最受欢迎的工具之一&#xff0c;因为它可以模拟用户与Web应用程序的交互。因此&#xff0c;对于许多测试工程师来说&#xff0c;熟练掌握Selenium框架是非常重要的。如果你正在寻找一份…

CW12B-3A-RCWW12B-6A-RCW12B-10A-RCWW12B-20A-RCWW12B-30A-RCWW12B-40A-R导轨式滤波器

CW4L2-3A-R1 CW4L2-6A-R1 CW4L2-10A-R1 CW4L2-20A-R1 CW4L2-30A-R1导轨式滤波器 CW12B-3A-R CWW12B-6A-R CW12B-10A-R CWW12B-20A-R CWW12B-30A-R CWW12B-40A-R导轨式滤波器 CW12C-3A-R CWW12C-6A-R CWW12C-10A-R CW12C-20A-R CW12C-30A-R导轨式滤波器 CW4L2-3A-R…

Python学习之操作XML文件详解

概要 我们经常需要解析用不同语言编写的数据&#xff0c;Python 提供了许多第三方库来解析或拆分用其他语言编写的数据&#xff0c;今天我们来学习下 Python XML 解析器的相关功能。 什么是 XML&#xff1f; XML 是可扩展标记语言&#xff0c;它在外观上类似于 HTML&#xff…

all in one之安装zerotier(第四章)

好像zerotier国内ipv4不能使用 pve安装zerotier 内网穿透软件总结参考 安装参考教程 安装命令&#xff1a; curl -s https://install.zerotier.com | sudo bash官网 如果有以下问题&#xff0c;进行解决&#xff0c;如果没有则跳过。 问题&#xff1a;-bash: sudo: comman…

每天一道leetcode:127. 单词接龙(图论困难建图广度优先遍历)

今日份题目&#xff1a; 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk&#xff1a; 每一对相邻的单词只差一个字母。 对于 1 < i < k 时&#xff0c;每个 si 都在 wordList 中…

2023全网Mysql 合集(25w字)附课程 从安装到高级,实战

mysql学习 1.安装mysql 安装教程 2.mysql的详细学习教程 mysql的详细教程 3.mysql 的高级优化 MySQL高级篇&#xff08;SQL优化、索引优化、锁机制、主从复制&#xff09; 4.MySQL 面试 MySQL数据库面试题总结 二.mysql实战 一、创建数据表并插入数据 1、学生表 Stud…

【python办公自动化】PysimpleGUI中的popup弹窗中的按钮设置居中

PysimpleGUI中的popup弹窗中的按钮设置居中 背景问题解决背景 默认的popup弹窗中的OK按钮是在最下面偏左侧一些,有时需要将按钮放置居中 问题解决 首先找到pysimplegui源代码文件中popup的部分 然后定位到19388行,源文件内容如下 关于popup弹窗OK按钮的设置,将pad属性…

C语言好题解析(三)

目录 选择题一选择题二选择题三选择题四编程题一编程题二 选择题一 以下程序段的输出结果是&#xff08;&#xff09;#include<stdio.h> int main() { char s[] "\\123456\123456\t"; printf("%d\n", strlen(s)); return 0; }A: 12 B: 13 …

《算法竞赛·快冲300题》每日一题:“糖果配对”

《算法竞赛快冲300题》将于2024年出版&#xff0c;是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码&#xff0c;以中低档题为主&#xff0c;适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 糖…

使用自己的领域数据扩充baichuan模型词表(其他模型也一样)

文章目录 前言环境项目结构一、使用步骤二、训练词表三、合并词表四、效果前言 总的来说,扩充词表可以加快解码速度,对于对中文支持不太友好的模型(如llama),扩充词表还能提升模型在中文的表现。 环境 jsonlines==3.1.0 sentencepiece==0.1.99 transformers==4.28.1项目…

【Golang系统开发】搜索引擎(3) 压缩倒排索引表

写在前面 假设我们的数据集中有 800000 篇文章&#xff0c;每篇文章有 200 词条&#xff0c;每个词条有6个字符&#xff0c;倒排记录数目是 1 亿。那么如果我们倒排索引表中单单记录文档id&#xff0c;不记录文档内的频率和偏移信息。 那么 文档id 的长度就必须是 l o g 2 8…

04.Show, Attend and Tell

目录 前言泛读摘要IntroductionRelated Work小结 精读编码器&#xff1a;特征卷积解码器&#xff1a;LSTM网络随机硬注意力和确定软注意力机制硬注意力软注意力双重随机注意力 训练实验数据集评估过程定量分析定性分析 结论 代码&#xff08;略&#xff09; 前言 本课程来自深…

前端单点登录SSO面试回答

JWT鉴权机制 1.JWT用于登录身份验证 2.用户登录成功后&#xff0c;后端通过JWT机制生成一个token&#xff0c;返回给客户端 3.客户端后续的每次请求都需要携带token&#xff0c;放在header的authorization中 4.后端从authorization中拿到token后&#xff0c;通过secretKey进…