主頁 > 後端開發 > 死磕Spring之AOP篇 - Spring AOP總覽

死磕Spring之AOP篇 - Spring AOP總覽

2021-04-17 06:11:45 後端開發

該系列文章是本人在學習 Spring 的程序中總結下來的,里面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼注釋 Spring 原始碼分析 GitHub 地址 進行閱讀,

Spring 版本:5.1.14.RELEASE

在開始閱讀 Spring AOP 原始碼之前,需要對 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章導讀》 這一系列文章

了解 AOP 相關術語,可先查看 《Spring AOP 常見面試題) 》 這篇文章

該系列其他文章請查看:《死磕 Spring 之 AOP 篇 - 文章導讀》

通過上一篇 《初識 JDK、CGLIB 兩種動態代理》 文章我們對 Spring AOP 底層的 JDK 動態代理和 CGLIB 動態代理有了一定的了解,也知道如何簡單地使用兩種動態代理創建代理物件,相信上篇文章可以讓你對 Spring AOP 有了一個初步的認識,那么接下來我們準備進入 Spring AOP 原始碼學習階段,

在開始 Spring AOP 原始碼學習前,本文會對 Spring AOP 涉及到的大部分主要的 API 進行介紹,讓我們對 Spring AOP 有一個全面的認識,這樣在學習 Spring AOP 原始碼的程序中有一個清晰的思路會更加易于理解,然后在后續的文章從 Spring AOP 的自動代理開始深入學習,直接進入正題吧,

Spring AOP API 總覽

如下圖所示:

上面這張圖片列出了 Spring AOP 涉及到的大部分 API,接下來我們依次簡單介紹一下:

  • Joinpoint:連接點,也就是我們需要執行的目標方法

  • Pointcut:切點,提供 ClassFilter 類過濾器和 MethodMatcher 方法匹配器支持對類和方法進行篩選,

  • Advice:通知器,一般都是 MethodInterceptor 方法攔截器,不是的話會通過 AdvisorAdapter 配接器轉換成對應的 MethodInterceptor 方法攔截器,

  • Advisor:Advice 容器介面,與 Advice 是一對一的關系;它的子介面 PointcutAdvisor 相當于一種 Pointcut 和 Advice 的容器,將 Pointcut 過濾 Joinpoint 的能力和 Advice 進行整合,這樣一來就將兩者關聯起來了,

  • Advisor 配接器AdvisorAdapter 是 Advisor 的配接器,當篩選出能夠應用于方法的所有 Advisor 后,需要獲取對應的 Advice;

    • 如果不是 MethodInterceptor 型別,則需要通過 AdvisorAdapter 配接器轉換成對應的 MethodInterceptor 方法攔截器,
  • AOP 代理物件:AOP 代理物件,由 JDK 動態代理或者 CGLIB 動態代理創建的代理物件;

    • 選擇哪種動態代理是通過 AopProxyFactory 代理工廠根據目標類來決定的,
  • AOP 代理配置AdvisedSupport 配置管理器中保存了對應代理物件的配置資訊,例如滿足條件的 Advisor 物件、TargetSource 目標類來源;

    • 在創建代理物件的程序,AdvisedSupport 扮演著一個非常重要的角色,
  • AOP 代理物件創建:AOP 代理物件的創建分為手動模式自動模式;不管哪種模式都和 AdvisedSupport 配置管理器有關;

    • 手動模式就是通過 Spring AOP 提供的 API 進行創建;
    • 自動模式則是和 Spring IoC 進行整合,在 Bean 的加載程序中如果需要進行代理,則創建對應的代理物件;
  • AdvisorChainFactoryAdvisor 鏈路工廠

    • AdvisedSupport 配置管理器中保存了代理物件的所有 Advisor 物件,當攔截某個方法時,需要通過 AdvisorChainFactory 篩選出能夠應用于該方法的 Advisor 們;
    • 另外還需要借助 AdvisorAdapter 配接器獲取 Advisor 對應的 MethodInterceptor 方法攔截器,將這些 MethodInterceptor 有序地形成一條鏈路并回傳,
  • IntroductionInfo引介介面,支持代理物件實作目標類沒有真正實作的額外的介面;

    • 在 Advisor 的子介面 IntroductionAdvisor 中會繼承這個 IntroductionInfo 介面,通過 @DeclareParents 注解定義的欄位會被決議成 IntroductionAdvisor 物件,
  • AOP 代理目標物件來源目標類來源,和代理物件進行關聯,用于獲取被代理代理的目標物件;

    • 在代理物件中最終的方法執行都需要先通過 TargetSource 獲取對應的目標物件,然后執行目標方法,

Joinpoint

類圖

  • ConstructorInvocation,是基于構造器的一個呼叫器,在 Spring AOP 中僅支持方法級別的代理,所以這個介面并沒有被使用

  • ReflectiveMethodInvocation,Joinpoint 的底層實作類,一個基于反射的方法呼叫器,本文不進行分析,在后續的文章進行講解??

  • CglibMethodInvocation,和上者實作類差不多,新增了一個 CGLIB 中的 MethodProxy 方法代理物件,本文不進行分析,在后續的文章進行講解??

org.aopalliance.intercept.Joinpoint,連接點,也就是我們需要執行的目標方法,是由 AOP 聯盟提供的一個介面,如下:

public interface Joinpoint {

	/**
	 * 執行方法呼叫器中的下一個攔截器,執行完所有的攔截器則執行目標方法
	 */
	Object proceed() throws Throwable;

	/**
	 * 回傳目標物件
	 */
	Object getThis();

	/**
	 * 回傳目標方法
	 */
	AccessibleObject getStaticPart();
}

org.aopalliance.intercept.Invocation,呼叫器,是由 AOP 聯盟提供的一個介面,如下:

public interface Invocation extends Joinpoint {

	/**
	 * 獲取引數陣列
	 */
	Object[] getArguments();
}

MethodInvocation

org.aopalliance.intercept.MethodInvocation,方法呼叫器,是由 AOP 聯盟提供的一個介面,如下:

public interface MethodInvocation extends Invocation {

	/**
	 * 獲取目標方法
	 */
	Method getMethod();
}

ProxyMethodInvocation

org.springframework.aop.ProxyMethodInvocation,MethodInvocation 方法呼叫器的擴展,允許訪問代理物件,如下:

public interface ProxyMethodInvocation extends MethodInvocation {

	/**
	 * 回傳代理物件
	 */
	Object getProxy();

	/**
	 * 克隆方法
	 */
	MethodInvocation invocableClone();

	/**
	 * 克隆方法,使用引數
	 */
	MethodInvocation invocableClone(Object... arguments);

	/**
	 * 設定引數陣列
	 */
	void setArguments(Object... arguments);

	/**
	 * 添加自定義屬性
	 */
	void setUserAttribute(String key, @Nullable Object value);

	/**
	 * 獲取自定義屬性
	 */
	@Nullable
	Object getUserAttribute(String key);
}

Pointcut

類圖

  • AspectJExpressionPointcut,基于 AspectJ 處理運算式的能力實作的一個 Pointcut,本文不進行分析,在后續的文章進行講解??

上述類圖僅列出了部分 Pointcut 相關的介面

org.springframework.aop.Pointcut,切點,提供 ClassFilter 類過濾器和 MethodMatcher 方法匹配器支持對類和方法進行篩選,如下:

public interface Pointcut {

	/**
	 * 回傳類過濾器
	 */
	ClassFilter getClassFilter();

	/**
	 * 回傳方法匹配器
	 */
	MethodMatcher getMethodMatcher();

	/**
	 * 總是匹配通過的 Pointcut 實體物件
	 */
	Pointcut TRUE = TruePointcut.INSTANCE;
}

org.springframework.aop.support.ExpressionPointcut,支持運算式匹配的 Pointcut,如下:

public interface ExpressionPointcut extends Pointcut {
    
	/**
	 * 回傳運算式
	 */
	@Nullable
	String getExpression();
}

StaticMethodMatcherPointcut

org.springframework.aop.support.StaticMethodMatcherPointcut,抽象類,本身是一個方法匹配器的 Pointcut,如下:

public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {

    /** 默認情況類過濾器總是匹配通過 */
	private ClassFilter classFilter = ClassFilter.TRUE;

	/**
	 * 設定類過濾器
	 */
	public void setClassFilter(ClassFilter classFilter) {
		this.classFilter = classFilter;
	}

    /**
     * 獲取類過濾器
     */
	@Override
	public ClassFilter getClassFilter() {
		return this.classFilter;
	}

    /**
     * 回傳方法匹配器,就是當前物件,因為當前物件繼承的 StaticMethodMatcher 就是一個 MethodMatcher
     */
	@Override
	public final MethodMatcher getMethodMatcher() {
		return this;
	}
}

我們自定義的 Pointcut 通常可以繼承 StaticMethodMatcherPointcut 來實作,重寫 MethodMatcher matches(Method method, Class<?> targetClass, Object... args) 方法即可,也可以再實作 ClassFilter,實作 matches(Class clazz) 方法

ClassFilter

org.springframework.aop.ClassFilter,函式式介面,類過濾器,用于判斷這個 Class 是否滿足 Pointcut 切點,如下:

@FunctionalInterface
public interface ClassFilter {

	/**
	 * 匹配這個 Class 類
	 */
	boolean matches(Class<?> clazz);


	/**
	 * 總是匹配通過的類過濾器
	 */
	ClassFilter TRUE = TrueClassFilter.INSTANCE;
}

MethodMatcher

org.springframework.aop.MethodMatcher,方法匹配器,用于判斷這個 Method 是否滿足 Pointcut 切點,如下:

public interface MethodMatcher {

	/**
	 * 匹配這個方法
	 */
	boolean matches(Method method, Class<?> targetClass);

	/**
	 * 當前方法匹配器是否為運行狀態
	 */
	boolean isRuntime();

	/**
	 * 匹配這個方法,并校驗引數
	 */
	boolean matches(Method method, Class<?> targetClass, Object... args);

	/**
	 * 總是匹配通過的方法匹配器
	 */
	MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}

Advice

類圖

  • Advice,標記介面
  • BeforeAdvice,標記介面,后置通知
  • AfterAdvice,標記介面,前置通知
  • Interceptor,標記介面,攔截器
  • AbstractAspectJAdvice,包裝了一個 Aspect 切面或者 AspectJ 注解標注的方法,Around、Before、After、AfterReturning、AfterThrowing 幾種型別的 Advice 最終都會轉換成 AbstractAspectJAdvice 對應的子類并實作 MethodInterceptor 方法攔截器介面,本文不進行分析,在后續的文章進行講解??

上述類圖僅列出了部分 Advice 相關的介面

MethodInterceptor

org.aopalliance.intercept.MethodInterceptor,方法攔截器,函式式介面,如下:

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {

	/**
	 * 執行 MethodInvocation 呼叫器
	 */
	Object invoke(MethodInvocation invocation) throws Throwable;
}

Advisor

類圖

上面只列出了 Advisor 的部分實作類,在 Spring AOP 中還有非常多的實作類,在后續的文章進行分析??

  • AbstractBeanFactoryPointcutAdvisor,關聯 BeanFactory 的 PointcutAdvisor 抽象類,支持從 IoC 容器中獲取 Advice 物件,我們可以通過繼承這個類來自定義一個 PointcutAdvisor 物件

org.springframework.aop.Advisor,Advice 容器介面,與 Advice 是一對一的關系,如下:

public interface Advisor {

	/**
	 * 空的 Advice
	 */
	Advice EMPTY_ADVICE = new Advice() {};

	/**
	 * 獲取 Advice
	 */
	Advice getAdvice();

	/**
	 * 回傳這個 Advice 是否有一個指定的目標實體物件,默認都是 true
	 */
	boolean isPerInstance();
}

PointcutAdvisor

org.springframework.aop.PointcutAdvisor,繼承 Advisor 介面,Pointcut 和 Advice 的容器,將 Pointcut 過濾 Joinpoint 的能力和 Advice 進行整合,這樣一來就將兩者關聯起來了,如下:

public interface PointcutAdvisor extends Advisor {

	/**
	 * 獲取 Pointcut 切點
	 */
	Pointcut getPointcut();
}

IntroductionAdvisor

org.springframework.aop.IntroductionAdvisor,繼承 Advisor 和 IntroductionInfo 介面,支持代理物件實作目標類沒有真正實作的額外的介面;通過 @DeclareParents 注解定義的欄位會被決議成 IntroductionAdvisor 物件,如下:

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {

	/**
	 * 獲取類加載器,因為沒有 Pointcut 切點,則提供一個類過濾器
	 */
	ClassFilter getClassFilter();

	/**
	 * 校驗是否實作 IntroductionInfo 中的介面
	 */
	void validateInterfaces() throws IllegalArgumentException;
}

public interface IntroductionInfo {

	/**
	 * 回傳額外的介面
	 */
	Class<?>[] getInterfaces();
}

AdvisorAdapter

類圖

org.springframework.aop.framework.adapter.AdvisorAdapter,Advisor 的配接器,當篩選出能夠應用于方法的所有 Advisor 后,需要獲取對應的 Advice;如果不是 MethodInterceptor 型別,則需要通過 AdvisorAdapter 配接器轉換成對應的 MethodInterceptor 方法攔截器,如下:

public interface AdvisorAdapter {

	/**
	 * 是否支持該型別的 Advice 適配
	 */
	boolean supportsAdvice(Advice advice);

	/**
	 * 獲取 Advisor 的 Advice,并包裝成對應的 MethodInterceptor 方法攔截器
	 */
	MethodInterceptor getInterceptor(Advisor advisor);
}

org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter,前置 Advice 的配接器,如下:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof MethodBeforeAdvice);
	}

	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
		return new MethodBeforeAdviceInterceptor(advice);
	}

}

可以看到這個 MethodBeforeAdviceAdapter 配接器只能在 Spring 內部使用,先判斷 Advice 是否為 MethodBeforeAdvice 型別,如果是的話,則可以將 Advice 包裝成 MethodBeforeAdviceInterceptor 物件,其他的配接器類似,

當然,AdvisorAdapter 配接器不是直接被使用,而是通過 DefaultAdvisorAdapterRegistry 配接器注冊中心使用的,在后續文章進行分析??

AOP 代理物件

類圖

org.springframework.aop.framework.AopProxy,AOP 代理介面,用于創建代理物件,如下:

public interface AopProxy {

	/**
	 * 創建一個代理物件
	 */
	Object getProxy();

	/**
	 * 創建一個代理物件,傳入指定的 ClassLoader 類加載器
	 */
	Object getProxy(@Nullable ClassLoader classLoader);
}

在 Spring AOP 中有 JdkDynamicAopProxy 和 CglibAopProxy 兩種實作類,分別代表 JDK 動態代理和 CGLIB 動態代理,選擇哪種動態代理是通過 DefaultAopProxyFactory 代理工廠根據目標類來決定的,這些內容在后續文章進行分析??

AOP 代理配置

類圖

org.springframework.aop.framework.ProxyConfig,代理配置類,如下:

/**
 * @see AdvisedSupport
 */
public class ProxyConfig implements Serializable {

	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = -8409359707199703185L;
    /** 是否使用類代理 */
	private boolean proxyTargetClass = false;
	private boolean optimize = false;
	boolean opaque = false;
    /** 是否暴露代理物件 */
	boolean exposeProxy = false;
	/** 配置是否被凍結 */
	private boolean frozen = false;
}

這個類僅提供一些頂層的配置資訊,更多和創建代理物件相關的配置資訊都在子類 AdvisedSupport 中,這些內容在后續文章進行分析??

AOP 代理物件創建

類圖

AOP 代理物件的創建分為手動模式自動模式;不管哪種模式都和 AdvisedSupport 配置管理器有關;

  • 手動模式就是通過 Spring AOP 提供的 API 進行創建,例如 ProxyFactory 代理工廠;
  • 自動模式則是和 Spring IoC 進行整合,在 Bean 的加載程序中如果需要進行代理,則創建對應的代理物件;可以看到 AbstractAutoProxyCreator 實作了 BeanPostProcessor 相關介面,在加載 Bean 的程序中,初始化后會呼叫 BeanPostProcessor#postProcessAfterInitialization 的初始化后置處理方法,在 AbstractAutoProxyCreator 中則可以創建對應的代理物件(如果有必要的話)

上面這些 AOP 自動代理類在后續文章會進行分析??

AOP 代理目標物件來源

類圖

org.springframework.aop.TargetSource目標類來源,和代理物件進行關聯,用于獲取被代理代理的目標物件,如下:

public interface TargetSource extends TargetClassAware {

	/**
	 * 獲取目標物件的 Class 物件
	 */
	@Override
	@Nullable
	Class<?> getTargetClass();

	/**
	 * 是否是靜態的,回傳 `fasle` 表示每次獲取目標物件都需要進行創建,那么每次創建都需要釋放,例如原型模式的 Bean
	 */
	boolean isStatic();

	/**
	 * 獲取目標物件
	 */
	@Nullable
	Object getTarget() throws Exception;

	/**
	 * 釋放目標物件
	 */
	void releaseTarget(Object target) throws Exception;
}

SingletonTargetSource

org.springframework.aop.target.SingletonTargetSource,單例 Bean 的目標物件來源,如下:

public class SingletonTargetSource implements TargetSource, Serializable {

	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = 9031246629662423738L;

	/** 保存目標物件 */
	private final Object target;

	/**
	 * 創建實體物件的時候就是設定目標物件
	 */
	public SingletonTargetSource(Object target) {
		Assert.notNull(target, "Target object must not be null");
		this.target = target;
	}

	@Override
	public Class<?> getTargetClass() {
		return this.target.getClass();
	}

	@Override
	public Object getTarget() {
		return this.target;
	}

	@Override
	public void releaseTarget(Object target) {
		// nothing to do
	}

	@Override
	public boolean isStatic() {
		return true;
	}

	@Override
	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof SingletonTargetSource)) {
			return false;
		}
		SingletonTargetSource otherTargetSource = (SingletonTargetSource) other;
		return this.target.equals(otherTargetSource.target);
	}

	@Override
	public int hashCode() {
		return this.target.hashCode();
	}

	@Override
	public String toString() {
		return "SingletonTargetSource for target object [" + ObjectUtils.identityToString(this.target) + "]";
	}
}

單例 Bean 對應的 TargetSource 都是 SingletonTargetSource,里面保存了這個單例 Bean,

總結

本文開頭的圖片展示了 Spring AOP 涉及到的大部分主要的 API,圍繞著這張圖片對這些 API 進行簡單的講述,對 Spring AOP 可以有一個整體的認識,不過 Spring AOP 還有一個部分,如何開啟整個 AOP 模塊在本文沒有體現出來,簡單提一下,通過 @EnableAspectJAutoProxy 注解或者 <aop:aspectj-autoproxy /> XML 配置可以激活 AOP 模塊,底層會注冊一個 AbstractAutoProxyCreator 型別的 Bean 完成 AOP 自動代理,具體程序在后面的文章進行分析??

  • 在 Spring AOP 中有著 Joinpoint 連接點,Pointcut 切點和 Advice 通知,通過 Advisor 介面保存一個 Advice,其子介面 PointcutAdvisor 又關聯一個 Pointcut,將 Pointcut 過濾 Joinpoint 的能力和 Advice 進行整合,這樣一來就將兩者關聯起來了,

  • Spring AOP 傳遞 Advice 的程序通常是通過 Advisor 實作的,而使用 Advice 的程序都是通過 MethodInterceptor 執行,如果不是該型別則通過 AdvisorAdapter 配接器將其包裝成對應的 MethodInterceptor 方法攔截器,

  • Sping AOP 底層有 JDK 動態代理和 CGLIB 動態代理兩種方式,分別對應 JdkDynamicAopProxyCglibAopProxy,選擇哪種代理方式需要通過 DefaultAopProxyFactory 代理工廠根據目標類來決定,

  • 在 Spring AOP 中一個 AdvisedSupport 配置管理器,里面保存對應代理物件的配置資訊,例如滿足條件的 Advisor 物件、TargetSource 目標類來源,AdvisedSupport 在 Spring AOP 中扮演一個重要的角色,

  • Spring AOP 中的自動代理主要由 AbstractAutoProxyCreator 這個 Bean 進行創建,因為它實作了幾種 BeanPostProcessor,例如在 Bean 加載程序中,初始化后會呼叫 AbstractAutoProxyCreator 的方法進行處理,回傳一個代理物件(如果有必要的話),

在后續的文章我們主要圍繞自動代理進行分析,對于 Bean 的加載程序不熟悉的小伙伴可查看我前面的《死磕Spring之IoC篇 - 文章導讀》文章,或者直接查看《死磕Spring之IoC篇 - Bean 的創建程序》 這篇文章

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/276902.html

標籤:Java

上一篇:【MQ中間件】RabbitMQ -- RabbitMQ訊息模式(2)

下一篇:JVM之引數調優

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more