笔记:Context

news2025/1/18 6:05:28

Context 是上下文对象,是 Android 常用类 Activity、Service 和 Application 都间接继承 Context ,Context 是一个抽象类,内部定义了很多方法和静态常量,具体实现类是 ContextImpl
在这里插入图片描述
ContextImpl 和 ContextWrapper 继承子 Context ,ContextWrapper 内部包含了一个 Context 类型的对象 mBase对象,这个对象指向 ContextImpl ,ContextWrapper 是装饰类,它对 ContextImpl 进行了包装,ContextThemeWrapper、Service、Application 都继承自 ContextWrapper 都可以通过 mBase 来使用 Context 的方法,同时它们也是装饰了,ContextThemeWrapper 中包含了和主题相关的方法

Application Context 创建过程

Android 应用程序启动的最后一步,也是应用程序的入口是 RuntimeInit.java 类通过反射调用其静态 main 方法并创建 ActivityThread 对象
位置:\frameworks\base\core\java\android\app\ActivityThread.java

	public static void main(String[] args) {
        ......

        Looper.prepareMainLooper();	// 创建一个消息循环

        ......
        ActivityThread thread = new ActivityThread(); 	// 创建 ActivityThread 对象
        thread.attach(false, startSeq);					// 并调用attach方法

        ......
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
	private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ......
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            ......
        } else {
           ......
            try {
                mInstrumentation = new Instrumentation();
                mInstrumentation.basicInit(this);
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }
		.......
    }

system 表示是否是系统进程,这个只有在 Framework 进程启动时才会调用到,直接调用了 attachApplication 方法,通过 Binder进程间通讯的方式,向 AMS 发送了一个消息
位置:\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

	@Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        if (thread == null) {
            throw new SecurityException("Invalid application interface");
        }
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);  // 调用 attachApplicationLocked 方法
            Binder.restoreCallingIdentity(origId);
        }
    }

	@GuardedBy("this")
    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {

        ......
            if (app.isolatedEntryPoint != null) {
                // This is an isolated process which should just call an entry point instead of
                // being bound to an application.
                thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
            } else if (app.instr != null) {
                thread.bindApplication(processName, appInfo, providers,
                        app.instr.mClass,
                        profilerInfo, app.instr.mArguments,
                        app.instr.mWatcher,
                        app.instr.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, isAutofillCompatEnabled);
            } else {
                thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, isAutofillCompatEnabled);
            }
        ......
        return true;
    }

可以看到这里面又调用了 IApplicationThread.bindApplication 方法,IApplicationThread 是 ActivityThread 中 ApplicationThread binder 对象的客户端
位置:\frameworks\base\core\java\android\app\ActivityThread.java

	private class ApplicationThread extends IApplicationThread.Stub {
		......
		public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, boolean autofillCompatibilityEnabled) {

            if (services != null) {
                if (false) {
                    // Test code to make sure the app could see the passed-in services.
                    for (Object oname : services.keySet()) {
                        if (services.get(oname) == null) {
                            continue; // AM just passed in a null service.
                        }
                        String name = (String) oname;

                        // See b/79378449 about the following exemption.
                        switch (name) {
                            case "package":
                            case Context.WINDOW_SERVICE:
                                continue;
                        }

                        if (ServiceManager.getService(name) == null) {
                            Log.wtf(TAG, "Service " + name + " should be accessible by this app");
                        }
                    }
                }

                // Setup the service cache in the ServiceManager
                ServiceManager.initServiceCache(services);
            }

            setCoreSettings(coreSettings);

            AppBindData data = new AppBindData();
            data.processName = processName;
            data.appInfo = appInfo;
            data.providers = providers;
            data.instrumentationName = instrumentationName;
            data.instrumentationArgs = instrumentationArgs;
            data.instrumentationWatcher = instrumentationWatcher;
            data.instrumentationUiAutomationConnection = instrumentationUiConnection;
            data.debugMode = debugMode;
            data.enableBinderTracking = enableBinderTracking;
            data.trackAllocation = trackAllocation;
            data.restrictedBackupMode = isRestrictedBackupMode;
            data.persistent = persistent;
            data.config = config;
            data.compatInfo = compatInfo;
            data.initProfilerInfo = profilerInfo;
            data.buildSerial = buildSerial;
            data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
            sendMessage(H.BIND_APPLICATION, data);
        }
        ......
	}

最后调用了ActivityThread.sendMessage(),sendMessage 发送了一个 Handler 的异步消息,最后被 handleMessage 方法处理
在这里插入图片描述

private void handleBindApplication(AppBindData data) {
        ......
        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
        ......
        final InstrumentationInfo ii;
        // 创建 Instrumentation
        if (data.instrumntationName != null) {
            try {
                ii = new ApplicationPackageManager(null, getPackageManager())
                        .getInstrumentationInfo(data.instrumentationName, 0);
            } catch (PackageManager.NameNotFoundException e) {
                throw new RuntimeException(
                        "Unable to find instrumentation info for: " + data.instrumentationName);
            }

            // Warn of potential ABI mismatches.
            if (!Objects.equals(data.appInfo.primaryCpuAbi, ii.primaryCpuAbi)
                    || !Objects.equals(data.appInfo.secondaryCpuAbi, ii.secondaryCpuAbi)) {
                Slog.w(TAG, "Package uses different ABI(s) than its instrumentation: "
                        + "package[" + data.appInfo.packageName + "]: "
                        + data.appInfo.primaryCpuAbi + ", " + data.appInfo.secondaryCpuAbi
                        + " instrumentation[" + ii.packageName + "]: "
                        + ii.primaryCpuAbi + ", " + ii.secondaryCpuAbi);
            }

            mInstrumentationPackageName = ii.packageName;
            mInstrumentationAppDir = ii.sourceDir;
            mInstrumentationSplitAppDirs = ii.splitSourceDirs;
            mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
            mInstrumentedAppDir = data.info.getAppDir();
            mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
            mInstrumentedLibDir = data.info.getLibDir();
        } else {
            ii = null;
        }

        .......
        
        try {
            
            app = data.info.makeApplication(data.restrictedBackupMode, null); // 创建 Application 对象

            // Propagate autofill compat state
            app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);

            mInitialApplication = app;

            .......
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            catch (Exception e) {
                throw new RuntimeException(
                    "Exception thrown in onCreate() of "
                    + data.instrumentationName + ": " + e.toString(), e);
            }
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                      "Unable to create application " + app.getClass().getName()
                      + ": " + e.toString(), e);
                }
            }
        } finally {
            if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
                    || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
                StrictMode.setThreadPolicy(savedPolicy);
            }
        }
		......
    }

handleBindApplication 方法首先通过反射创建了 Instrumentation 对象,并执行了 init 方法初始化,然后调用 LoadedApk 类的 makeApplication 方法来创建一个 Application 对象,在 LoadedApk 类中会把创建的 Application 对象保存在 mApplication 变量中,并返回这个变量赋值给 ActivityThread 类中的 mInitialApplication 变量
位置:\frameworks\base\core\java\android\app\LoadedApk.java

	public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        // 检查是否已经创建
        if (mApplication != null) {
            return mApplication;
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

        Application app = null;
		// 设置 Application 的类名
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
        	// 创建 Application 及其 Context
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "initializeJavaContextClassLoader");
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            // 1.创建Context
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            // 2.创建 Application
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            // 3.将两个对象关联起来
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        // 4.保存创建的Application
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
            	// 调用 Application 中的 onCreate() 方法
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }

        .......
        return app;
    }

1.首先调用 ContextImpl.createAppContext 静态方法创建 ContextImpl 实例

2.调用 newApplication 方法并传入 ContextImpl 实例和之前设置的 appClass,来创建该类名对应的一个 Application实例,在 newApplication 方法内部,创建完 Application 实例后,会调用其 attach 方法并传入 ContextImpl 实例,在 attach 方法中又会调用其父类 ContextWrapper(装饰类) 中的 attachBaseContext() 方法,将 ContextImpl 对象设置给内部实例变量 mBase, 这样 Application 内部就持有了Context的实现类ContextImpl实例
位置:\frameworks\base\core\java\android\app\Instrumentation.java

	static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance(); // 创建 Application 类,相当于 new 关键字
        app.attach(context);	// 调用 Application 的 attach 方法
        return app;
    }

位置:\frameworks\base\core\java\android\app\Application.java

    /* package */ final void attach(Context context) {
        attachBaseContext(context); // 直接调用 attachBaseContext 方法,attachBaseContext 方法是在其父类 ContextWrapper 实现的
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

位置:\frameworks\base\core\java\android\content\ContextWrapper.java

    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base; // 将 ContextImpl 对象设置给内部实例变量 mBase
    }

3.最后调用 ContextImpl 的实例方法 setOuterContext,传入这个 Application 实例,这样 ContextImpl 实例也会持有 Context 的包装类 ContextWrapper 实例

4.创建完一个 Application 对象后,将其保存在 mApplication 实例变量中,由于一个应用程序进程中的 LoadedApk 对象也是一个单例,因此一个进程中只能创建一个 Application 对象。

Application 得到 Context

都知道得到 Application 的 Context 是通过 getApplicationContext() 方法获得到的,这个方法是在 Application 的父类 ContextWrapper 中实现的
在这里插入图片描述

Activity 创建 Context

从上面得知,创建 Application 对象是通过 ActivityManagerService 中的 attachApplicationLocked 方法中的 thread.bindApplication 方法去创建并绑定到 AMS 中,在 thread.bindApplication 之后会调用 mStackSupervisor.attachApplicationLocked(app) 方法去启动应用的 Activity,详细见这篇文章:https://blog.csdn.net/weixin_44128558/article/details/132140588 之后经过层层调用会调用到 ActivityThread 中的 performLaunchActivity 方法
位置:\frameworks\base\core\java\android\app\ActivityThread.java

	/**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        
        ContextImpl appContext = createBaseContextForActivity(r); //1.创建 Context
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);  // 2.创建一个新的Activity
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } 
        
        ......
        
        try {
            ......

            if (activity != null) {
                ......
                appContext.setOuterContext(activity); //3.将Activity 和 Context 关联起来
                activity.attach(appContext, this, getInstrumentation(), r.token,	//4.调用attach 将 ContextImpl 对象设置给内部实例变量 mBase
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

                ......
                if (r.isPersistable()) { // 调用 activity 的 OnCreate 方法
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); 
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ......
                r.activity = activity;	//5.保存创建的Activity
            }
            ......
        } 
        .......

        return activity;
    }

	private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        ......

        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

        ......
        return appContext;
    }

可见,与 Application 创建 Context 流程类似
1.直接调用 createBaseContextForActivity 方法返回一个 ContextImpl 对象

	private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        ......
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

        ......
        return appContext;
    }

createBaseContextForActivity 方法里调用 ContextImpl.createActivityContext 静态方法创建 ContextImpl 实例并返回
位置:\frameworks\base\core\java\android\app\ContextImpl.java

static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
        ......
        
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader);
        
        ......

        final ResourcesManager resourcesManager = ResourcesManager.getInstance();

        // Create the base resources for which all configuration contexts for this Activity
        // will be rebased upon.
        context.setResources(resourcesManager.createBaseActivityResources(activityToken,
                packageInfo.getResDir(),
                splitDirs,
                packageInfo.getOverlayDirs(),
                packageInfo.getApplicationInfo().sharedLibraryFiles,
                displayId,
                overrideConfiguration,
                compatInfo,
                classLoader));
        context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
                context.getResources());
        return context;
    }

这里真正创建了 Context

2. 调用 newActivity 方法并传入 ContextImpl 实例,实际调用的是 AppComponentFactory 的 instantiateActivity() 方法,该方法通过反射方式创建 Activity
位置:frameworks\base\core\java\android\app\Instrumentation.java

	public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        String pkg = intent != null && intent.getComponent() != null
                ? intent.getComponent().getPackageName() : null;
        return getFactory(pkg).instantiateActivity(cl, className, intent);
    }

位置:frameworks\base\core\java\android\app\AppComponentFactory.java

	public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Activity) cl.loadClass(className).newInstance();
    }

3. 与 Application 相同,调用 ContextImpl 的实例方法 setOuterContext,传入这个 Activity 实例,这样 ContextImpl 实例也会持有 Context 的包装类 ContextWrapper 实例

4. 再调用 Activity 的 attach ,也 Application 类似,该方法中会调用其父类 ContextWrapper 中的 attachBaseContext 方法,将 ContextImpl 对象设置给内部实例变量 mBase
位置:\frameworks\base\core\java\android\app\Activity.java

	final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context); // 将 ContextImpl 对象设置给内部实例变量 mBase

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this, window, activityConfigCallback);  //创建 PhoneWindow 应用程序的窗口
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);				// 设置回调接口,有关屏幕事件回调
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
        mUiThread = Thread.currentThread();		//创建刷新ui的线程

       ......

        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager(); // 得到 WindowManager 并赋给 mWindowManager 成员变量,这样 Activity 可以通过 getWindowManager 方法来获得 WindowManager
        mCurrentConfig = config;

        mWindow.setColorMode(info.colorMode);

        setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
        enableAutofillCompatibilityIfNeeded();
    }

	@Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        if (newBase != null) {
            newBase.setAutofillClient(this);
        }
    }

首先调用 attachBaseContext 方法,attachBaseContext 方法中又直接调用其父类 (ContextThemeWrapper) 的 attachBaseContext 方法
在这里插入图片描述
ContextThemeWrapper 又会调用其父类 (ContextThemeWrapper) 的 attachBaseContext 方法,将 ContextImpl 对象设置给内部实例变量 mBase (与上面 Application 相同)

之后会创建 PhoneWindow ,PhoneWindow 会接受很多事件,比如点击,菜单弹出,屏幕焦点变化等,这些都会转发给与 PhoneWindow 关联的 Activity,通过 Window.Callback 回调接口实现,当前的 Activity 通过 Window 的 setCallback 方法 传递给 PhoneWindow

5.创建完一个 Activity 对象后,将其保存在 mApplication 实例变量中

Service 创建 Context

Service 的 Context创建过程与 Activity 的 Context 创建过程类似,是在 Service 的启动过程中被创建,Service 是通过 ActiviytThread 的内部类 ApplicationThread 调用 scheduleCreateService 方法来启动
在这里插入图片描述
与 Activity 类似,最后将创建的 ContextImpl 一路传递到 Context

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

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

相关文章

用Python代码删除Word文档空白行

Word文档内容的整洁性与易读性是体现文档水平的关键因素之一。许多错误或不合理的内容&#xff0c;如多余的空白行&#xff0c;往往会影响阅读流畅度&#xff0c;或是干扰自动化数据处理的准确性。特别是在进行数据分析、报告生成及长文档编辑时&#xff0c;多余的空白行可能导…

赚钱其实没有秘密,多琢磨一下不丢人

为什么学了很多知识还是挣不到钱&#xff1f; 挣不到钱&#xff0c;是因为你不够稀缺&#xff1b;挣钱太少&#xff0c;是因为你不懂杠杆&#xff0c;用杠杆撬动稀缺&#xff0c;个人价值自然水涨船高。 学富五车&#xff0c;为何财库依旧空空&#xff1f;怎样才能提高挣钱的…

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五)

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09; 参考 目录 文章目录 SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09;1、设置sping.beaninfo.ignore属性2、…

Python自动化办公2.0 即将发布

第一节课&#xff1a;数据整理与清洗 第二节课&#xff1a;数据筛选、过滤与排序 第三节课&#xff1a;高级数据处理技巧 第四节课&#xff1a;数据可视化与实践案例 第五节课&#xff1a;统计分析与报表 第六节&#xff1a;常见的Excel报表 与下方的课程形成知识体系&…

『ZJUBCA MeetUP』 5月25日线下活动——Aptos 链的动态与应用

2024 求是创新 ZJUBCA Sponsored by the ALCOVE Community TIME&#xff1a;2024/05/25 ADD&#xff1a;浙江大学紫金港校区 --- Alcove 是 Aptos 公链与 Alibaba Cloud 共同打造的亚洲首个 Move 开发者社区&#xff0c;致力于支持开发者使用 Move 语言构建下一代 Web3 应用&am…

探索 Ollama: 你的本地 AI 助手

本期推荐的开源项目是 Ollama&#xff0c;它是一款本地大模型运行工具&#xff0c;可以帮助用户轻松下载和运行各种大型语言模型&#xff08;LLM&#xff09;&#xff0c;而无需将数据上传到云端。以下是关于 Ollama 的介绍以及安装和使用教程&#xff1a; Ollama 是什么&#…

springboot结合mybatis使用多数据源的方式

背景 最近有一个需求&#xff0c;有两个库需要做同步数据&#xff0c;一个Doris库&#xff0c;一个mysql库&#xff0c;两边的表结构一致&#xff0c;这里不能使用navicat等工具提供的数据传输之类的功能&#xff0c;只能使用代码做同步&#xff0c;springboot配置多数据…

公众号爆文全攻略:最新推荐机制与实战干货分享

期待已久的公众号爆文直播来了&#xff01;老规矩&#xff0c;免费&#xff0c;只讲干货&#xff01;全程不废话&#xff01; 本次直播你将收获&#xff1a; 深度拆解公众号最新推荐机制&#xff1a;掌握公众号运营的核心规则&#xff0c;精准把握推荐逻辑&#xff0c;让你的内…

云动态摘要 2024-05-31

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [1.5折起]年中盛惠--AI分会场 腾讯云 2024-05-30 人脸核身、语音识别、文字识别、数智人、腾讯混元等热门AI产品特惠&#xff0c;1.5折起 云服务器ECS试用产品续用 阿里云 2024-04-14 云…

手写HTML字符串解析成对应的 AST语法树

先看效果 展示如下&#xff1a; HTML模版 转成ast语法树后 在学习之前&#xff0c;我们需要了解这么一个问题&#xff0c;为什么要将HTML字符串解析成对应的 AST语法树。 为什么&#xff1f; 语法分析&#xff1a;HTML字符串是一种标记语言&#xff0c;其中包含了大量的标签…

掀桌子、降价、免费...之后,国内大模型应用进入高速时代

5月15日&#xff0c;字节跳动打响大模型市场价格战第一枪&#xff1b;5月21日阿里云更狠&#xff0c;价格降了97%&#xff0c;比字节还便宜37.5%同日&#xff0c;百度更为激进&#xff0c;直接宣布其两款主力模型ENIRE Speed和ENIRE Lite全面免费&#xff1b;5月22号&#xff0…

Windows10专业版系统安装Hyper-V虚拟机软件

Windows10专业版系统安装Hyper-V虚拟机软件 适用于在Windows10专业版系统安装Hyper-v虚拟机软件。 1. 安装准备 1.1 安装平台 Windows 10 1.2. 软件信息 软件名称软件版本安装路径windowswindows 10 专业版Hyper-vHyper-v 2. Hyper-v搭建 2.1打开cmd软件 2.2打开控制面…

【PostgreSQL17新特性之-explain命令新增选项】

EXPLAIN是一个用于显示语句执行计划的命令&#xff0c;可用于显示以下语句类型之一的执行计划&#xff1a; - SELECT - INSERT - UPDATE - DELETE - VALUES - EXECUTE - DECLARE - CREATE TABLE AS - CREATE MATERIALIZED VIEWPostgreSQL17-beta1版本近日发布了&#xff0c;新…

使用Prompt,轻松实现你的第一个全栈项目

前言 还有程序员没有应用过大模型技术吗&#xff1f;是工具也可以&#xff01;如果你还未使用过大模型技术&#xff0c;那么我劝你尽早行动&#xff0c;它会成为你开发的一大神器。如果你对大模型感兴趣&#xff0c;同时想使用大模型技术来开发产品&#xff0c;我接下来这个实…

Ubuntu24.04 LTS安装中文输入法

前言 最近&#xff0c;windows玩没了&#xff0c;一怒之下决定换一个操作系统&#xff0c;当然就是最新的Ubuntu24.04 LTS.&#xff0c;其中魔法和咒语&#xff08;汉语&#xff09;是inux遇到的第一大难关&#xff0c;我权限不够教不了魔法&#xff0c;但我可以教你咒语(๑•…

JVM优化之垃圾收集器

JVM优化之垃圾收集器 Serial收集器Parallel Scavenge收集器ParNew收集器 如果说垃圾收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回收的具体实现。 没有最好的垃圾收集器&#xff0c;只有根据具体应用场景选择适合自己的垃圾收集器。 Serial收集器 #使用方…

GPU学习(1)

一、为什么要GPU 我们先看一个基本的神经网络计算 YF(x)AxB 这就是一次乘法一次加法 &#xff0c;也叫FMA&#xff0c;(fused multiply-add) 如果矩阵乘&#xff0c;就是上面的那个式子扩展一下&#xff0c;所以又用了这张老图 比如你要多执行好几个yAxB&#xff0c;可能比较简…

C++11中的新特性(2)

C11 1 可变参数模板2 emplace_back函数3 lambda表达式3.1 捕捉列表的作用3.2 lambda表达式底层原理 4 包装器5 bind函数的使用 1 可变参数模板 在C11之前&#xff0c;模板利用class关键字定义了几个参数&#xff0c;那么我们在编译推演中&#xff0c;我们就必须传入对应的参数…

在鲲鹏服务器上安装nginx

华为鲲鹏服务器采用华为自研cpu ARMv8架构,提供 Windows 和多个Linux 系统 常使用 CentOS 7.6 64bit with ARM Nginx 和 Apache 一样都是一种 Web 服务器。是基于 REST 架构风格&#xff0c;以统一资源描述符URI 或者统一资源定位符URL 作为沟通依据&#xff0c;通过 HTTP 协议…

【算法】模拟算法——Z字形变换(medium)

题解&#xff1a;模拟算法——Z字形变换(medium) 目录 1.题目2.题解3.参考代码4.总结 1.题目 题目链接&#xff1a;LINK 2.题解 利用模拟&#xff0c;来解决问题。 首先创建出一个O(numRows*n)的数组来&#xff0c;并按照题目要求把每个字符按顺序填进去。 这里以numRows…