深入分析MVC中通过IOC实现Controller依赖注入的原理
这几天利用空闲时间,我将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依赖注入的原理的更多相关文章
- AspectCore中的IoC容器和依赖注入
IOC模式和依赖注入是近年来非常流行的一种模式,相信大家都不陌生了,在Asp.Net Core中提供了依赖注入作为内置的基础设施,如果仍不熟悉依赖注入的读者,可以看看由我们翻译的Asp.Net Cor ...
- ASP.NET MVC进阶之路:深入理解依赖注入(DI)和控制反转(IOC)
0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点.在程序运行过程中,客户 ...
- ASP.NET MVC和ASP.NET Core MVC中获取当前URL/Controller/Action (转载)
ASP.NET MVC 一.获取URL(ASP.NET通用): [1]获取完整url(协议名+域名+虚拟目录名+文件名+参数) string url=Request.Url.ToString(); [ ...
- 轻松了解Spring中的控制反转和依赖注入(二)
紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...
- 控制反转(IoC)与依赖注入(DI)
前言 最近在学习Spring框架,它的核心就是IoC容器.要掌握Spring框架,就必须要理解控制反转的思想以及依赖注入的实现方式.下面,我们将围绕下面几个问题来探讨控制反转与依赖注入的关系以及在Sp ...
- IOC容器的依赖注入
1.依赖注入发生的时间 当Spring IoC容器完成了Bean定义资源的定位.载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入 ...
- 控制反转( IoC)和依赖注入(DI)
控制反转( IoC)和依赖注入(DI) tags: 容器 依赖注入 IOC DI 控制反转 引言:如果你看过一些框架的源码或者手册,像是laravel或者tp5之类的,应该会提到容器,依赖注入,控制反 ...
- Spring IOC - 控制反转(依赖注入) - 入门案例 - 获取对象的方式 - 别名标签
1. IOC - 控制反转(依赖注入) 所谓的IOC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交 由Spring框架来处理,从此在开发过程中不再需要关注对象的创建和生命周 ...
- springboot成神之——ioc容器(依赖注入)
springboot成神之--ioc容器(依赖注入) spring的ioc功能 文件目录结构 lang Chinese English GreetingService MyRepository MyC ...
随机推荐
- Node.js系列之node.js初探
官方介绍:Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable n ...
- 《你必须知道的.NET》读书笔记一:小OO有大智慧
此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.对象 (1)出生:系统首先会在内存中分配一定的存储空间,然后初始化其附加成员,调用构造函数执行初 ...
- 作业七:团队项目——Alpha版本冲刺阶段-10
部分代码: public void run(){ while (true){ //单击棋子第一下开始闪烁 if (chessManClick){ play[Man].setVisible(false) ...
- 从点击Button到弹出一个MessageBox, 背后发生了什么
思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox. 这个看似简单的行为, 谁能说清楚它是如何运行起来的,背后究 ...
- PMP和PRINCE2
首先先简单介绍一下,PMP是属于美国的项目管理知识体系.PRINCE2是属于英国项目体系. 美国的项目管理知识体系最主要的价值是把世界上所有跟项目管理相关的,不管是知识.最佳实践.工具技术,把它们汇总 ...
- 我心中的核心组件(可插拔的AOP)~第四回 异常拦截器
回到目录 之前说过有关拦截器的文章,第二回 缓存拦截器,事实上,在那讲里说的最多是AOP和缓存组件,对于拦截的概念并没有详细的说明,这一讲,不说AOP,主要说一下拦截器,拦截器Interceptio ...
- Java程序员的日常 —— 注册工厂的妙用
注册工厂是一种很常用的框架书写方法,它适合于快速创建相同类型的对象. 举个栗子 比如一个家具工厂,有沙发.椅子.茶几等等,正常的编程模式是这样的: //创建 class 沙发{} class 椅子{} ...
- Atitit 常用比较复杂的图像滤镜 attilax大总结
Atitit 常用比较复杂的图像滤镜 attilax大总结 像素画滤镜 水彩油画滤镜 素描滤镜 梦幻镜 特点是中央集焦,周围景物朦化微带光晕,使人产生如入梦境的感觉.常用于拍摄婚纱.明星照,也用于其它 ...
- paip.mysql 性能测试by mysqlslap
paip.mysql 性能测试by mysqlslap 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog. ...
- iOS-------应用性能调优的25个建议和技巧
性能对 iOS 应用的开发尤其重要,如果你的应用失去反应或者很慢,失望的用户会把他们的失望写满App Store的评论.然而由于iOS设备的限制,有时搞好性能是一件难事.开发过程中你会有很多需要注意的 ...