国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Android12】Monkey壓力測試源碼執(zhí)行流程分析

這篇具有很好參考價值的文章主要介紹了【Android12】Monkey壓力測試源碼執(zhí)行流程分析。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Monkey壓力測試源碼執(zhí)行流程分析

Monkey是Android提供的用于應用程序自動化測試、壓力測試的測試工具。
其源碼路徑(Android12)位于

/development/cmds/monkey/

部署形式為Java Binary

# development/cmds/monkey/Android.bp
// Copyright 2008 The Android Open Source Project
//

package {
    default_applicable_licenses: ["development_cmds_monkey_license"],
}

// See: http://go/android-license-faq
license {
    name: "development_cmds_monkey_license",
    visibility: [":__subpackages__"],
    license_kinds: [
        "SPDX-license-identifier-Apache-2.0",
    ],
    license_text: [
        "NOTICE",
    ],
}

//###############################################################
java_binary {
    name: "monkey",
    srcs: ["**/*.java"],
    wrapper: "monkey",
}

通過Monkey,可以模擬用戶的Touch(單指、多指、手勢)、按鍵(key)事件等,檢測應用程序發(fā)生的ANR、Crash事件,并收集相關Debug信息等。
例如測試應用com.package.linduo,

adb shell monkey -p com.package.linduo --pct-touch 10 --pct-motion 20 10000
# 該命令表示,執(zhí)行1萬次測試事件,其中Touch事件占10%,Motion事件占20%

# 或者adb shell進入android終端,直接使用monkey命令

Monkey支持的命令

    private void showUsage() {
        StringBuffer usage = new StringBuffer();
        usage.append("usage: monkey [-p ALLOWED_PACKAGE [-p ALLOWED_PACKAGE] ...]\n");
        usage.append("              [-c MAIN_CATEGORY [-c MAIN_CATEGORY] ...]\n");
        usage.append("              [--ignore-crashes] [--ignore-timeouts]\n");
        usage.append("              [--ignore-security-exceptions]\n");
        usage.append("              [--monitor-native-crashes] [--ignore-native-crashes]\n");
        usage.append("              [--kill-process-after-error] [--hprof]\n");
        usage.append("              [--match-description TEXT]\n");
        usage.append("              [--pct-touch PERCENT] [--pct-motion PERCENT]\n");
        usage.append("              [--pct-trackball PERCENT] [--pct-syskeys PERCENT]\n");
        usage.append("              [--pct-nav PERCENT] [--pct-majornav PERCENT]\n");
        usage.append("              [--pct-appswitch PERCENT] [--pct-flip PERCENT]\n");
        usage.append("              [--pct-anyevent PERCENT] [--pct-pinchzoom PERCENT]\n");
        usage.append("              [--pct-permission PERCENT]\n");
        usage.append("              [--pkg-blacklist-file PACKAGE_BLACKLIST_FILE]\n");
        usage.append("              [--pkg-whitelist-file PACKAGE_WHITELIST_FILE]\n");
        usage.append("              [--wait-dbg] [--dbg-no-events]\n");
        usage.append("              [--setup scriptfile] [-f scriptfile [-f scriptfile] ...]\n");
        usage.append("              [--port port]\n");
        usage.append("              [-s SEED] [-v [-v] ...]\n");
        usage.append("              [--throttle MILLISEC] [--randomize-throttle]\n");
        usage.append("              [--profile-wait MILLISEC]\n");
        usage.append("              [--device-sleep-time MILLISEC]\n");
        usage.append("              [--randomize-script]\n");
        usage.append("              [--script-log]\n");
        usage.append("              [--bugreport]\n");
        usage.append("              [--periodic-bugreport]\n");
        usage.append("              [--permission-target-system]\n");
        usage.append("              COUNT\n");
        Logger.err.println(usage.toString());
    }

Monkey執(zhí)行測試的源碼分析

這里主要關注模式事件的執(zhí)行流程

  • Monkey啟動
  • Monkey生成模擬事件
  • Monkey向系統(tǒng)發(fā)送模擬事件
    【Android12】Monkey壓力測試源碼執(zhí)行流程分析,AndroidFramework,壓力測試,Monkey,自動化測試,源碼分析,anr,crash
Monkey啟動

Monkey.java中定義了程序入口函數main,該函數中啟動了Monkey程序。

// development/cmds/monkey/src/com/android/commands/monkey/Monkey.java

public static void main(String[] args) {
	// Set the process name showing in "ps" or "top"
	Process.setArgV0("com.android.commands.monkey");

	Logger.err.println("args: " + Arrays.toString(args));
	int resultCode = (new Monkey()).run(args);
	System.exit(resultCode);
}
// development/cmds/monkey/src/com/android/commands/monkey/Monkey.java

/**
 * Run the command!
 *
 * @param args The command-line arguments
 * @return Returns a posix-style result code. 0 for no error.
 */
private int run(String[] args) {
	// Default values for some command-line options
	mVerbose = 0;
	// 默認的測試次數
	mCount = 1000;
	// 生成radom的seed
	mSeed = 0;
	// 記錄事件之間的延遲,就是每個事件執(zhí)行的間隔
	mThrottle = 0;

	// prepare for command-line processing
	mArgs = args;
	
	// 解析參數
	if (!processOptions()) {
		return -1;
	}
	
	// 確定待測試的Package
	if (!loadPackageLists()) {
		return -1;
	}
	
	// now set up additional data in preparation for launch
	if (mMainCategories.size() == 0) {
		mMainCategories.add(Intent.CATEGORY_LAUNCHER);
		mMainCategories.add(Intent.CATEGORY_MONKEY);
	}
	
	if (mSeed == 0) {
		mSeed = System.currentTimeMillis() + System.identityHashCode(this);
	}
	// 獲取系統(tǒng)服務接口(AMS、PMS、WMS)
	if (!getSystemInterfaces()) {
		return -3;
	}
	// 獲取用于啟動應用的Activity
	if (!getMainApps()) {
		return -4;
	}
	
	if (mScriptFileNames != null && mScriptFileNames.size() == 1) {
		// script mode, ignore other options
	} else if (mScriptFileNames != null && mScriptFileNames.size() > 1) {
	} else if (mServerPort != -1) {
	} else {
		// 創(chuàng)建用于產生模擬器事件的Source對象
		mEventSource = new MonkeySourceRandom(mRandom, mMainApps,
				mThrottle, mRandomizeThrottle, mPermissionTargetSystem);
		mEventSource.setVerbose(mVerbose);
		// 設置各測試類型的測試比例
		// set any of the factors that has been set
		for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
			if (mFactors[i] <= 0.0f) {
				((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]);
			}
		}
		
		// 產生activity事件,該事件用來啟動應用
		// in random mode, we start with a random activity
		((MonkeySourceRandom) mEventSource).generateActivity();
	}
	
	try {
		// 執(zhí)行模擬測試事件
		crashedAtCycle = runMonkeyCycles();
	} finally {
		// Release the rotation lock if it's still held and restore the
		// original orientation.
		new MonkeyRotationEvent(Surface.ROTATION_0, false).injectEvent(
			mWm, mAm, mVerbose);
	}

}
Monkey解析輸入參數

processOptions函數解析輸入參數(就是monkey命令后跟著的參數信息),根據入參設置Monkey類中相關成員變量。

// development/cmds/monkey/src/com/android/commands/monkey/Monkey.java
private boolean processOptions() {
	// quick (throwaway) check for unadorned command
	if (mArgs.length < 1) {
		showUsage();
		return false;
	}

	try {
		String opt;
		Set<String> validPackages = new HashSet<>();
		while ((opt = nextOption()) != null) {
			if (opt.equals("-s")) {
				mSeed = nextOptionLong("Seed");
			} else if (opt.equals("-p")) {
				validPackages.add(nextOptionData());
			} else if (opt.equals("-c")) {
				// 省略
			} else {
				Logger.err.println("** Error: Unknown option: " + opt);
				showUsage();
				return false;
			}
		}
		// 根據輸入參數,設置待測試的應用
		MonkeyUtils.getPackageFilter().addValidPackages(validPackages);
	} catch (RuntimeException ex) {
		Logger.err.println("** Error: " + ex.toString());
		showUsage();
		return false;
	}

	// If a server port hasn't been specified, we need to specify
	// a count
	if (mServerPort == -1) {
		// 省略
	}

	return true;
}
Monkey獲取系統(tǒng)服務

getSystemInterfaces函數用于獲取Android系統(tǒng)服務,包括AMS、PMS、WMS服務。調用AMS服務的setActivityController接口,通過該接口向AMS設置IActivityController.Stub對象,通過該對象監(jiān)聽應用(Activity)的ANR和Crash事件。

/**
 * Attach to the required system interfaces.
 *
 * @return Returns true if all system interfaces were available.
 */
private boolean getSystemInterfaces() {
	mAm = ActivityManager.getService();
	if (mAm == null) {
		Logger.err.println("** Error: Unable to connect to activity manager; is the system "
				+ "running?");
		return false;
	}

	mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
	if (mWm == null) {
		Logger.err.println("** Error: Unable to connect to window manager; is the system "
				+ "running?");
		return false;
	}

	mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
	if (mPm == null) {
		Logger.err.println("** Error: Unable to connect to package manager; is the system "
				+ "running?");
		return false;
	}

	try {
		mAm.setActivityController(new ActivityController(), true);
		mNetworkMonitor.register(mAm);
	} catch (RemoteException e) {
		Logger.err.println("** Failed talking with activity manager!");
		return false;
	}

	return true;
}

/**
 * Monitor operations happening in the system.
 */
private class ActivityController extends IActivityController.Stub {
	public boolean activityStarting(Intent intent, String pkg) {
		// 省略
	}

	private boolean isActivityStartingAllowed(Intent intent, String pkg) {
		// 省略
	}

	public boolean activityResuming(String pkg) {
		// 省略
	}

	public boolean appCrashed(String processName, int pid,
			String shortMsg, String longMsg,
			long timeMillis, String stackTrace) {
		// 省略
	}

	public int appEarlyNotResponding(String processName, int pid, String annotation) {
		return 0;
	}

	public int appNotResponding(String processName, int pid, String processStats) {
		// 省略
	}

	public int systemNotResponding(String message) {
		// 省略
	}
}
Monkey獲取待測試應用的Activity

monkey通過PackageManager的queryIntentActivities接口,查詢帶有 Intent.CATEGORY_LAUNCHERIntent.CATEGORY_MONKEY信息的Activity,并判斷Activity是否屬于待測試應用。將待測試應用的Activity添加到mMainApps變量中。

// development/cmds/monkey/src/com/android/commands/monkey/Monkey.java
/**
 * Using the restrictions provided (categories & packages), generate a list
 * of activities that we can actually switch to.
 *
 * @return Returns true if it could successfully build a list of target
 *         activities
 */
private boolean getMainApps() {
	try {
		final int N = mMainCategories.size();
		for (int i = 0; i < N; i++) {
			Intent intent = new Intent(Intent.ACTION_MAIN);
			String category = mMainCategories.get(i);
			if (category.length() > 0) {
				intent.addCategory(category);
			}
			// 查找?guī)в?Intent.CATEGORY_LAUNCHER、Intent.CATEGORY_MONKEY的Activity
			List<ResolveInfo> mainApps = mPm.queryIntentActivities(intent, null, 0,
					ActivityManager.getCurrentUser()).getList();
			
			final int NA = mainApps.size();
			for (int a = 0; a < NA; a++) {
				ResolveInfo r = mainApps.get(a);
				String packageName = r.activityInfo.applicationInfo.packageName;
				if (MonkeyUtils.getPackageFilter().checkEnteringPackage(packageName)) {
					// 如果Activity屬于待測試Package,將其添加到mMainApps中。
					mMainApps.add(new ComponentName(packageName, r.activityInfo.name));
				} else {
				}
			}
		}
	} catch (RemoteException e) {
		Logger.err.println("** Failed talking with package manager!");
		return false;
	}

	if (mMainApps.size() == 0) {
		Logger.out.println("** No activities found to run, monkey aborted.");
		return false;
	}

	return true;
}
Monkey生成模擬測試事件,并執(zhí)行
// development/cmds/monkey/src/com/android/commands/monkey/Monkey.java
private int run(String[] args) {
	// 創(chuàng)建該對象,用于產生測試事件
	mEventSource = new MonkeySourceRandom(mRandom, mMainApps,
			mThrottle, mRandomizeThrottle, mPermissionTargetSystem);

	for (int i = 0; i < MonkeySourceRandom.FACTORZ_COUNT; i++) {
		if (mFactors[i] <= 0.0f) {
			((MonkeySourceRandom) mEventSource).setFactors(i, mFactors[i]);
		}
	}

	try {
		// 執(zhí)行Monkey測試
		crashedAtCycle = runMonkeyCycles();
	} finally {
		// Release the rotation lock if it's still held and restore the
		// original orientation.
		new MonkeyRotationEvent(Surface.ROTATION_0, false).injectEvent(
			mWm, mAm, mVerbose);
	}
}

runMonkeyCycles函數中調用MonkeySourceRandom的getNextEvent函數生成模擬測試事件(MonkeyEvent),調用MonkeyEventinjectEvent執(zhí)行模擬測試。

private int runMonkeyCycles() {
	int eventCounter = 0;
	int cycleCounter = 0;

	boolean shouldReportAnrTraces = false;
	boolean shouldReportDumpsysMemInfo = false;
	boolean shouldAbort = false;
	boolean systemCrashed = false;

	try {
		// TO DO : The count should apply to each of the script file.
		while (!systemCrashed && cycleCounter < mCount) {
			synchronized (this) {
			// 注意:因為先執(zhí)行過generateActivity,所以第一次調用會,會獲得啟動Activity的模擬測試事件
			MonkeyEvent ev = mEventSource.getNextEvent();
			if (ev != null) {
				int injectCode = ev.injectEvent(mWm, mAm, mVerbose);

			} else {
			}
		}
	} catch (RuntimeException e) {
		Logger.error("** Error: A RuntimeException occurred:", e);
	}
	Logger.out.println("Events injected: " + eventCounter);
	return eventCounter;
}

MonkeySourceRandom的getNextEvent,會在事件隊列(存儲模擬測試事件)為空時,產生測試對象。生成測試事件時,先生成一個隨機數,然后根據測試類型所占比例(比例越大,生成該測試類型的概率越大),生成不同測試類型。

// development/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
/**
 * generate an activity event
 */
public void generateActivity() {
	MonkeyActivityEvent e = new MonkeyActivityEvent(mMainApps.get(
			mRandom.nextInt(mMainApps.size())));
	mQ.addLast(e);
}

/**
 * if the queue is empty, we generate events first
 * @return the first event in the queue
 */
public MonkeyEvent getNextEvent() {
	if (mQ.isEmpty()) {
		generateEvents();
	}
	mEventCount++;
	MonkeyEvent e = mQ.getFirst();
	mQ.removeFirst();
	return e;
}

/**
 * generate a random event based on mFactor
 */
private void generateEvents() {
	// 生成隨機數
	float cls = mRandom.nextFloat();
	int lastKey = 0;
	// 根據Factor,即不同測試類型所占的比例,生成測試事件
	if (cls < mFactors[FACTOR_TOUCH]) {
		generatePointerEvent(mRandom, GESTURE_TAP);
		return;
	} else if (cls < mFactors[FACTOR_MOTION]) {
		generatePointerEvent(mRandom, GESTURE_DRAG);
		return;
	} else if (cls < mFactors[FACTOR_PINCHZOOM]) {
		generatePointerEvent(mRandom, GESTURE_PINCH_OR_ZOOM);
		return;
	} else if (cls < mFactors[FACTOR_TRACKBALL]) {
		generateTrackballEvent(mRandom);
		return;
	} else if (cls < mFactors[FACTOR_ROTATION]) {
		generateRotationEvent(mRandom);
		return;
	} else if (cls < mFactors[FACTOR_PERMISSION]) {
		mQ.add(mPermissionUtil.generateRandomPermissionEvent(mRandom));
		return;
	}

	// The remaining event categories are injected as key events
	for (;;) {
		if (cls < mFactors[FACTOR_NAV]) {
			lastKey = NAV_KEYS[mRandom.nextInt(NAV_KEYS.length)];
		} else if (cls < mFactors[FACTOR_MAJORNAV]) {
			lastKey = MAJOR_NAV_KEYS[mRandom.nextInt(MAJOR_NAV_KEYS.length)];
		} else if (cls < mFactors[FACTOR_SYSOPS]) {
			lastKey = SYS_KEYS[mRandom.nextInt(SYS_KEYS.length)];
		} else if (cls < mFactors[FACTOR_APPSWITCH]) {
			MonkeyActivityEvent e = new MonkeyActivityEvent(mMainApps.get(
					mRandom.nextInt(mMainApps.size())));
			mQ.addLast(e);
			return;
		} else if (cls < mFactors[FACTOR_FLIP]) {
			MonkeyFlipEvent e = new MonkeyFlipEvent(mKeyboardOpen);
			mKeyboardOpen = !mKeyboardOpen;
			mQ.addLast(e);
			return;
		} else {
			lastKey = 1 + mRandom.nextInt(KeyEvent.getMaxKeyCode() - 1);
		}

		if (lastKey != KeyEvent.KEYCODE_POWER
				&& lastKey != KeyEvent.KEYCODE_ENDCALL
				&& lastKey != KeyEvent.KEYCODE_SLEEP
				&& lastKey != KeyEvent.KEYCODE_SOFT_SLEEP
				&& PHYSICAL_KEY_EXISTS[lastKey]) {
			break;
		}
	}

	MonkeyKeyEvent e = new MonkeyKeyEvent(KeyEvent.ACTION_DOWN, lastKey);
	mQ.addLast(e);

	e = new MonkeyKeyEvent(KeyEvent.ACTION_UP, lastKey);
	mQ.addLast(e);
}

以Ttouch事件為例子,調用generatePointerEvent函數。通過DMS獲取Display對象(用于得知屏幕大?。?,生成MonkeyTouchEvent對象。

// development/cmds/monkey/src/com/android/commands/monkey/MonkeySourceRandom.java
private void generatePointerEvent(Random random, int gesture) {
	Display display = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);

	PointF p1 = randomPoint(random, display);
	PointF v1 = randomVector(random);

	long downAt = SystemClock.uptimeMillis();

	mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_DOWN)
			.setDownTime(downAt)
			.addPointer(0, p1.x, p1.y)
			.setIntermediateNote(false));

	// 省略

	randomWalk(random, display, p1, v1);
	mQ.addLast(new MonkeyTouchEvent(MotionEvent.ACTION_UP)
			.setDownTime(downAt)
			.addPointer(0, p1.x, p1.y)
			.setIntermediateNote(false));
}

調用MonkeyTouchEvent的injectEvent函數,使用InputManager向系統(tǒng)派發(fā)TouchEvent。

// development/cmds/monkey/src/com/android/commands/monkey/MonkeyMotionEvent.java
@Override
public int injectEvent(IWindowManager iwm, IActivityManager iam, int verbose) {
	MotionEvent me = getEvent();
	if ((verbose > 0 && !mIntermediateNote) || verbose > 1) {
		StringBuilder msg = new StringBuilder(":Sending ");
		msg.append(getTypeLabel()).append(" (");
		switch (me.getActionMasked()) {
			case MotionEvent.ACTION_DOWN:
				msg.append("ACTION_DOWN");
				break;
			case MotionEvent.ACTION_MOVE:
				msg.append("ACTION_MOVE");
				break;
			case MotionEvent.ACTION_UP:
				msg.append("ACTION_UP");
				break;
			case MotionEvent.ACTION_CANCEL:
				msg.append("ACTION_CANCEL");
				break;
			case MotionEvent.ACTION_POINTER_DOWN:
				msg.append("ACTION_POINTER_DOWN ").append(me.getPointerId(me.getActionIndex()));
				break;
			case MotionEvent.ACTION_POINTER_UP:
				msg.append("ACTION_POINTER_UP ").append(me.getPointerId(me.getActionIndex()));
				break;
			default:
				msg.append(me.getAction());
				break;
		}
		msg.append("):");

		int pointerCount = me.getPointerCount();
		for (int i = 0; i < pointerCount; i++) {
			msg.append(" ").append(me.getPointerId(i));
			msg.append(":(").append(me.getX(i)).append(",").append(me.getY(i)).append(")");
		}
		Logger.out.println(msg.toString());
	}
	try {
		// 派發(fā)TouchEvent
		if (!InputManager.getInstance().injectInputEvent(me,
				InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT)) {
			return MonkeyEvent.INJECT_FAIL;
		}
	} finally {
		me.recycle();
	}
	return MonkeyEvent.INJECT_SUCCESS;
}
Monkey主要相關類圖

【Android12】Monkey壓力測試源碼執(zhí)行流程分析,AndroidFramework,壓力測試,Monkey,自動化測試,源碼分析,anr,crash文章來源地址http://www.zghlxwxcb.cn/news/detail-842306.html

到了這里,關于【Android12】Monkey壓力測試源碼執(zhí)行流程分析的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 在Android Studio上使用Monkey工具對安卓應用進行壓力測試

    在Android Studio上使用Monkey工具對安卓應用進行壓力測試

    2–pct-trackball 調整軌跡事件的百分比(軌跡事件由一個或幾個隨機的移動組成,有時還伴隨有點擊)–(軌跡球) 3–pct-nav 調整“基本”導航事件的百分比(導航事件由來自方向輸入設備的up/down/left/right組成) 4–pct-majornav 調整“主要”導航事件的百分比(這些導航事件通常引發(fā)圖

    2024年04月15日
    瀏覽(29)
  • 【day01】monkey壓力測試,穩(wěn)定性

    1.壓力測試:在一定的時間內進行大量操作。 2.穩(wěn)定性測試:功能基本穩(wěn)定之后,一直做到回歸 主要找crash和anr問題,必解 測試:隨機操作(對整體app驗證,不針對模塊,不針對單個功能。用于模擬人的操作),如調節(jié)亮度,調節(jié)聲音,截屏,做設置。本質上monkey為偽隨機操

    2024年02月13日
    瀏覽(15)
  • android源碼學習- APP啟動流程(android12源碼)

    android源碼學習- APP啟動流程(android12源碼)

    百度一搜能找到很多講APP啟動流程的,但是往往要么就是太老舊(還是基于android6去分析的),要么就是不全(往往只講了整個流程的一小部分)。所以我結合網上現有的文章,以及源碼的閱讀和調試,耗費了3整天的時間,力求寫出一篇最完整,最詳細,最通俗易懂的文章,

    2024年02月11日
    瀏覽(22)
  • SpringMVC的執(zhí)行流程與源碼分析

    SpringMVC的執(zhí)行流程與源碼分析

    通過深入分析Spring MVC的源碼,我們可以更好地理解其工作原理和內部機制。這有助于我們更好地使用該框架進行Web應用程序的開發(fā),并解決實際開發(fā)中遇到的問題。同時,對于學習和研究Spring MVC框架的人來說,閱讀源碼并進行分析也是一種重要的學習和提升手段。 Spring MV

    2024年01月21日
    瀏覽(53)
  • 【SpringMVC】| SpringMVC執(zhí)行流程(含源碼分析)

    【SpringMVC】| SpringMVC執(zhí)行流程(含源碼分析)

    目錄 SpringMVC執(zhí)行流程 1.?SpringMVC常用組件 2.?DispatcherServlet初始化過程(源碼分析) 3.?DispatcherServlet調用組件處理請求 4. SpringMVC的完整執(zhí)行流程 圖書推薦:Spring Cloud Alibaba核心技術與實戰(zhàn)案例 1.? SpringMVC常用組件 (1) DispatcherServlet: 前端控制器 ,不需要工程師開發(fā),由框架

    2024年02月13日
    瀏覽(24)
  • Android Monkey測試

    當配置好一切環(huán)境的前提下,僅需套用以下基礎語法,即可簡單使用(更多的命令可以去Android的官網查詢) 舉例,如我這里的包名是 com.test.chj233 ,需要隨機生成 1萬次的點擊事件 如果你的是還未配置好adb環(huán)境,參照如下: ? ? ? ? 一、windows平臺? ? ? ? ??????????windo

    2024年02月12日
    瀏覽(14)
  • mybatis源碼學習之mybatis執(zhí)行流程分析

    mybatis源碼學習之mybatis執(zhí)行流程分析

    mybatis全局配置文件中涉及的標簽如下圖所示 下面我們來進行源碼分析。 配置文件的解析創(chuàng)建SqlSessionFactory 配置文件的解析主要涉及到的類如下:XMLConfigBuilder、XPathParser、XPath、XNode,其中XPath、XNode是對 1、build方法內部首先會根據輸入流等信息創(chuàng)建XMLConfigBuilder類的實例對象,

    2024年02月07日
    瀏覽(24)
  • 【Mybatis源碼解析】mapper實例化及執(zhí)行流程源碼分析

    基礎環(huán)境:JDK17、SpringBoot3.0、mysql5.7 儲備知識:《【Spring6源碼?AOP】AOP源碼解析》、《JDBC詳細全解》 基于SpringBoot的Mybatis源碼解析: 1.如何對mapper實例化bean 在加載BeanDefinition時,會將SqlSessionFactory、SqlSessionTemplate、MapperScannerConfigurer加載到注冊表中,以供后續(xù)進行實例化。

    2024年02月01日
    瀏覽(25)
  • Android 12系統(tǒng)源碼_窗口管理(一)WindowManagerService的啟動流程

    Android 12系統(tǒng)源碼_窗口管理(一)WindowManagerService的啟動流程

    WindowManagerService是Android系統(tǒng)中重要的服務,它是WindowManager的管理者,WindowManagerService無論對于應用開發(fā)還是Framework開發(fā)都是重要的知識點,究其原因是因為WindowManagerService有很多職責,每個職責都會涉及重要且復雜的系統(tǒng),這使得WindowManagerService就像一個十字路口的交通燈一樣

    2024年02月11日
    瀏覽(24)
  • Flink window 源碼分析1:窗口整體執(zhí)行流程

    Flink window 源碼分析1:窗口整體執(zhí)行流程

    注:本文源碼為flink 1.18.0版本。 其他相關文章: Flink window 源碼分析1:窗口整體執(zhí)行流程 Flink window 源碼分析2:Window 的主要組件 Flink window 源碼分析3:WindowOperator Flink window 源碼分析4:WindowState Window 本質上就是借助狀態(tài)后端緩存著一定時間段內的數據,然后在達到某些條件

    2024年01月16日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包