应用--WebApplication
应用--Program中的WebApplication
在6.0,微软团队对于NetCore做了很大的改变,其中有一个改变就是推出了新的托管模型--最小托管模型,使用该模型可以创建最小的web应用。(最小webapi请查看官网)
需要掌握:
- 什么是最小托管模型?以及他的作用
- 什么是WebApplication和WebApplicationBuilder?他们和Host的区别是什么
- WebApplication代码上以及对应逻辑上的构造流程,能简单描述就好了
- WebApplication的六个属性以及其作用,为什么需要这6个属性?
- WebApplicationBuilder的作用
- WebApplication的6个属性以及继承4个接口有什么用
我自己默写一遍,整理完有点乱,
首先,最小托管模型是6.0微软推出来的一个新的应用模板,为的是方便配置和学习,他只有3句代码,利用他可以生成最小webapi。
第一句是var bulider = WebAppliaction.CreateBuilder();
这句代码的作用是通过调用WebAppliaction的工厂方法CreateBuilder()得到WebApplicationBuilder对象,因为创建一个WebApplication对象需要一个Host,Host则必须由HostBuilder创建,所以WebApplicationBuilder对象的作用是提供一个封装好的HostBuilder对象用来构建IHost,
它含有6个属性以及一个构造函数,属性包括IServiceCollection依赖注入容器Services、ConfigureManage配置管理Configure、IWebHostEnvironment托管环境environment、ILoggingBuilder日志记录logging、ConfigureWebHostBuilder类型webhost、ConfigureHostBuilder类型host,需要这6个属性的目的就是用来提供HostBuilder的创建
构造函数的作用是根据传进来的命令行参数来初始化这些属性,首先他会初始化一个_hostBuilder对象,然后创建一个bootstrapBuilder对象用来调用他的拓展方法收集服务和配置,赋值给services和configure属性,接下里根据bootstrapBuilder对象的一些属性,初始化剩余属性,初始化WebHost和Host。
第二句代码是var app = bulider.bulider();
在这句代码之前,我们可以注入自己的一些服务和系统服务,通过调用AddScope()等依赖注入方法或者使用系统提供的服务方法、如AddController(),
这句代码的作用是,根据得到WebApplicationBuilder对象来创建WebApplication,这句代码最重要的就是,把services和configure属性赋值给HostBuilder,然后我们可以看到这个对象继承了4个接口,一个是IHost接口,这就解释了为什么WebApplicationBuilder需要有一个ConfigurHostBuilder对象,还有一个IApplicationBuilder接口,这个接口是构建中间件管道服务的接口,所以我们的中间件可以直接注册在WebApplication的原因,IEndpointRouteBuilder则是默认构造了路由,还有一个异步释放的接口。
第三句代码是app.Run();
在这句代码之前可以注入中间件服务,比如UseAuthorization()之类的,
这句代码的作用是,通过调用WebApplication内部的BuildRequestDelegation()方法把注册的中间件管道作为请求处理器,至此一个WebApplication对象完成
所以根据这几行代码我们不难看出,WebApplication其实就是对Host的再次封装,只是为了我们更加简单的去配置一些我们需要的服务和中间件
构造流程
得到WebApplicationBuilder构造器 -> 配置服务 -> build()方法得到WebApplication对象 -> 配置中间件 -> 运行主机
// 得到应用构造器:WebApplicationBuilder
var builder = WebApplication.CreateBuilder(args);
// 配置日志
builder.Logging.AddLog4Net("ConfigFile/log4net.config");
// 得到应用:WebApplication
var app = builder.Build();
// 配置中间件
app.UseStaticFiles();
// 运行主机
app.Run();
你可能在疑惑,在3.0至5.0的版本都是直接调用Host.CreateDefaultBuilder()方法得到HostBuilder构造器,然后调用ConfigureWebHostBuilder()配置WebHost,然后在上面配置一些服务,构建然后运行。而6.0使用WebApplication.CreateBuilder(args)方法得到的是一个WebApplicationBuilder构造器,然后构建运行,他们有什么区别吗?
答:没什么区别,流程都是一样的,WebApplication对主机和服务做了一个更进一步的封装,使得更加方便配置和学习,而且额外暴露2个Host属性和WebHost属性用来配置(这2个属性也是方便之前的版本迁移到6.0的关键)。举个很简单的例子
| 区别 | 在3.0至5.0的版本中 | 6.0版本中 |
|---|---|---|
| 中间管道的配置 | 必须放在Startup.cs类中的Configure方法中,或者通过ConfigureWebHostDefaults中的webBuilder 来配置服务 | 通过调用app.UseXXXX来配置 |
| 路由中间件 | 使用app.UseRouting()之后才能app.UseEndpoints() | 因为WebApplication继承了WebIEndpointRouteBuilder可以直接将路由,而无需显式调用 UseEndpoints 或 UseRouting。 |
按照上方Program.cs流程顺序介绍相关类和方法
1. CreateBuilder(args) 方法:
使用默认值来生成构造一个WebApplicationBuilder对象
该方法有3个重载:
WebApplication.CreateBuilder():使用预配置的默认值来构造;WebApplication.CreateBuilder(String []):根据传入的命令行参数初始化;WebApplication.CreateBuilder(WebApplicationOption):根据传入的预配置来构造;
public class WebApplicationOptions
{
public WebApplicationOptions();
// 命令行参数
public string[]? Args { get; init; }
// 环境名称。
public string? EnvironmentName { get; init; }
// 应用程序名称。
public string? ApplicationName { get; init; }
// 内容根路径。
public string? ContentRootPath { get; init; }
// Web 根路径。
public string? WebRootPath { get; init; }
}
WebApplicationBuilder类:
要创建一个WebApplication对象,需要一个IHost对象,IHost对象是通过IHostBuilder创建的,而WebApplication需要WebApplicationBuilder来构建,所以WebApplicationBuilder还需要一个IHostBuilder对象,我们针对WebApplication的一切配置,最终都会转移到这个对象上面才能生效,所以这就是为什么WebApplicationBuilder提供了这6个属性的原因。
构造函数
当通过调用WebApplication.CreateBuilder()方法的时候,根据命令行的参数传给WebApplicationBuilder的构造函数,而WebApplicationBuilder的构造函数内部会做:
- 创建
HostBuilder _hostBuilder类。 - 创建
BootstrapHostBuilder对象,调用拓展方法ConfigureWebHostBuilder()和ConfigureDefaults()方法,将初始化的设置和服务收集起来,然后把收集到的服务和配置注入到Services成员属性和Configure成员属性中。 - 然后会创建承载托管环境的
IWebHostEnvironment,对于Environment成员属性初始化。 - 调用
Apply()方法得到HostBuilderContext上下文。 - 使用
HostBuilderContext的WebHostBuilderContext,创建ConfigureWebHostBuilder和ConfigureHostBuilder并赋值给WebHost和Host属性。初始化Logging属性。 - 得到一个
Configure、Environment、WebHost、Host、Logging属性都被初始化的WebApplication对象。
WebApplicationBuilder构造函数源码
public class WebApplicationBuilder
{
private readonly HostBuilder _hostBuilder = new HostBuilder();
private WebApplication _application;
// 提供应用程序正在运行的Web托管环境的信息
public IWebHostEnvironment Environment { get; }
// 提供应用程序所需要的服务,即依赖注入容器
public IServiceCollection Services { get; }
// 提供应用程序所需要的配置
public ConfigurationManager Configuration { get; }
// 提供日志记录
public ILoggingBuilder Logging { get; }
// 配置WebHost服务器特定属性,实现IWebHostBuilder
public ConfigureWebHostBuilder WebHost { get; }
// 配置Host特定属性,实现IHostBuilder
public ConfigureHostBuilder Host { get; }
public WebApplicationBuilder(WebApplicationOptions options)
{
//创建BootstrapHostBuilder并利用它收集初始化过程中设置的配置、服务和针对依赖注入容器的设置
var args = options.Args;
var bootstrap = new BootstrapHostBuilder();
bootstrap
.ConfigureDefaults(null)
// 此处用于中间件的注册
.ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.Configure(app =>app.Run(_application.BuildRequestDelegate())))
.ConfigureHostConfiguration(config => {
// 添加命令行配置源
if (args?.Any() == true)
{
config.AddCommandLine(args);
}
// 将WebApplicationOptions配置选项转移到配置中
Dictionary<string, string>? settings = null;
if (options.EnvironmentName is not null) {
(settings ??= new())[HostDefaults.EnvironmentKey] = options.EnvironmentName;
}
if (options.ApplicationName is not null){
(settings ??= new())[HostDefaults.ApplicationKey] = options.ApplicationName;
}
if (options.ContentRootPath is not null){
(settings ??= new())[HostDefaults.ContentRootKey] = options.ContentRootPath;
}
if (options.WebRootPath is not null) {
(settings ??= new())[WebHostDefaults.WebRootKey] = options.EnvironmentName;
}
if (settings != null)
{
config.AddInMemoryCollection(settings);
}
});
// 将BootstrapHostBuilder收集到配置和服务转移到Configuration和Services上
// 将应用到BootstrapHostBuilder上针对依赖注入容器的设置转移到_hostBuilder上
// 得到BuilderContext上下文
bootstrap.Apply(_hostBuilder, Configuration, Services, out var builderContext);
// 如果提供了命令行参数,在Configuration上添加对应配置源
if (options.Args?.Any() == true)
{
Configuration.AddCommandLine(options.Args);
}
// 构建WebHostBuilderContext上下文
// 初始化Host、WebHost和Logging属性
var webHostContext = (WebHostBuilderContext)builderContext.Properties[typeof(WebHostBuilderContext)];
Environment = webHostContext.HostingEnvironment;
Host = new ConfigureHostBuilder(builderContext, Configuration, Services);
WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);
Logging = new LogginigBuilder(Services);
}
}
简单来说WebApplicationBuilder的作用就是为了提供构建封装的一个HostBuilder对象
注意:记住这6个属性,NetCore的生态库基本上就是围绕这几个来构建的
接下来我们按照这几个属性来逐一分析其作用
IWebHostEnvironment Environment 属性
接口,继承IHostEnvironment,提供一些该应用程序的环境信息,比如根目录、环境变量、名称等,包含几个属性
WebRootPath,用于设置和获取Web的根目录,默认是wwwroot的子文件夹(在5.0的时候。是通过Host.CreateDefaultBuilder()方法去设置的);ApplicationName:应用名称;ContentRootFileProvider:;ContentRootPath:;EnvironmentName:环境名称;
比如我们经常用的判断是否是开发环境就是用的该类
demo
var builder = WebApplication.CreateBuilder(args);
bool isDevelopment = builder.Environment.IsDevelopment();
IServiceCollection Services 属性
依赖注入容器,可以注入服务,也可也获取服务实例,继承于ICollection<ServiceDescriptor>泛型接口,这个我们后续会在依赖注入章节详细描述。
通过往该属性添加系统服务支持,或者注入自己的服务
demo
var builder = WebApplication.CreateBuilder(args);
// 注入Sql数据库支持
builder.Services.AddDbContext<SqlDbContext>();
// 依赖注入
builder.Services.AddSingleton<PersonService>();
ConfigurationManager Configuration 属性
配置管理,是6.0版本新增的类,更见简单的用于获取和设置系统配置文件,替换掉了5.0版本中IConfigurationBuilder接口和IConfigurationRoot接口(6.0是把这2个接口整合在一起了,看源码可以发现ConfigureManager继承于这2个接口)
ConfigurationManager密封类源码
public sealed class ConfigurationManager : IConfigurationBuilder, IConfigurationRoot, IConfiguration, IDisposable
{
public ConfigurationManager();
public string this[string key] { get; set; }
public void Dispose();
public IEnumerable<IConfigurationSection> GetChildren();
public IConfigurationSection GetSection(string key);
}
public interface IConfigurationBuilder
{
IDictionary<string, object> Properties { get; }
IList<IConfigurationSource> Sources { get; }
IConfigurationBuilder Add(IConfigurationSource source);
IConfigurationRoot Build();
}
增加系统配置文件
当你调用builder.Configuration.AddJsonFile("文件名称")拓展方法的来增加自定义配置文件的时候(实际上是往调用的IConfigurationBuilder.Add()方法往IList<IConfigurationSource> Sources { get; }属性增加了一条数据),会将立即加载提供程序并更新配置,这样可以不用等到Build()方法,可以避免在部分生成方法多次加载配置源数据。
demo
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("servicesetting.json");
获取系统配置数据
demo
var builder = WebApplication.CreateBuilder(args);
ConfigurationManager config = builder.Configuration;
string value1 = config["DBContextModel:SqlConnection"];
IConfigurationSection value2 = config.GetSection("DBContextModel");
ILoggingBuilder Logging
提供日志记录,包括控制台、调试、事件日志、TraceSource等组件,你是不是在疑惑为什么创建项目的时候appsetting.json配置文件有一个这样的配置?他就和日志记录息息相关
appstting.json文件节点
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
具体在日志章节描述
ConfigureWebHostBuilder WebHost 属性
继承于IWebHostBuilder接口,目的是复用接口,继承于ISupportsStartUp接口,由于6.0使用的是最小托管模型,所以传统的使用Startup.cs文件来配置服务和注册中间件已经不支持了,继承此接口的是原因是:
微软原话“但是我们希望用户在采用这种编程方式时得到显式的提醒,所以依然让它实现该接口,并在实现的方法中抛出NotImplementedException类型的异常。”
WebApplication构造函数中,通过传进来的一些构造参数初始化一个实例赋值给该属性;
构造函数,通过WebHostContext,Services成员属性、Configure成员属性来初始化
ConfigureWebHostBuilder类源码
public class ConfigureWebHostBuilder : IWebHostBuilder, ISupportsStartup
{
private readonly WebHostBuilderContext _builderContext;
private readonly IServiceCollection _services;
private readonly ConfigurationManager _configuration;
public ConfigureWebHostBuilder(WebHostBuilderContext builderContext, ConfigurationManager configuration, IServiceCollection services)
{
_builderContext = builderContext;
_services = services;
_configuration = configuration;
}
}
ConfigureHostBuilder Host 属性
继承于IHostBuilder接口,目的是复用接口,他更多的用来配置主机服务
WebApplication构造函数中,通过bootStrapBuilder收集到的服务,传进来的一些构造参数初始化一个实例赋值给他;
构造函数,通过HostBuilderContext ,Services成员属性、Configure成员属性来初始化
Services成员属性会直接赋值ConfigureHostBuilder的_services属性
Configure成员属性相关Host的配置会被存放在ConfigureHostBuilder内部类的一个_configureActions字段暂时存起来
ConfigureHostBuilder类源码
public class ConfigureHostBuilder : IHostBuilder
{
private readonly ConfigurationManager _configuration;
private readonly IServiceCollection _services;
private readonly HostBuilderContext _context;
private readonly List<Action<IHostBuilder>> _configureActions = new();
internal ConfigureHostBuilder(HostBuilderContext context, ConfigurationManager configuration, IServiceCollection services)
{
_configuration = configuration;
_services = services;
_context = context;
}
}
BootstrapHostBuilder类:
BootstrapHostBuilder继承于IHostBuilder,目的是为了构建和初始化IHostBuilder对象
这个它的作用是收集初始化IHostBuilder对象提供的设置并将它们分别应用到指定的IServiceCollection、ConfigurationManager和IHostBuilder对象上,在构造函数中会调用他的Apply()方法。
2. Build()方法:
简单来说就是将对于WebApplicationBuilder的一切配置转移到IHostBuilder对象上,然后得到一个WebApplication对象
注意!!!!!
WebApplication一旦创建,环境变量、配置都不允许再次改变(虽然我们也用不着,但是知道就好)
这个方法作用:
把WebApplication的Configure成员属性和Services成员属性转移到HostBuilder上面
// 获取WebApplication对象,用于配置 HTTP 管道和路由的 Web 应用程序
public WebApplication Build()
{
// 在此处连接主机配置。我们不会尝试保留配置,在此处获取本身,因为我们不支持在创建构建器后更改主机值。
_hostBuilder.ConfigureHostConfiguration(builder =>
{
builder.AddInMemoryCollection(_hostConfigurationValues);
});
// 将ConfigurationManager的配置转移到_hostBuilder
_hostBuilder.ConfigureAppConfiguration(builder =>
{
builder.AddConfiguration(Configuration);
foreach (var kv in ((IConfigurationBuilder)Configuration).Properties)
{
builder.Properties[kv.Key] = kv.Value;
}
});
var chainedConfigSource = new TrackingChainedConfigurationSource(Configuration);
_hostBuilder.ConfigureServices((context, services) =>
{
// 简单来说就是把WeApplicationBuilder中的IServiceCollection属性添加到泛型主机中
foreach (var s in _services)
{
services.Add(s);
}
// 把服务列表只能关于主机的服务添加到主机中
// 确保添加的任何托管服务在初始托管服务集之后运行。也就是托管服务在web主机启动前运行
foreach (var s in _services.HostedServices)
{
services.Add(s);
}
// 清除主机托管服务列表
_services.HostedServices.Clear();
// 将任何服务添加到用户可见的服务集合中,
_services.InnerCollection = services;
// 保留主机中的配置
var beforeChainedConfig = true;
var hostBuilderProviders = ((IConfigurationRoot)context.Configuration).Providers;
if (!hostBuilderProviders.Contains(chainedConfigSource.BuiltProvider))
{
((IConfigurationBuilder)Configuration).Sources.Clear();
beforeChainedConfig = false;
}
// 使配置管理器与最终_hostBuilder的配置匹配。
foreach (var provider in hostBuilderProviders)
{
if (ReferenceEquals(provider, chainedConfigSource.BuiltProvider))
{
beforeChainedConfig = false;
}
else
{
IConfigurationBuilder configBuilder = beforeChainedConfig ? _hostConfigurationManager : Configuration;
configBuilder.Add(new ConfigurationProviderSource(provider));
}
}
});
// 在最终主机构建器上运行其他回调
Host.RunDeferredCallbacks(_hostBuilder);
// 构建应用
_builtApplication = new WebApplication(_hostBuilder.Build());
// 将服务集合标记为只读以防止将来修改
_services.IsReadOnly = true;
// 解析_hostBuilder的配置和构建器。
_ = _builtApplication.Services.GetService<IEnumerable<IConfiguration>>();
return _builtApplication;
}
WebApplication类:
应用类
继承4个接口
IHost接口:所以这就是上文当中说到为什么WebApplicationBuilder需要一个IConfigureHostBuilder属性的原因;IApplicationBuilder:提供配置应用程序请求管道机制的类,所以我们的中间件可以直接注册到WebApplication;IEndpointRouteBuilder:定义应用程序中路由生成器的协定。 路由生成器指定应用程序的路由。所以我们无需显示调用UseEndpoint、UseRouting这2个中间件,这个在6.0的更新中也提到了;IAsyncDisposable:提供异步释放的接口;
6个重要属性
IServiceProvider:应用程序的已配置服务。提供在程序运行期间解析的服务类型,简称依赖注入容器;IConfiguration:应用程序的已配置,可以获取已经配置好的配置源;IWebHostEnvironment: 托管环境信息;IHostApplicationLifetime:允许通知使用者应用程序生存期事件;ILogger:日志服务;ICollection<string>:HTTP 服务器绑定到的 URL 列表。(IServerAddressesFeature:启动地址);
WebApplication类源码
public sealed class WebApplication : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
{
public IServiceProvider Services => _host.Services;
public IConfiguration Configuration => _host.Services.GetRequiredService<IConfiguration>();
public IWebHostEnvironment Environment => _host.Services.GetRequiredService<IWebHostEnvironment>();
public IHostApplicationLifetime Lifetime => _host.Services.GetRequiredService<IHostApplicationLifetime>();
public ILogger Logger { get; }
public ICollection<string> Urls => ServerFeatures.Get<IServerAddressesFeature>()?.Addresses ??
throw new InvalidOperationException($"{nameof(IServerAddressesFeature)} could not be found.");
}
拓展方法
就是各种系统定义好的中间件服务。
3. Run()方法 :
WebApplication.BuildRequestDelegate()方法
前面调用ConfigureWebHostDefaults()扩展方法提供的委托会将使用BuildRequestDelegate()方法注册的中间件管道,作为请求处理器,至此一个WebApplication对象完成。
应用--WebApplication的更多相关文章
- [原] VS新添加WebApplication项目,无法运行,请求帮助,问题如何解决
最近在WIN10 Pro上安装运行VS2012(安装顺利),新建WebApplication项目,无法运行,编译都无法通过,但都是警告. 症状: 1.新建项目无法编译: 2.新建后,默认引用全部感叹号 ...
- error MSB4019: 未找到导入的项目“C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets”
error MSB4019: 未找到导入的项目“C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\ ...
- WebSite和WebApplication的区别
1. WebApplication(Web应用程序)和WebSite(网站)的区别:WebSite是为了兼容从ASP转过来的开发人员的习惯而存在的,用起来简单,例如:不需要创建命名控件.C#代码修改以 ...
- Visual Stadio 2015创建WebApplication应用和运行赏析
专题图: 1,创建一个WebApplication应用 2,项目结构和布局 3,运行项目 作者:ylbtech出处:http://ylbtech.cnblogs.com/本文版权归作者和博客园共有, ...
- web项目的两个创建形式website和webapplication(转)
前言 在利用VS2010创建web项目的时候,会有两个选择.可以选择直接创建website网站,还可以选择使用 webapplication应用程序.刚刚接触web开发,看到这两个就疑惑了,既然是都可 ...
- web项目的两个创建形式website和webapplication
前言 在利用VS2010创建web项目的时候,会有两个选择.可以选择直接创建website网站,还可以选择使用 webapplication应用程序.刚刚接触web开发,看到这两个就疑惑了,既然是都可 ...
- WebApplication和WebSite的区别
不同点 1. 创建方式不同 一个是FILE->NEW->PROJECT->ASP.NET WEB APPLICATION 另外一个是 FILE->NEW->WEBSITE ...
- 【ASP.NET】website转webapplication
*以下操作都以VS2013为参考: #新建两种web项目 1.添加webapplication项目: 2.添加website项目: #比较两种web项目新建的webform页面的不同点: 1.文件目录 ...
- WebApplication与WebSite区别
1. WebApplication(Web应用程序)和WebSite(网站)的区别:WebSite是为了兼容从ASP转过来的开发人员的习惯而存在的,用起来简单,例如:不需要创建命名控件.C#代码修改以 ...
- 利用 PowerShell 分析SharePoint WebApplication 体系结构
之前一篇文章<两张图看清SharePoint 2013 Farm 逻辑体系结构>谈到Web Application,Content Database,Site Collection的关系. ...
随机推荐
- Tomcat 9.0.26 高并发场景下DeadLock问题排查与修复
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/-OcCDI4L5GR8vVXSYhXJ7w作者:黄卫兵.陈锦霞 一.Tomcat容器 9.0. ...
- 如何把thinkphp5的项目迁移到阿里云函数计算来应对流量洪峰?
原文链接:https://developer.aliyun.com/article/982746 1. 为什么要迁移到阿里云函数? 我的项目是一个节日礼品领取项目,过节的时候会有短时间的流量洪峰.平时 ...
- CommonJS 和 ES6 Module 究竟有什么区别?
https://juejin.im/post/5e5f10176fb9a07cd443c1e2
- 如何一键私有化部署 Laf ?
太长不看:Laf 上架了 Sealos 的模板市场,通过 Laf 应用模板即可一键部署! Laf 是一个完全开源的项目,除了使用公有云之外,还有大量的用户选择私有化部署 Laf.然而,私有化部署通常伴 ...
- 5分钟教会你如何在生产环境debug代码
前言 有时出现的线上bug在测试环境死活都不能复现,靠review代码猜测bug出现的原因,然后盲改代码直接在线上测试明显不靠谱.这时我们就需要在生产环境中debug代码,快速找到bug的原因,然后将 ...
- Linux vim-go 开发环境搭建
本文介绍 Linux 下 vim-go 的开发环境搭建.主要参考这篇博客进行的配置,其中记录了几个搭建环境时遇到的问题. 1. vim-go 开发环境搭建 1.1 用户隔离 由于使用的是共享宿主机,为 ...
- spring--JDK动态代理的实现原理
JDK 动态代理的实现原理涉及到 Java 的反射机制.它允许在运行时动态创建一个代理类,这个代理类实现了一组接口,并将所有方法调用转发到一个 InvocationHandler 实例.下面是 JDK ...
- 比Nginx更好用的Gateway!
比Nginx更好用的Gateway! Token新开源Gateway,使用yarp实现的一个反向代理,支持界面操作动态添加集群添加路由绑定,并且支持动态添加域名绑定https证书,超强yarp+Fre ...
- 基于html+jquery开发的科学计算器(课程作业)
基于html和jquery开发的科学计算器,该科学计算器可进行乘方.开方.指数.对数.三角函数.统计等方面的运算,又称函数计算器. 科学型带有所有普通的函数,所有的函数都分布在键盘上以致于你可以不用通 ...
- springboot启动流程 (2) 组件扫描
SpringBoot的组件扫描是基于Spring @ComponentScan注解实现的,该注解使用basePackages和basePackageClasses配置扫描的包,如果未配置这两个参数,S ...