Spring AOP 源码分析

news2024/12/27 13:59:12

【阅读前提】: 需了解AOP注解开发流程:链接

一、注解 @EnableAspectJAutoProxy

在配置类中添加注解@EnableAspectJAutoProxy,便开启了AOP(面向切面编程) 功能。此注解也是了解AOP源码的入口。

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {

【1】@EnableAspectJAutoProxy是什么?我们进入注解,查看其源码如下:发现调用EnableAspectJAutoProxy类,同时使用 @Import注解向容器中导入 AspectJAutoProxyRegistrar 组件:作用是给容器中注册自定义的Bean

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

【2】进入AspectJAutoProxyRegistrar类,调用registerBeanDefinitions中的register...Necessary方法注册组件。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

             //向容器(registry)中注入组件	
             AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

【3】 进入register...Necessary方法,通过源码分析:该方法向容器中注册一个AnnotationAwareAspectJAutoProxyCreator(支持注解模式的面向切面自动代理创建器)组件,其名称为internalAutoProxyCreator。需要注意的是其注册的是一个BeanDefinitionBean的定义信息,并没有实例化。后续分析时会说到) 。

//debug 进来后,发现cls参数的值等于 AnnotationAwareAspectJAutoProxyCreator 这个参数也是直接写死的,如下:。
//registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
		Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	//AUTO_PROXY_CREATOR_BEAN_NAME == internalAutoProxyCreator 
	//因第一次进来,所以容器中不存在 internalAutoProxyCreator 
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}
	//创建一个新的对象封装 cls
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	//将封装的cls对象注册到容器中,并将名称定义为AUTO_PROXY_CREATOR_BEAN_NAME == internalAutoProxyCreator 就上上述判断的语句。
	//此时我们就应该分析 AnnotationAwareAspectJAutoProxyCreator对象的作用
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

二、研究AnnotationAwareAspectJAutoProxyCreator

此自动代理创建器的内部功能,其等价于AOP的主要功能。 此类的继承结构如下:

我们进入自动代理的抽象父类AbstractAutoProxyCreator中发现,其实现了SmartInstantiationAwareBeanPostProcessor后置处理器(在bean初始化前后做一些操作,AOP的特点)和BeanFactoryAware自动装配BeanFactory

@SuppressWarnings("serial")
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

AOP原理分析技巧:【看给容器中注册了什么组件, 这个组件什么时候工作,这个组件的功能是什么?】,研究透这些,原理也就清楚了。

我们从AbstractAutoProxyCreator父类向AnnotationAwareAspectJAutoProxyCreator子类的顺序,查看其内部关于后置处理器和自动装备的方法并加入断点:

【1】AbstractAutoProxyCreator:包含后置处理器前后的两个方法和自动装配的方法。

//后置处理器相关的方法1
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
	Object cacheKey = getCacheKey(beanClass, beanName);

	if (!StringUtils.hasLength(beanName) || !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;
		}
	}

//后置处理器相关的方法2
@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;
}

//自动装备相关的方法
@Override
public void setBeanFactory(BeanFactory beanFactory) {
	this.beanFactory = beanFactory;
}

【2】AbstractAdvisorAutoProxyCreator:重写了setBeanFactory方法。

//自动装备方法
@Override
public void setBeanFactory(BeanFactory beanFactory) {
	super.setBeanFactory(beanFactory);
	if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
		throw new IllegalArgumentException(
				"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
	}
	initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

【3】对 2中的initBeanFactory方法进行了重写。

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	super.initBeanFactory(beanFactory);
	if (this.aspectJAdvisorFactory == null) {
		this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
	}
	this.aspectJAdvisorsBuilder =
			new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

三、Debug 测试类流程梳理

【1】创建 IOC 容器,传入主配置类MainConfigOfAOP

//获取容器中的类
ApplicationContext ApplicationContext = 
                                    new AnnotationConfigApplicationContext(MainConfigOfAOP.class);

【2】调用AnnotationConfigApplicationContext构造器:注册配置类和刷新容器(创建容器中的所有Bean,类似于初始化容器)

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        //创建对象
	this();
        //注册配置类
	register(annotatedClasses);
        //刷新容器
	refresh();
}

【3】调用refresh方法:主要查看registerBeanPostProcessors(beanFactory); 方法,其作用是注册bean后置处理器,用方便来拦截bean的创建。

@Override
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
        ....
	// 注册 bean 后置处理器,用来拦截 bean 的创建
	registerBeanPostProcessors(beanFactory);
        ....
}

【4】进入registerBeanPostProcessors调用的方法:先获取 IOC 容器中已经定义了的需要创建对象的所有后置处理器BeanPostProcessor(已定义:指我们在解析配置类的时候@EnableAspectJAutoProxy会为我们注册一个AnnotationAwareAspectJAutoProxyCreator后置处理器的定义,包括默认的一些后置处理器的定义)例如:

上述列表中的internalAutoProxyCreator后置处理器,就是我们分析@EnableAspectJAutoProxy时注入的那个处理器。后置处理的注册分为以下三种情况:
 ■ 优先注册实现了PriorityOrdered(优先级)接口的BeanPostProcessors
 ■ 其次注册实现了Ordered接口的BeanPostProcessors
 ■ 注册所有常规Beanpstprocessors
internalAutoProxyCreator后置处理器实现了Ordered接口。分析代码可知:【根据bean定义名称internalAutoProxyCreatorbeanFactory中获取注入的后置处理器】调用的方法 = beanFactory.getBean(ppName, BeanPostProcessor.class);

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    //获取ioc容器中已经定义了的需要创建对象的所有 BeanPostProcessor
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

    //也会注意一些其他后置处理器,bean 是在 beanPostProcessor 实例化期间创建的,即 bean 不适合由所有 beanPostProcessors 处理。这个其实不重要,可以省略...
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 +    postProcessorNames.length;
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    //判断哪些后置处理器配置了优先级
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
	    BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
	    priorityOrderedPostProcessors.add(pp);
	    if (pp instanceof MergedBeanDefinitionPostProcessor) {
	        internalPostProcessors.add(pp);
	    }
	}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
	    orderedPostProcessorNames.add(ppName);
	}else {
	    nonOrderedPostProcessorNames.add(ppName);
	}
    }
    // 优先注册实现了 PriorityOrdered(优先级) 的 BeanPostProcessors
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

    // 其次注册实现了Ordered 接口的 BeanPostProcessors.
    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String ppName : orderedPostProcessorNames) {
        //根据 bean定义的名称internalAutoProxyCreator 从 beanFactory 中获取注入的后置处理器
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
	orderedPostProcessors.add(pp);
	if (pp instanceof MergedBeanDefinitionPostProcessor) {
	    internalPostProcessors.add(pp);
	}
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, orderedPostProcessors);

    // 注册所有常规beanpstprocessors。
    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String ppName : nonOrderedPostProcessorNames) {
	    BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
	    nonOrderedPostProcessors.add(pp);
	    if (pp instanceof MergedBeanDefinitionPostProcessor) {
	        internalPostProcessors.add(pp);
	    }
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

    // 最后,重新注册所有内部beanpstprocessors。
    sortPostProcessors(internalPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, internalPostProcessors);

【5】进入上述所说的beanFactory.getBean(ppName, BeanPostProcessor.class); 方法如下:因第一次进入容器,因此获取不到实例。会通过 getSingleton方法创建BeanPostProcessor的实例,并保存到容器中。

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	return doGetBean(name, requiredType, null, false);
}


//上述方法内部调用的是 doGetBean(name, requiredType, null, false); 代码如下:
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //因为第一次获取,容器中不存在此实例。因此 sharedInstance==null
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
        ...
        }else {
	    // 创建 bean 实例
	    if (mbd.isSingleton()) {
	        sharedInstance = getSingleton(beanName, () -> {
	        try {
		    return createBean(beanName, mbd, args);
	        }catch (BeansException ex) {
		    destroySingleton(beanName);
		    throw ex;
	        }
	    });
	    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	    }
    }

【6】创建internalAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator实例。步骤如下:

//1、创建bean的实例
createBean(beanName, mbd, args);
//2、给Bean 的各属性赋值
populateBean(beanName, mbd, instanceWrapper);
//3、初始化 bean ,比较重要,因为后置处理器就是在此前后进行工作的
exposedObject = initializeBean(beanName, exposedObject, mbd);

【7】重点是:初始化initializeBean方法,查看实现的步骤如下:

//1、调用 invokeAwareMethods 处理Aware 接口的方法回调,beanName=internalAutoProxyCreator 实现了 BeanAware 接口
invokeAwareMethods(beanName, bean);
//2、应用后置处理器 BeforeInitialization
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
//3、执行自定义的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
//4、执行后置处理器的 After方法
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

//下面是上述方法的具体实现

//1、invokeAwareMethods 实现如下:
private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
                //.....
                //实现了 BeanFactoryAware 接口,因此执行 setBeanFactory.
                //bean==AnnotationAwareAspectJAutoProxyCreator
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}


//2、applyBeanPostProcessorsBeforeInitialization 实现如下:
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    throws BeansException {

	Object result = existingBean;
        //获取所有的后置处理器,执行前置Before 处理器。
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

//3、invokeInitMethods 方法的具体实现
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
		throws Throwable {

	boolean isInitializingBean = (bean instanceof InitializingBean);
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
		}
		if (System.getSecurityManager() != null) {
			try {
				AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
					((InitializingBean) bean).afterPropertiesSet();
					return null;
				}, getAccessControlContext());
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			((InitializingBean) bean).afterPropertiesSet();
		}
	}

	if (mbd != null && bean.getClass() != NullBean.class) {
		String initMethodName = mbd.getInitMethodName();
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}

//4、applyBeanPostProcessorsAfterInitialization 具体实现
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
		Object current = processor.postProcessAfterInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

【8】执行Aware初始化时,会调用setBeanFactory方法,我们追下去会发现调用的是AbstractAdvisorAutoProxyCreatorsetBeanFactory方法(就是我们分析AnnotationAwareAspectJAutoProxyCreator继承关系时的父类 )。

AnnotationAwareAspectJAutoProxyCreator(AbstractAdvisorAutoProxyCreator).setBeanFactory(BeanFactory)line:58
@Override
public void setBeanFactory(BeanFactory beanFactory) {
        //调用父类的 setBeanFactory
	super.setBeanFactory(beanFactory);
	if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
		throw new IllegalArgumentException(
				"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
	}
        //AnnotationAwareAspectJAutoProxyCreator  方法对此进行了重写
	initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}

【9】进入initBeanFactory方法,我们知道此方法已被AnnotationAwareAspectJAutoProxyCreator重写:

//位于 AnnotationAwareAspectJAutoProxyCreator 类中
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	super.initBeanFactory(beanFactory);
	if (this.aspectJAdvisorFactory == null) {
                //创建了放射的通知工厂
		this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
	}
	this.aspectJAdvisorsBuilder =
			new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

【10】最终BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功,将其添加到beanFactory中。

for (String ppName : orderedPostProcessorNames) {
        //实例 pp==AnnotationAwareAspectJAutoProxyCreator 
	BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        //放入 ordered后置处理器集合
	orderedPostProcessors.add(pp);
	if (pp instanceof MergedBeanDefinitionPostProcessor) {
		internalPostProcessors.add(pp);
	}
}
//将处理器按优先级排序
sortPostProcessors(orderedPostProcessors, beanFactory);
//调用注册方法
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

//上述注册方法的内部代码
private static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
        //将后置处理器都添加到bean工厂
	for (BeanPostProcessor postProcessor : postProcessors) {
		beanFactory.addBeanPostProcessor(postProcessor);
	}
}

四、后置处理器创建后的操作

【1】以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程。接下来就是对创建后的流程进行说明:AnnotationAwareAspectJAutoProxyCreator是继承InstantiationAwareBeanPostProcessor的后置处理器:我们在上面说的IOC容器初始化时,会调用 refresh方法:我们进入此方法看下,我们之前分析registerBeanPostProcessors方法,接下来分析finishBeanFactoryInitialization方法(实例所有剩余的单实例bean)完成BeanFactory初始化工作。

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
	//......
	// 注册 bean后置处理器 来拦截 bean 的创建。
	registerBeanPostProcessors(beanFactory);
	//......
	// 初始化特定上下文子类中的其他特殊bean。
	onRefresh();
	//......
	// 实例化所有剩余的(非延迟初始化)单例。
	finishBeanFactoryInitialization(beanFactory);
}

【2】遍历获取容器中所有的Bean,依次创建对象 getBean(beanName); 流程:getBean->doGetBean()->getSingleton()getBean方法如下:先从缓存中获取当前bean,如果能获取到说明bean是之前被创建过的,直接使用,否则创建bean;只要是创建好的bean都会被缓存起来。

// 先检查单例缓存中是否有已存在手动注册的单例,如果存在说明之前bean已创建
Object sharedInstance = getSingleton(beanName);
//缓存中不存在 bean 时才创建该单例 bean
if (sharedInstance != null && args == null) {
	//...
}else{
	//创建bean实例。
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				destroySingleton(beanName);
				throw ex;
			}
		});
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
}

【2.1】进入创建bean的步骤:createBean方法,首先会调用resolveBeforeInstantiation方法,让beanPostProcessors后置处理器有机会返回代理对象而不是目标bean实例。如果能返回则直接使用,如果不能则调用doCreateBean方法来创建实例。

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
        /*现获取类的基本信息 例如:
        Root bean: class [org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator]; 
        scope=singleton等等*/
        RootBeanDefinition mbdToUse = mbd;
	//......
	//让beanPostProcessors有机会返回代理而不是目标bean实例。		
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
	}
	//通过此方法,先调用 aware、前置处理器、bean初始化、后置处理器 ,之前有分析过。
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

BeanPostProcessor是在Bean对象创建完成初始化前后调用的】
InstantiationAwareBeanPostProcessor是在创建bean实例之前先尝试用后置处理器返回代理对象】
 后置处理器与后置处理器不同,具体什么时候调用,需要根据不同情况而定。

【2.1.1】分析resolveBeforeInstantiation方法(让beanPostProcessors有机会返回代理对象):我们分析的AnnotationAwareAspectJAutoProxyCreator就是InstantiationAwareBeanPostProcessor类型的后置处理器。会在任何bean创建之前先尝试返回bean的代理实例。

@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
	if (bean != null) {
		bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
	}
}

//上面两个方法的源码展示
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
	//获取所有的后置处理器
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		//如果后置处理器是 InstantiationAwareBeanPostProcessor 类型的处理器则执行 postProcessBeforeInstantiation 方法。
		//我们分析的 AnnotationAwareAspectJAutoProxyCreator 就是 InstantiationAwareBeanPostProcessor 类型的处理器
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			//***** 后续分析
			Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
	}
	return null;
}

【2.1.1.1】接着分析上述的postProcessBeforeInstantiation方法:内容较多,放在五中分析。

【2.1.2】分析doCreateBean方法,之前有介绍过,我们在看下源码:就是对创建的目标类前后对后置处理器的方法进行初始化。才是真正创建一个bean的实例。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
    //创建 bean 实例
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    //bean 属性赋值
    populateBean(beanName, mbd, instanceWrapper);
    //初始化 bean
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}


//初始化方法 initializeBean 的源码
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	//初始化 aware 接口的类
	invokeAwareMethods(beanName, bean);
	//后置处理器 Before 方法初始化
	wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	//初始化类
	invokeInitMethods(beanName, wrappedBean, mbd);
	//后置处理器 after 方法初始化
	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	//返回创建好的类
	return wrappedBean;
}

五、postProcessBeforeInstantiation方法分析

【1】每个bean创建之前,调用此方法。我们主要观察业务逻辑MathCalculator类和切面LogAspects类的创建。

//当bean = MathCalculator or LogAspects 我们着重分析此方法,其他的略过
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
	Object cacheKey = getCacheKey(beanClass, beanName);
        
	if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
                //判断当前 bean 是否在 advisedBeans 中(保存了所有需要增加的 bean:意思就是添加了切面的内容),第一次进行肯定是不包含的所以会跳过
		if (this.advisedBeans.containsKey(cacheKey)) {
			return null;
		}
                //isInfrastructureClass 判断当前类是否为基础类型的,也就是实现了 Advice、Pointcut、Advisor、AopInfrastructureBean 
                //或者是否为切面注解标注的类 (@Aspect),第一个 MathCalculator = false
                //shouldSkip 是否需要跳过:内部是获取候选的增强器(也就是切面内的通知方法)
                //将所有的增强器封装成了 List<Advisor> 集合,增强器的类型是 InstantiationModelAwarePointcutAdvisor
		if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return null;
		}
	}
        // targetSource = null
	TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
	if (targetSource != null) {
		if (StringUtils.hasLength(beanName)) {
			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;
	}
        //直接返回空,进入我们配置类中,创建 MathCalculator 对象
	return null;
}

【2】上述代码中的shouldSkip源码:

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
	//获取所有的增强器 考虑通过缓存方面名称列表进行优化
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	for (Advisor advisor : candidateAdvisors) {
                //我们的增强器都是 InstantiationModelAwarePointcutAdvisor 类型的,不是AspectJPointcutAdvisor 所以跳过
		if (advisor instanceof AspectJPointcutAdvisor &&
				((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
			return true;
		}
	}
        //父类直接返回 false
	return super.shouldSkip(beanClass, beanName);
}

【3】创建完MathCalculator后,调用postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
                // cacheKey = calculator
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
                //判断之前是否代理过
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                        //包装目标类,如果需要的话
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

【3.1】查看包装方法wrapIfNecessary的源码:分析后得出如下结论:以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //...... 省略的都是判断是否为切面类或以代理类
    //如果需要就创建代理类
    //getAdvicesAndAdvisorsForBean 获取能在当前类使用的增强器
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        //保存当前 bean 在advisedBeans 表示当前bean 被处理了
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        //创建代理对象 ****重点,返回的是一个通过 Cglib 代理的对象
	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;

【3.1.1】进入当前类使用的增强器方法:getAdvicesAndAdvisorsForBean

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
		Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        //获取可用的增强器
	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	if (advisors.isEmpty()) {
		return DO_NOT_PROXY;
	}
	return advisors.toArray();
}

【3.1.1.1】进入获取可用增强器的方法:findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        //获取后置增强器
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
        //找到能在当前bean中使用的增强器(找那些方法能够切入到当前方法的)
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
                //对增强器进行了排序
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}

//上面获取当前bean中使用的增强器的方法源码
protected List<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
                //通过 AopUtils工具类获取所有的通知方法
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	}
	finally {
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}

//工具类方法源码展示
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
	if (candidateAdvisors.isEmpty()) {
		return candidateAdvisors;
	}
	List<Advisor> eligibleAdvisors = new ArrayList<>();
	for (Advisor candidate : candidateAdvisors) {
                //我们的增强器不是此类型
		if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
			eligibleAdvisors.add(candidate);
		}
	}
	boolean hasIntroductions = !eligibleAdvisors.isEmpty();
	for (Advisor candidate : candidateAdvisors) {
		if (candidate instanceof IntroductionAdvisor) {
			// already processed
			continue;
		}
                //判断增强器是否可用,我们的都是可用的
		if (canApply(candidate, clazz, hasIntroductions)) {
                        //将所有可以使用的增强器,加入到可用的增强器集合中
			eligibleAdvisors.add(candidate);
		}
	}
	return eligibleAdvisors;
}

//判断是否为可用的增强器的方法 canApply源码:
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	if (advisor instanceof IntroductionAdvisor) {
		return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
	}
        //查看切面的方法是否都能匹配
	else if (advisor instanceof PointcutAdvisor) {
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	}
	else {
		// It doesn't have a pointcut so we assume it applies.
		return true;
	}
}

【3.1.2】进入代理对象的创建方法: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[] 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());
}

【3.1.2.1】进入代理工厂创建对象的方法proxyFactory.getProxy的源码:

public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}

//进入 createAopProxy().getProxy 内部的内部方法
@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.");
		}
                //创建 JDK 代理或者 Cglib 代理。如果实现了接口则使用 JDK 代理,否则Cglib 代理
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

六、目标方法执行

【1】容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如:增强器,目标对象…)

【2】CglibAopProxy.intercept(); 拦截目标方法执行如下:主要是根据ProxyFactory对象获取将要执行的目标方法的拦截器链。
 1)、如果没有拦截器链,直接执行目标方法。
 2)、如果有拦截器链,吧需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation对象,并调用retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 方法。

@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;
	Object target = null;
	TargetSource targetSource = this.advised.getTargetSource();
	try {
		if (this.advised.exposeProxy) {
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);
                //根据 ProxyFactory 对象获取将要执行的目标方法的拦截器链
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
                //如果没有拦截器链,直接执行目标方法。
		if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = methodProxy.invoke(target, argsToUse);
		}
                //如果有拦截器链,吧需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用如下方法。
		else {
			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
		}
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
	finally {
		//......
	}
}

【3】 拦截器链:List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice的源码展示:
 1)、List<Object> interceptorList中保存了所有拦截器,总计5个。一个默认的ExposeInvocationInterceptor和 4个增强器。
 2)、遍历所有的增强器,将其转为Interceptor(拦截器):registry.getInterceptors(advisor);

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, @Nullable Class<?> targetClass) {

	//......
	//获取所有的增强器进行遍历
	for (Advisor advisor : advisors) {
		//判断是否为切面的增强器
		if (advisor instanceof PointcutAdvisor) {
			//......
                        //将增强器转化为 MethodInterceptor
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        if (mm.isRuntime()) {
				for (MethodInterceptor interceptor : interceptors) {
					interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
				}
			}
			else {
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		else if (advisor instanceof IntroductionAdvisor) {
			IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
			if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		else {
			Interceptor[] interceptors = registry.getInterceptors(advisor);
			interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	return interceptorList;
}

 3)、将增强器转为MethodInterceptor,转化方式如下:最终返回拦截器链(每一个通知方法又被包装为方法拦截器,后期都是利用MethodInterceptor机制)。

@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
	List<MethodInterceptor> interceptors = new ArrayList<>(3);
	Advice advice = advisor.getAdvice();
        //如果是 MethodInterceptor 直接加入到 list 中
	if (advice instanceof MethodInterceptor) {
		interceptors.add((MethodInterceptor) advice);
	}
        //如果不是则,使用 AdvisorAdapter 将增强器转为 MethodInterceptor
	for (AdvisorAdapter adapter : this.adapters) {
		if (adapter.supportsAdvice(advice)) {
			interceptors.add(adapter.getInterceptor(advisor));
		}
	}
	if (interceptors.isEmpty()) {
		throw new UnknownAdviceTypeException(advisor.getAdvice());
	}
	return interceptors.toArray(new MethodInterceptor[0]);
}

【4】拦截器链有了之后,创建CglibMethodInvocation并执行proceed方法:

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

七、拦截器链的触发过程

【1】拦截器链展示:除了默认的方法ExposeInvocationInterceptor剩下的 4个都是我们切面中的方法。

【2】如果没有拦截器执行目标方法执行代理对象CglibMethodInvocationproceed方法:

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

【3】进入proceed方法:

@Override
@Nullable
public Object proceed() throws Throwable {
	//判断连接器栏的长度是否 == 0,此方法会在拦截器链的最后一个链时调用
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                //执行目标方式,输入为:MathCalculator...div...
		return invokeJoinpoint();
	}
	//获取下标=0的拦截器 ExposeInvocationInterceptor
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		//下标0 跳过......
	}
	else {
		// this=ReflectiveMethodInvocation
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

【4】进入[MethodInterceptor] interceptorOrInterceptionAdvice).invoke(this); 方法:会循环调用list中的拦截器,直到后置处理器:AspectJMethodBeforeAdvice

//ThreadLocal 线程共享数据 (共享 MethodInvocation)
private static final ThreadLocal<MethodInvocation> invocation =
		new NamedThreadLocal<>("Current AOP method invocation");

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
	//获取 invocation 
	MethodInvocation oldInvocation = invocation.get();
        //将当前方法,放入 invocation
	invocation.set(mi);
	try {
                //执行 cglib 的proceed() 就获取到了下标为1的拦截器 AspectJAfterThrowingAdvice
		return mi.proceed();
	}
	finally {
                //执行后置通知
		invocation.set(oldInvocation);
	}
}

【5】 当advice=AspectJMethodBeforeAdvice后置处理器时,invoke方法如下:

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
        //执行后置处理器的 before 方法
        //输出如下:div运行。。。@Before:参数列表是:{[2, 3]}
	this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        //进入上述展示的 processd 方法,此时进入第一个判断语句,执行目标方法
	return mi.proceed();
}

【6】 后置处理器的After方法执行的invoke方法展示:最终执行结果的返回方法。

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
	try {
		return mi.proceed();
	}
	finally {
                //执行 after 方法:div结束。。。@After
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}
}

【7】上述分析的流程图如下:根据链表循环向下执行,当最后一个后置处理器的before执行完成后,进行目标方法,并进行回流执行拦截器的目标方法。

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

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

相关文章

蓝桥杯备赛 | 洛谷做题打卡day2

​ 蓝桥杯备赛 | 洛谷做题打卡day2 嵌套循环yyds&#xff01;&#xff01; 题目来源&#xff1a;洛谷P2670 [NOIP2015 普及组] 扫雷游戏 题目背景 NOIP2015 普及组 T2 题目描述 扫雷游戏是一款十分经典的单机小游戏。在 n n n 行 m m m 列的雷区中有一些格子含有地雷&am…

❤ Uniapp使用二 ( 日常使用篇)

❤ Uniapp使用二 ( 日常使用篇) 一、表单 1、基础表单验证 form <form submit"formSubmit" reset"formReset"> <view class"uni-form-item uni-column"><view class"title">请选择类型{{selectvalue}}</view&…

海思SD3403,SS928/926,hi3519dv500,hi3516dv500移植yolov7,yolov8(9)

上一节yolov8的训练已经完成了,现在要开始做模型的转换了,这里和yolov7方式相似,但是有一些差异,尤其是yolov7的不带NMS部分的输出顺序和yolov8的输出顺序与格式是有差异的。 首先还是要自己手动加入rpn_op,这里包含了filter,sort,nms部分。 我们一个一个看,首先filter.py…

深度学习基础知识整理

自动编码器 Auto-encoders是一种人工神经网络&#xff0c;用于学习未标记数据的有效编码。它由两个部分组成&#xff1a;编码器和解码器。编码器将输入数据转换为一种更紧凑的表示形式&#xff0c;而解码器则将该表示形式转换回原始数据。这种方法可以用于降维&#xff0c;去噪…

高级分布式系统-第15讲 分布式机器学习--分布式机器学习算法

高级分布式系统汇总&#xff1a;高级分布式系统目录汇总-CSDN博客 分布式机器学习算法 按照通信步调&#xff0c;大致可以分为同步算法和异步算法两大类。 同步算法下&#xff0c;通信过程中有一个显式的全局同步状态&#xff0c;称之为同步屏障。当工作节点运行到同步屏障 …

MySQL索引创建原则和失效问题

一.索引创建原则 数据量较大,且查询比较频繁的表常作为查询条件、分组、排序的字段字段内容区分度高内容较长,使用前缀索引尽量创建联合索引要控制索引的数量如果索引列不能存储NULL值,请在创建表示使用NOT NULL约束它 二.索引失效 违反最左前缀法则范围查询右边的列,不能使用…

可持续技术:2024 年技术趋势的绿色创新

随着我们步入2024年&#xff0c;对可持续技术解决方案的关注从未如此强烈。从可再生能源到环保小工具&#xff0c;科技行业正朝着更环保、更可持续的未来大步迈进。 在快速发展的技术领域&#xff0c;创新是推动我们走向可持续未来的动力。随着我们步入2024年&#xff0c;对可持…

基于Docker Compose单机实现多级缓存架构2024

文章目录 一、环境参考二、专栏简介三、扩展 一、环境参考 NameVersionDocker Desktop for Windows4.23.0Openjdk8MySQL8.2.0Redis7.2Canal1.1.7OpenResty1.21.4.3-3-jammy-amd64Lua-Caffeine- 二、专栏简介 多级缓存实现过程比较长&#xff0c;将拆分为多个文章分步讲述。如…

[我的rust付费栏目]rust跟我学(一)已上线

大家好&#xff0c;我是开源库get_local_info的作者带剑书生&#xff0c;get_local_info诞生半个月&#xff0c;现在已经获得500的下载量&#xff0c;并获社区日更前五名&#xff0c;后被西安城市开发者社区收录&#xff08;【我的Rust库】get_local_info 0.1.5发布_rust_科比布…

CMake 实战构建TcpServer项目 静态库/动态库

爱编程的大丙CMake&#xff1a; 20. 举例 - 下_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV14s4y1g7Zj?p20&spm_id_frompageDriver&vd_sourcea934d7fc6f47698a29dac90a922ba5a3 hehedalinux:~/Linux/LinuxServerCpp$ ls Buffer.cpp Log.h Buffe…

墙地砖外形检测的技术方案-图像分割

基础原理 由于对碗口进行缺口检测&#xff0c;因此只需要碗口的边界信息。得到陶瓷碗区域填充后的图像&#xff0c;对图像进行边缘检测。这是属于图像分割中的内容&#xff0c;在图像的边缘中&#xff0c;可以利用导数算子对数字图像求差分&#xff0c;将边缘提取出来。 案例…

shell脚本算术运算

算术运算符 注意&#xff1a; 不是单引号&#xff0c;是键盘左上角那个反单引号条件表达式要放在方括号之间&#xff0c;并且要有空格&#xff0c;例如:[ a a ab]是错误的&#xff0c;必须写成[ $a $b ]。cost_Minexpr $cost_time / 60 前后不能有空格&#xff0c;否则出…

【第十四课】并查集(acwing-836合并集合 / 做题思路 /c++代码)

目录 错误思路(但能骗分emm)--邻接矩阵(可以跳过) 思路 存在的问题 代码如下 并查集 思路 代码如下 一些解释 错误思路(但能骗分emm)--邻接矩阵(可以跳过) 思路 刚看到这道题我自己做的时候&#xff0c;因为之前学的trie树的时候意识到使用二维数组的含义&#xff0c;…

如何配置Pycharm服务器并结合内网穿透工具实现远程开发

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…

开启C++之旅(下):引用、内联函数及现代特性(auto和范围for循环)

上次介绍了&#xff1a;开启C之旅&#xff08;上&#xff09;&#xff1a;探索命名空间与函数特性&#xff08;缺省参数和函数重载&#xff09; 今天就接着进行c入门的知识讲解 文章目录 1.引用1.1引用概念1.2引用特性1.3常引用其他情况 1.4引用使用场景1.4.1做参数1.4.2做返回…

使用VSCode内的jupyter编写R语言:绘制中国省份地区热力图

R语言绘制中国省份地区热力图教程 1、R语言的安装和编辑器的选择 对于一门从未接触过的编程语言&#xff0c;相信大家的吐槽点和我一样&#xff1a;又要安装软件&#xff0c;配置环境&#xff01;其实R语言的安装和环境配置并不复杂&#xff0c;只需要安装两部分内容&#xf…

第15届蓝桥STEMA测评真题剖析-2023年12月17日Scratch编程初中级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第166讲。 第15届蓝桥第3次STEMA测评&#xff0c;这是2023年12月17日举办的STEMA&#xff0c;比赛仍然采取线上形式。这…

ESP32-Touch(Arduino)

Touch Touch传感器是一种外围设备&#xff0c;具有内部振荡器电路&#xff0c;可在固定时间段内测量相应GPIO引脚上的充电/放电频率。 因此&#xff0c;这些触摸传感器也被称为电容式传感器。例如&#xff0c;如果您触摸这些引脚中的任何一个&#xff0c;手指电荷将改变这个周…

Vue学习计划-Vue3--核心语法(十)Proxy响应式原理

Proxy响应式原理 1.Vue2的响应式 实现原理&#xff1a; 对象类型&#xff1a;通过Object.defineProperty()对属性的读取、修改进行拦截&#xff08;数据劫持&#xff09;数组类型&#xff1a;通过重写更新数组的一系列方法来实现拦截&#xff0c;&#xff08;对数组的变更方法…

【数学建模】图论模型

文章目录 图的基础理论及networkx简介图的基本概念图的表示及Networkx简介图的表示NetworkX简介 最短路算法及其Python实现固定起点到其余各点的最短路算法每对顶点间的最短路算法最短路应用 最小生成树算法及其networkx实现基本概念最小生成树算法最小生成树应用 匹配问题最大…