这几天利用空闲时间,我将ASP.NET反编译后的源代码并结合园子里几位大侠的写的文章认真的看了一遍,收获颇丰,同时也摘要了一些学习内容,存入了该篇文章:《ASP.NET运行机制图解》,在对整个ASP.NET的运行机制有所了解后,我又对MVC的运行机制也进行了源码分析,因为网上已经有很多的关于MVC实现原理的介绍,所以我这里不再重复讨论这方面的内容,而主要讲解一下Controller的的创建、执行以及如何实现依赖注入,注入的步骤是什么?

首先,我们来看一下正常的Controller的的创建与执行顺序:

大家都应该知道,用于处理ASP.NET请求是由实现了IHttpHandler的对象来进行处理的,我们所常见的Handler包括但不限于:Page,MvcHandler等

如下是MvcHandler类中的方法及执行步骤说明:

处理入口方法:异步-->BeginProcessRequest,同步-->  ProcessRequest,源代码如下:

        IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
return this.BeginProcessRequest(context, cb, extraData);
} void IHttpHandler.ProcessRequest(HttpContext httpContext)
{
this.ProcessRequest(httpContext);
}

注意这两个方法是显示实现IHttpHandler的同名方法的,不能直接调用,必需转换成IHttpHandler类型后才能调用,调用转到如下方法:

        protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
{
HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
return this.BeginProcessRequest(httpContext2, callback, state);
} protected virtual void ProcessRequest(HttpContext httpContext)
{
HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
this.ProcessRequest(httpContext2);
}

当然这两个方法均又分别调动了各自的重载方法,在重载方法中都调用了ProcessRequestInit,源代码如下:

        private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
if (ValidationUtility.IsValidationEnabled(HttpContext.Current) == true)
{
ValidationUtility.EnableDynamicValidation(HttpContext.Current);
}
this.AddVersionHeader(httpContext);
this.RemoveOptionalRoutingParameters();
string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
factory = this.ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(this.RequestContext, requiredString);
if (controller == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[]
{
factory.GetType(),
requiredString
}));
}
}

红色标明的就是创建Controller的地方,创建完后就开始执行Controller,异步与同步方法的执行有所不同,源代码如下:

        protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
{
return SecurityUtil.ProcessInApplicationTrust<IAsyncResult>(delegate
{
IController controller;
IControllerFactory factory;
this.ProcessRequestInit(httpContext, out controller, out factory);
IAsyncController asyncController = controller as IAsyncController;
if (asyncController != null)
{
BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState)
{
IAsyncResult result;
try
{
result = asyncController.BeginExecute(this.RequestContext, asyncCallback, asyncState);
}
catch
{
factory.ReleaseController(asyncController);
throw;
}
return result;
};
EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult)
{
try
{
asyncController.EndExecute(asyncResult);
}
finally
{
factory.ReleaseController(asyncController);
}
};
SynchronizationContext synchronizationContext = SynchronizationContextUtil.GetSynchronizationContext();
AsyncCallback callback2 = AsyncUtil.WrapCallbackForSynchronizedExecution(callback, synchronizationContext);
return AsyncResultWrapper.Begin(callback2, state, beginDelegate, endDelegate, MvcHandler._processRequestTag);
}
Action action = delegate
{
try
{
controller.Execute(this.RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
};
return AsyncResultWrapper.BeginSynchronous(callback, state, action, MvcHandler._processRequestTag);
});
} protected internal virtual void EndProcessRequest(IAsyncResult asyncResult)
{
SecurityUtil.ProcessInApplicationTrust(delegate
{
AsyncResultWrapper.End(asyncResult, MvcHandler._processRequestTag);
});
} protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
SecurityUtil.ProcessInApplicationTrust(delegate
{
IController controller;
IControllerFactory controllerFactory;
this.ProcessRequestInit(httpContext, out controller, out controllerFactory);
try
{
controller.Execute(this.RequestContext);
}
finally
{
controllerFactory.ReleaseController(controller);
}
});
}

通过上述代码,我们知道Controller执行步骤是:异步(BeginExecute-->EndExecute-->ReleaseController),同步(Execute-->  ReleaseController)

我们知道了Controller的创建与执行原理,就可以针对这些代码规则来扩展我们自定义的一些实现代码,比如我们本文要讲的:通过IOC实现Controller依赖注入。

通过上面源代码的分析,我们知道,Controller是由ControllerFactory来创建的,而ControllerFactory又是由ControllerBuilder,也就是我们只要能够改变ControllerBuilder.GetControllerFactory返回的值,也就改变了ControllerFactory,这样就给自定义创建Controller提供可能,我们先来看一下,ControllerBuilder.GetControllerFactory方法的定义:

public IControllerFactory GetControllerFactory()
{
return this._serviceResolver.Current;
}

方法很简单,直接通过IResolver<IControllerFactory>.Current返回实现了IControllerFactory对象,而对于方法中的_serviceResolver是在构造函数中实例化的,源代码如下:

        internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
{
IResolver<IControllerFactory> arg_6A_1 = serviceResolver;
if (serviceResolver == null)
{
arg_6A_1 = new SingleServiceResolver<IControllerFactory>(() => this._factoryThunk(), new DefaultControllerFactory
{
ControllerBuilder = this
}, "ControllerBuilder.GetControllerFactory"
);
}
this._serviceResolver = arg_6A_1;
}

通过构造函数,可以看出_serviceResolver是由SingleServiceResolver<IControllerFactory>实例化得来的,那么结合上面的this._serviceResolver.Current,就可以知道其实就是访问SingleServiceResolver<IControllerFactory>的Current属性来获得IControllerFactory对象,源代码如下:

        public TService Current
{
get
{
if (this._resolverThunk != null)
{
lock (this._currentValueThunk)
{
if (this._resolverThunk != null)
{
this._currentValueFromResolver = this._resolverThunk().GetService<TService>();
this._resolverThunk = null;
if (this._currentValueFromResolver != null && this._currentValueThunk() != null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.SingleServiceResolver_CannotRegisterTwoInstances, new object[]
{
typeof(TService).Name.ToString(),
this._callerMethodName
}));
}
}
}
}
TService arg_D2_0;
if ((arg_D2_0 = this._currentValueFromResolver) == null && (arg_D2_0 = this._currentValueThunk()) == null)
{
arg_D2_0 = this._defaultValue;
}
return arg_D2_0;
}
}

SingleServiceResolver构造函数如下:

        public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName)
{
if (currentValueThunk == null)
{
throw new ArgumentNullException("currentValueThunk");
}
if (defaultValue == null)
{
throw new ArgumentNullException("defaultValue");
}
this._resolverThunk = (() => DependencyResolver.Current);
this._currentValueThunk = currentValueThunk;
this._defaultValue = defaultValue;
this._callerMethodName =
callerMethodName;
}

这里我们结合ControllerBuilder的构造函数及SingleServiceResolver构造函数得知在Current属性的逻辑代码中if (this._currentValueFromResolver != null && this._currentValueThunk() != null)是不成立的,因为this._currentValueThunk = currentValueThunk;而currentValueThunk又是ControllerBuilder中默认的值: Func<IControllerFactory> _factoryThunk = () => null;所以就会走到arg_D2_0 = this._defaultValue,而_defaultValue又是等于ControllerBuilder构造函数中传来的DefaultControllerFactory,所以最终返回了DefaultControllerFactory,如果需要实现自定义的ControllerFactory并且能够被ControllerBuilder.GetControllerFactory返回,我们只需要自定义实现IControllerFactory的类,如:CustomControllerFactory,以及使用ControllerBuilder.SetControllerFactory方法来使_factoryThunk 的值等于()=>CustomControllerFactory即可,实现的代码如下:

    public class CustomControllerFactory : DefaultControllerFactory
{
private UnityContainer iocContainer; public CustomControllerFactory()
{
iocContainer = new UnityContainer();
AddBindings();
} protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
IController controller=null;
if (controllerType != null)
{
controller = (IController)iocContainer.Resolve(controllerType);
}
return controller;
} private void AddBindings()
{
iocContainer.RegisterType<IUserService, UserService>();
} }

我这里采用Unity容器,并重写了GetControllerInstance方法,如下代码是实现注入CustomControllerFactory到ControllerBuilder:

        protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
}

这样我们就实现了返回自己定义的CustomControllerFactory,并在CustomControllerFactory通过IOC容器来实现自己所需要的Controller。

以上虽然通过自定义ControllerFactory实现了IOC的注入,但我仍然觉得有些烦锁,且存在不安全性,因为自己实现的CustomControllerFactory是可以去重写、覆盖改变DefaultControllerFactory中的相应的属性方法,如果自己写的代码存在漏洞或不健全,则会造成无法预料的后果,因此一般不建议直接这样做,而应该采用风险更小的其它方法来实现,那是什么方法呢?请继续往下看。

通过分析源码得知,默认情况下,Controller是由DefaultControllerFactory.GetControllerInstance得来的,那我们先来看看这个方法定义:

        protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(, string.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_NoControllerFound, new object[]
{
requestContext.HttpContext.Request.Path
}));
}
if (!typeof(IController).IsAssignableFrom(controllerType))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase, new object[]
{
controllerType
}), "controllerType");
}
return this.ControllerActivator.Create(requestContext, controllerType);
}

注意红色标注的地方,这里是通过ControllerActivator属性对象来创建的,ControllerActivator属性定义如下:

        private IControllerActivator ControllerActivator
{
get
{
if (this._controllerActivator != null)
{
return this._controllerActivator;
}
this._controllerActivator = this._activatorResolver.Current;
return this._controllerActivator;
}
}

由此可知,ControllerActivator属性又是(私有字段:_activatorResolver) IResolver<IControllerActivator>.Current得来的,那么这个_activatorResolver又是如何得来的呢?通过上下源码的分析,得知,DefaultControllerFactory是在ControllerBuilder中构造的,那么我看一下DefaultControllerFactory的构造函数:

        public DefaultControllerFactory() : this(null, null, null)
{
} internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)
{
if (controllerActivator != null)
{
this._controllerActivator = controllerActivator;
return;
}
IResolver<IControllerActivator> arg_44_1 = activatorResolver;
if (activatorResolver == null)
{
arg_44_1 = new SingleServiceResolver<IControllerActivator>(() => null, new DefaultControllerFactory.DefaultControllerActivator(dependencyResolver), "DefaultControllerFactory contstructor");
}
this._activatorResolver = arg_44_1;
}

ControllerBuilder的构造函数中是采用的无参构造函数,而无参构造函数最终均会调用带有三个参数的构造函数,在这个函数中,我标出了重点需要关注的地方,有没有发现眼熟的地方,对的SingleServiceResolver又出现了,只不过泛型参数不同而已,我在上面分析时用绿色标记出了重要的地方:构造函数中的this._resolverThunk = (() => DependencyResolver.Current);以及Current属性中的this._currentValueFromResolver = this._resolverThunk().GetService<TService>();认真分析得知, DependencyResolver.Current是一个静态属性,看一下该属性的定义:

public static IDependencyResolver Current
{
get
{
return DependencyResolver._instance.InnerCurrent;
}
}

该属性的值来源于一个私有字段,这个字段是静态的并默认就实例化为DependencyResolver:

private static DependencyResolver _instance = new DependencyResolver();

得出结论DependencyResolver.Current调用DependencyResolver.InnerCurrent属性,而该属性又直接返回_current字段的值,代码如下:

private IDependencyResolver _current = new DependencyResolver.DefaultDependencyResolver();

        public IDependencyResolver InnerCurrent
{
get
{
return this._current;
}
}

_current字段默认是实例化DependencyResolver.DefaultDependencyResolver,而该类型是一个内部类:

        private class DefaultDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
object result;
try
{
result = Activator.CreateInstance(serviceType);
}
catch
{
result = null;
}
return result;
} public IEnumerable<object> GetServices(Type serviceType)
{
return Enumerable.Empty<object>();
}
}

这个类没有什么复杂的方法及属性,只是实现了IDependencyResolver接口的两个方法,分别是  GetService、  GetServices(该方法返回空集合,即无用)。

到此一切就都明了了,如果说想要实现通过DefaultControllerFactory.GetControllerInstance来返回我们IOC注入后的Controller,只需要改变  SingleServiceResolver.Current属性返回值,而改变该值则需要改变该类的_resolverThunk字段值,而_resolverThunk的值又来自构造函数中的如下语句:

this._resolverThunk = (() => DependencyResolver.Current);

最终我们只要改变DependencyResolver.Current属性返回值即可,而该值通过上面的分析知道是来自DependencyResolver的字段:_current,所以只要改变这个字段的值,就能改变最终返回Controller实例对象。那如何改变这个私有字段呢?不急,通过源码代码得知,DependencyResolver提供了SetResolver多个静态重载方法,我们只需要将实现了IDependencyResolver接口实例对象传入进去,就可以改变_current字段,从而最终实现我们想要的结果。

        public static void SetResolver(IDependencyResolver resolver)
{
DependencyResolver._instance.InnerSetResolver(resolver);
} public static void SetResolver(object commonServiceLocator)
{
DependencyResolver._instance.InnerSetResolver(commonServiceLocator);
} public static void SetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
{
DependencyResolver._instance.InnerSetResolver(getService, getServices);
} public void InnerSetResolver(IDependencyResolver resolver)
{
if (resolver == null)
{
throw new ArgumentNullException("resolver");
}
this._current = resolver;
} public void InnerSetResolver(object commonServiceLocator)
{
if (commonServiceLocator == null)
{
throw new ArgumentNullException("commonServiceLocator");
}
Type type = commonServiceLocator.GetType();
MethodInfo method = type.GetMethod("GetInstance", new Type[]
{
typeof(Type)
});
MethodInfo method2 = type.GetMethod("GetAllInstances", new Type[]
{
typeof(Type)
});
if (method == null || method.ReturnType != typeof(object) || method2 == null || method2.ReturnType != typeof(IEnumerable<object>))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, MvcResources.DependencyResolver_DoesNotImplementICommonServiceLocator, new object[]
{
type.FullName
}), "commonServiceLocator");
}
Func<Type, object> getService = (Func<Type, object>)Delegate.CreateDelegate(typeof(Func<Type, object>), commonServiceLocator, method);
Func<Type, IEnumerable<object>> getServices = (Func<Type, IEnumerable<object>>)Delegate.CreateDelegate(typeof(Func<Type, IEnumerable<object>>), commonServiceLocator, method2);
this._current = new DependencyResolver.DelegateBasedDependencyResolver(getService, getServices);
} public void InnerSetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices)
{
if (getService == null)
{
throw new ArgumentNullException("getService");
}
if (getServices == null)
{
throw new ArgumentNullException("getServices");
}
this._current = new DependencyResolver.DelegateBasedDependencyResolver(getService, getServices);
}

自定义实现IDependencyResolver接口的类型(采用Unity需要注意,使用常规的解析方法会存在错误,可参见DUDU的这篇文章《Unity+MVC:实现IDependencyResolver接口需要注意的地方》,我这里直接借鉴Unity.MVC3里面定义的类),如:

    public class CustomDependencyResolver:IDependencyResolver
{
private const string HttpContextKey = "perRequestContainer"; private readonly IUnityContainer container; public CustomDependencyResolver()
{
this.container = BuildAndInitContainer();
} public object GetService(Type serviceType)
{
if (typeof(IController).IsAssignableFrom(serviceType))
{
return ChildContainer.Resolve(serviceType);
} return IsRegistered(serviceType) ? ChildContainer.Resolve(serviceType) : null;
} public IEnumerable<object> GetServices(Type serviceType)
{
if (IsRegistered(serviceType))
{
yield return ChildContainer.Resolve(serviceType);
} foreach (var service in ChildContainer.ResolveAll(serviceType))
{
yield return service;
}
} protected IUnityContainer ChildContainer
{
get
{
var childContainer = HttpContext.Current.Items[HttpContextKey] as IUnityContainer; if (childContainer == null)
{
HttpContext.Current.Items[HttpContextKey] = childContainer = container.CreateChildContainer();
} return childContainer;
}
} public static void DisposeOfChildContainer()
{
var childContainer = HttpContext.Current.Items[HttpContextKey] as IUnityContainer; if (childContainer != null)
{
childContainer.Dispose();
}
} private bool IsRegistered(Type typeToCheck)
{
var isRegistered = true; if (typeToCheck.IsInterface || typeToCheck.IsAbstract)
{
isRegistered = ChildContainer.IsRegistered(typeToCheck); if (!isRegistered && typeToCheck.IsGenericType)
{
var openGenericType = typeToCheck.GetGenericTypeDefinition(); isRegistered = ChildContainer.IsRegistered(openGenericType);
}
} return isRegistered;
} private IUnityContainer BuildAndInitContainer()
{
var container = new UnityContainer(); container.RegisterType<IUserService, UserService>();
//这里添加其它类型映射 return container;
}
}

在Global文件的Application_Start方法中添加注入代码,如下:

        protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes); DependencyResolver.SetResolver(new MvcApplication1.Models.CustomDependencyResolver());
}

使用方法很简单,如下是全部代码:

    public interface IUserService
{
bool Login(string userName, string password, out string failureMsg);
} public class UserService : IUserService
{
public bool Login(string userName, string password, out string failureMsg)
{
failureMsg = null;
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
{
failureMsg = "用户名或密码不能为空!";
return false;
} if (userName != "admin" || password != "web.admin")
{
failureMsg = "用户名或密码不正确!";
return false;
} return true;
}
} public class UserController : Controller
{
private readonly IUserService userService; public UserController(IUserService service)
{
userService = service;
} public ActionResult Login()
{
return View();
} [HttpPost]
[ActionName("Login")]
public ActionResult LoginExecute(string username, string password)
{
string msg = null;
if (!userService.Login(username, password,out msg))
{
return Content("<p style='color:red;'>登录失败,原因如下:<br/>"+ msg +"</p>", "text/html", Encoding.UTF8);
}
return Content("<p style='color:green;'>登录成功!</p>", "text/html", Encoding.UTF8);
} }

VIEW视图代码:

@{
ViewBag.Title = "Login";
} <h2>Login</h2> @using(Html.BeginForm())
{
<p>
<span>用户名:</span>
@Html.TextBox("username")
</p>
<p>
<span>密 码:</span>
@Html.Password("password")
</p>
<input type="submit" value="登 录" />
}

最终的效果如下图示:

                        

                        

深入分析MVC中通过IOC实现Controller依赖注入的原理的更多相关文章

  1. AspectCore中的IoC容器和依赖注入

    IOC模式和依赖注入是近年来非常流行的一种模式,相信大家都不陌生了,在Asp.Net Core中提供了依赖注入作为内置的基础设施,如果仍不熟悉依赖注入的读者,可以看看由我们翻译的Asp.Net Cor ...

  2. ASP.NET MVC进阶之路:深入理解依赖注入(DI)和控制反转(IOC)

    0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点.在程序运行过程中,客户 ...

  3. ASP.NET MVC和ASP.NET Core MVC中获取当前URL/Controller/Action (转载)

    ASP.NET MVC 一.获取URL(ASP.NET通用): [1]获取完整url(协议名+域名+虚拟目录名+文件名+参数) string url=Request.Url.ToString(); [ ...

  4. 轻松了解Spring中的控制反转和依赖注入(二)

    紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...

  5. 控制反转(IoC)与依赖注入(DI)

    前言 最近在学习Spring框架,它的核心就是IoC容器.要掌握Spring框架,就必须要理解控制反转的思想以及依赖注入的实现方式.下面,我们将围绕下面几个问题来探讨控制反转与依赖注入的关系以及在Sp ...

  6. IOC容器的依赖注入

    1.依赖注入发生的时间 当Spring IoC容器完成了Bean定义资源的定位.载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入 ...

  7. 控制反转( IoC)和依赖注入(DI)

    控制反转( IoC)和依赖注入(DI) tags: 容器 依赖注入 IOC DI 控制反转 引言:如果你看过一些框架的源码或者手册,像是laravel或者tp5之类的,应该会提到容器,依赖注入,控制反 ...

  8. Spring IOC - 控制反转(依赖注入) - 入门案例 - 获取对象的方式 - 别名标签

    1. IOC - 控制反转(依赖注入) 所谓的IOC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交 由Spring框架来处理,从此在开发过程中不再需要关注对象的创建和生命周 ...

  9. springboot成神之——ioc容器(依赖注入)

    springboot成神之--ioc容器(依赖注入) spring的ioc功能 文件目录结构 lang Chinese English GreetingService MyRepository MyC ...

随机推荐

  1. Apache Marmotta 3.1.0-incubating 发布

    Apache Marmotta 3.1.0-incubating 发布了,Apache Marmotta 项目的目的是提供 Linked Data Platform 的开源实现,可让组织轻松的使用.扩 ...

  2. Linux 学习笔记(一) 入门

    Shell 显示Shell类型 $ps 切换Shell $[Shell 名称]  ex. $tcsh 快捷键 Ctrl + Z:挂起,可用jobs查看到,fg恢复运行 Ctrl + W:删除单词 Ct ...

  3. Java多线程16:线程组

    线程组 可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式,如图所示: 线程组的作用是:可以批量管理线程或线程组对象,有效地对线 ...

  4. Java对象表示方式2:XStream实现对对象的XML化

    上一篇文章讲到了使用Java原生的序列化的方式来表示一个对象.总结一下这种对象表示方式的优缺点: 1.纯粹的Java环境下这种方式可以很好地工作,因为它是Java自带的,也不需要第三方的Jar包的支持 ...

  5. Python黑客编程2 入门demo--zip暴力破解

    Python黑客编程2 入门demo--zip暴力破解 上一篇文章,我们在Kali Linux中搭建了基本的Python开发环境,本篇文章为了拉近Python和大家的距离,我们写一个暴力破解zip包密 ...

  6. DNS拾遗(二)

    MX Record补充 MX记录有优先级的概念,数字越小表示优先级越高.所以一个域可以配置多个不同优先级的MX记录,如果邮件通过第一优先级记录无法递送,则采用第二优先级,以此类推. TXT Recor ...

  7. Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结

    Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结 1.1. 原理,主要使用像素模糊后的差别会变小1 1.2. 具体流程1 1.3. 提升性能 可以使用采样法即可..1 ...

  8. atitit.事件驱动的总结attilax

    atitit.事件驱动的总结attilax Keyboard 基于的的ed 与  mouse 基础的ed Kb  base on focus ....   Mouse base on mouse mo ...

  9. SpringAOP之静态代理

    一.SpringAOP: ⒈AOP:Aspect Oriented Programming 面向切面编程, 实现的是核心业务和非核心业务之间的的分离,让核心类只做核心业务,代理类只做非核心业务.  ⒉ ...

  10. SVN更改登录用户

    如果装了TortoiseSVN: Settings -> Saved Data -> Authentication Data -> clear.即可清除保存的上个用户登录信息:当再次 ...