【Unity--Apwork框架】AOP编程--拦截,用于缓存和异常处理(Unity框架的拦截注入-Interception)
第一步:定义拦截行为:CachingBehavior 和 ExceptionLoggingBehavior
他们都继承接口:IInterceptionBehavior (程序集 Microsoft.Practices.Unity.Interception.dll, v2.1.505.0
命名空间:Microsoft.Practices.Unity.InterceptionExtension)
需要实现连个接口:
public IEnumerable<Type> GetRequiredInterfaces() public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
CachingBehavior.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Keasy5.Infrastructure.Caching;
using Microsoft.Practices.Unity.InterceptionExtension; namespace Keasy5.Infrastructure.InterceptionBehaviors
{
/// <summary>
/// 表示用于方法缓存功能的拦截行为。
/// </summary>
public class CachingBehavior : IInterceptionBehavior
{
#region Private Methods
/// <summary>
/// 根据指定的<see cref="CachingAttribute"/>以及<see cref="IMethodInvocation"/>实例,
/// 获取与某一特定参数值相关的键名。
/// </summary>
/// <param name="cachingAttribute"><see cref="CachingAttribute"/>实例。</param>
/// <param name="input"><see cref="IMethodInvocation"/>实例。</param>
/// <returns>与某一特定参数值相关的键名。
/// <remarks>
/// 例如:<see cref="ICacheProvider.Add"/>
/// </remarks>
/// </returns>
private string GetValueKey(CachingAttribute cachingAttribute, IMethodInvocation input)
{
switch (cachingAttribute.Method)
{
// 如果是Remove,则不存在特定值键名,所有的以该方法名称相关的缓存都需要清除
case CachingMethod.Remove:
return null;
// 如果是Get或者Put,则需要产生一个针对特定参数值的键名
case CachingMethod.Get:
case CachingMethod.Put:
if (input.Arguments != null &&
input.Arguments.Count > )
{
var sb = new StringBuilder();
for (int i = ; i < input.Arguments.Count; i++)
{
sb.Append(input.Arguments[i].ToString());
if (i != input.Arguments.Count - )
sb.Append("_");
}
return sb.ToString();
}
else
return "NULL";
default:
throw new InvalidOperationException("无效的缓存方式。");
}
}
#endregion #region IInterceptionBehavior Members
/// <summary>
/// 获取当前行为需要拦截的对象类型接口。
/// </summary>
/// <returns>所有需要拦截的对象类型接口。</returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} /// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var method = input.MethodBase;
var key = method.Name;
if (method.IsDefined(typeof(CachingAttribute), false))
{
var cachingAttribute = (CachingAttribute)method.GetCustomAttributes(typeof(CachingAttribute), false)[];
var valKey = GetValueKey(cachingAttribute, input);
switch (cachingAttribute.Method)
{
case CachingMethod.Get:
try
{
if (CacheManager.Instance.Exists(key, valKey))
{
var obj = CacheManager.Instance.Get(key, valKey);
var arguments = new object[input.Arguments.Count];
input.Arguments.CopyTo(arguments, );
return new VirtualMethodReturn(input, obj, arguments);
}
else
{
var methodReturn = getNext().Invoke(input, getNext);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Put:
try
{
var methodReturn = getNext().Invoke(input, getNext);
if (CacheManager.Instance.Exists(key))
{
if (cachingAttribute.Force)
{
CacheManager.Instance.Remove(key);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Put(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Remove:
try
{
var removeKeys = cachingAttribute.CorrespondingMethodNames;
foreach (var removeKey in removeKeys)
{
if (CacheManager.Instance.Exists(removeKey))
CacheManager.Instance.Remove(removeKey);
}
var methodReturn = getNext().Invoke(input, getNext);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
default: break;
}
} return getNext().Invoke(input, getNext);
} /// <summary>
/// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行
/// 某些操作。
/// </summary>
public bool WillExecute
{
get { return true; }
} #endregion
}
}
ExceptionLoggingBehavior.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity.InterceptionExtension; namespace Keasy5.Infrastructure.InterceptionBehaviors
{
/// <summary>
/// 表示用于异常日志记录的拦截行为。
/// </summary>
public class ExceptionLoggingBehavior : IInterceptionBehavior
{
#region IInterceptionBehavior Members
/// <summary>
/// 获取当前行为需要拦截的对象类型接口。
/// </summary>
/// <returns>所有需要拦截的对象类型接口。</returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} /// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var methodReturn = getNext().Invoke(input, getNext);
if (methodReturn.Exception != null)
{
Utils.Log(methodReturn.Exception);
}
return methodReturn;
}
/// <summary>
/// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行
/// 某些操作。
/// </summary>
public bool WillExecute
{
get { return true; }
} #endregion
}
}
第二步:添加配置文件,为需要被拦截的类添加拦截行为。
例如如下的配置,是为实现了接口
Keasy5.ServiceContract.IProductService
的类的所以方法添加拦截行为。
web/app.config文件:
<!--BEGIN: Unity-->
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
<container>
<extension type="Interception" />
。。。。。 <register type="Keasy5.ServiceContract.IProductService, Keasy5.ServiceContract" mapTo="Keasy5.Application.Implementation.ProductServiceImpl, Keasy5.Application">
<interceptor type="InterfaceInterceptor" />
<interceptionBehavior type="Keasy5.Infrastructure.InterceptionBehaviors.CachingBehavior, Keasy5.Infrastructure" />
<interceptionBehavior type="Keasy5.Infrastructure.InterceptionBehaviors.ExceptionLoggingBehavior, Keasy5.Infrastructure" />
</register> 。。。。
比如:对于ExceptionLoggingBehavior的拦截行为作用于IProductService接口的实现类的所有方法:
/// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var methodReturn = getNext().Invoke(input, getNext);
if (methodReturn.Exception != null)
{
Utils.Log(methodReturn.Exception);
}
return methodReturn;
}
效果是:如果IProductService接口的实现类的所有方法如果抛出了异常,将调用
Utils.Log(methodReturn.Exception);
将异常信息写入日志系统(这就是我们进行拦截的目的)。
------------------------------------------------
对应缓存CachingBehavior的拦截的补充:
第一:定义特性:CachingAttribute
CachingAttribute.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Keasy5.Infrastructure.Caching
{
/// <summary>
/// 表示由此特性所描述的方法,能够获得来自基础结构层所提供的缓存功能。
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class CachingAttribute : Attribute
{
#region Ctor
/// <summary>
/// 初始化一个新的<c>CachingAttribute</c>类型。
/// </summary>
/// <param name="method">缓存方式。</param>
public CachingAttribute(CachingMethod method)
{
this.Method = method;
}
/// <summary>
/// 初始化一个新的<c>CachingAttribute</c>类型。
/// </summary>
/// <param name="method">缓存方式。</param>
/// <param name="correspondingMethodNames">
/// 与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。
/// </param>
public CachingAttribute(CachingMethod method, params string[] correspondingMethodNames)
: this(method)
{
this.CorrespondingMethodNames = correspondingMethodNames;
}
#endregion #region Public Properties
/// <summary>
/// 获取或设置缓存方式。
/// </summary>
public CachingMethod Method { get; set; }
/// <summary>
/// 获取或设置一个<see cref="Boolean"/>值,该值表示当缓存方式为Put时,是否强制将值写入缓存中。
/// </summary>
public bool Force { get; set; }
/// <summary>
/// 获取或设置与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。
/// </summary>
public string[] CorrespondingMethodNames { get; set; }
#endregion
}
}
第二:将特性CachingAttribute应用于IProductService的接口方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using ByteartRetail.DataObjects;
using Keasy5.DataObject;
using Keasy5.Infrastructure;
using Keasy5.Infrastructure.Caching; namespace Keasy5.ServiceContract
{
/// <summary>
/// 表示与“商品”相关的应用层服务契约。
/// </summary>
[ServiceContract(Namespace = "http://www.ByteartRetail.com")]
public interface IProductService : IApplicationServiceContract
{
#region Methods
/// <summary>
/// 创建商品信息。
/// </summary>
/// <param name="productDataObjects">需要创建的商品信息。</param>
/// <returns>已创建的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsWithPagination",
"GetFeaturedProducts",
"GetProductsForCategoryWithPagination",
"GetProducts",
"GetProductByID")]
ProductDataObjectList CreateProducts(ProductDataObjectList productDataObjects);
/// <summary>
/// 创建商品分类。
/// </summary>
/// <param name="categoryDataObjects">需要创建的商品分类。</param>
/// <returns>已创建的商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetCategories")]
CategoryDataObjectList CreateCategories(CategoryDataObjectList categoryDataObjects);
/// <summary>
/// 更新商品信息。
/// </summary>
/// <param name="productDataObjects">需要更新的商品信息。</param>
/// <returns>已更新的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsWithPagination",
"GetFeaturedProducts",
"GetProductsForCategoryWithPagination",
"GetProducts", "GetProductByID")]
ProductDataObjectList UpdateProducts(ProductDataObjectList productDataObjects);
/// <summary>
/// 更新商品分类。
/// </summary>
/// <param name="categoryDataObjects">需要更新的商品分类。</param>
/// <returns>已更新的商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetCategories", "GetCategoryByID")]
CategoryDataObjectList UpdateCategories(CategoryDataObjectList categoryDataObjects);
/// <summary>
/// 删除商品信息。
/// </summary>
/// <param name="productIDs">需要删除的商品信息的ID值。</param>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsWithPagination",
"GetFeaturedProducts",
"GetProductsForCategoryWithPagination",
"GetProducts", "GetProductByID")]
void DeleteProducts(IDList productIDs);
/// <summary>
/// 删除商品分类。
/// </summary>
/// <param name="categoryIDs">需要删除的商品分类的ID值。</param>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetCategories", "GetCategoryByID")]
void DeleteCategories(IDList categoryIDs);
/// <summary>
/// 设置商品分类。
/// </summary>
/// <param name="productID">需要进行分类的商品ID值。</param>
/// <param name="categoryID">商品分类ID值。</param>
/// <returns>带有商品分类信息的对象。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsForCategoryWithPagination")]
CategorizationDataObject CategorizeProduct(Guid productID, Guid categoryID);
/// <summary>
/// 取消商品分类。
/// </summary>
/// <param name="productID">需要取消分类的商品ID值。</param>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsForCategoryWithPagination")]
void UncategorizeProduct(Guid productID);
/// <summary>
/// 根据指定的ID值获取商品分类。
/// </summary>
/// <param name="id">商品分类ID值。</param>
/// <param name="spec">查询方式。</param>
/// <returns>商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
CategoryDataObject GetCategoryByID(Guid id, QuerySpec spec);
/// <summary>
/// 获取所有的商品分类。
/// </summary>
/// <param name="spec">查询方式。</param>
/// <returns>所有的商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
CategoryDataObjectList GetCategories(QuerySpec spec);
/// <summary>
/// 根据指定的ID值获取商品信息。
/// </summary>
/// <param name="id">商品信息ID值。</param>
/// <param name="spec">查询方式。</param>
/// <returns>商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObject GetProductByID(Guid id, QuerySpec spec);
/// <summary>
/// 获取所有的商品信息。
/// </summary>
/// <param name="spec">查询方式。</param>
/// <returns>商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectList GetProducts(QuerySpec spec);
/// <summary>
/// 以分页的方式获取所有商品信息。
/// </summary>
/// <param name="pagination">带有分页参数信息的对象。</param>
/// <returns>经过分页的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectListWithPagination GetProductsWithPagination(Pagination pagination);
/// <summary>
/// 根据指定的商品分类ID值,获取该分类下所有的商品信息。
/// </summary>
/// <param name="categoryID">商品分类ID值。</param>
/// <returns>所有的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectList GetProductsForCategory(Guid categoryID);
/// <summary>
/// 根据指定的商品分类ID值,以分页的方式获取该分类下所有的商品信息。
/// </summary>
/// <param name="categoryID">商品分类ID值。</param>
/// <param name="pagination">带有分页参数信息的对象。</param>
/// <returns>所有的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectListWithPagination GetProductsForCategoryWithPagination(Guid categoryID, Pagination pagination);
/// <summary>
/// 获取所有的特色商品信息。
/// </summary>
/// <param name="count">需要获取的特色商品信息的个数。</param>
/// <returns>特色商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectList GetFeaturedProducts(int count);
#endregion
}
}
第三:拦截IProductService接口的实现类的所有方法的所有方法,
并通过CachingAttribute特性进行方法 的筛选,
还进一步根据CachingAttribute的属性值进行一步的处理:
CachingBehavior .cs
/// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var method = input.MethodBase;
var key = method.Name;
if (method.IsDefined(typeof(CachingAttribute), false))
{
var cachingAttribute = (CachingAttribute)method.GetCustomAttributes(typeof(CachingAttribute), false)[];
var valKey = GetValueKey(cachingAttribute, input);
switch (cachingAttribute.Method)
{
case CachingMethod.Get:
try
{
if (CacheManager.Instance.Exists(key, valKey))
{
var obj = CacheManager.Instance.Get(key, valKey);
var arguments = new object[input.Arguments.Count];
input.Arguments.CopyTo(arguments, );
return new VirtualMethodReturn(input, obj, arguments);
}
else
{
var methodReturn = getNext().Invoke(input, getNext);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Put:
try
{
var methodReturn = getNext().Invoke(input, getNext);
if (CacheManager.Instance.Exists(key))
{
if (cachingAttribute.Force)
{
CacheManager.Instance.Remove(key);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Put(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Remove:
try
{
var removeKeys = cachingAttribute.CorrespondingMethodNames;
foreach (var removeKey in removeKeys)
{
if (CacheManager.Instance.Exists(removeKey))
CacheManager.Instance.Remove(removeKey);
}
var methodReturn = getNext().Invoke(input, getNext);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
default: break;
}
} return getNext().Invoke(input, getNext);
}
--------------------------------
unity服务定位器:ServiceLocator
ServiceLocator.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration; namespace Keasy5.Infrastructure
{
/// <summary>
/// Represents the Service Locator.
/// </summary>
public sealed class ServiceLocator : IServiceProvider
{
#region Private Fields
private readonly IUnityContainer container;
#endregion #region Private Static Fields
private static readonly ServiceLocator instance = new ServiceLocator();
#endregion #region Ctor
/// <summary>
/// Initializes a new instance of <c>ServiceLocator</c> class.
/// </summary>
private ServiceLocator()
{
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
container = new UnityContainer();
section.Configure(container);
}
#endregion #region Public Static Properties
/// <summary>
/// Gets the singleton instance of the <c>ServiceLocator</c> class.
/// </summary>
public static ServiceLocator Instance
{
get { return instance; }
}
#endregion #region Private Methods
private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments)
{
List<ParameterOverride> overrides = new List<ParameterOverride>();
Type argumentsType = overridedArguments.GetType();
argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToList()
.ForEach(property =>
{
var propertyValue = property.GetValue(overridedArguments, null);
var propertyName = property.Name;
overrides.Add(new ParameterOverride(propertyName, propertyValue));
});
return overrides;
}
#endregion #region Public Methods
/// <summary>
/// Gets the service instance with the given type.
/// </summary>
/// <typeparam name="T">The type of the service.</typeparam>
/// <returns>The service instance.</returns>
public T GetService<T>()
{
return container.Resolve<T>();
} public IEnumerable<T> ResolveAll<T>()
{
return container.ResolveAll<T>();
}
/// <summary>
/// Gets the service instance with the given type by using the overrided arguments.
/// </summary>
/// <typeparam name="T">The type of the service.</typeparam>
/// <param name="overridedArguments">The overrided arguments.</param>
/// <returns>The service instance.</returns>
public T GetService<T>(object overridedArguments)
{
var overrides = GetParameterOverrides(overridedArguments);
return container.Resolve<T>(overrides.ToArray());
}
/// <summary>
/// Gets the service instance with the given type by using the overrided arguments.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="overridedArguments">The overrided arguments.</param>
/// <returns>The service instance.</returns>
public object GetService(Type serviceType, object overridedArguments)
{
var overrides = GetParameterOverrides(overridedArguments);
return container.Resolve(serviceType, overrides.ToArray());
}
#endregion #region IServiceProvider Members
/// <summary>
/// Gets the service instance with the given type.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <returns>The service instance.</returns>
public object GetService(Type serviceType)
{
return container.Resolve(serviceType);
} #endregion
}
}
【Unity--Apwork框架】AOP编程--拦截,用于缓存和异常处理(Unity框架的拦截注入-Interception)的更多相关文章
- Spring框架--AOP编程
2 手动实现AOP编程 AOP 面向切面的编程, AOP可以实现"业务代码"与"关注点代码"分离 // 保存一个用户 public void add(User ...
- Aop编程--注解与xml的实现
一.注解方式 1.首先引入spring对于aop编程的jar支持包,spring框架没有的包请自行在网上下载. aopalliance-alpha1.jar aspectjrt.jar aspectj ...
- 聊聊在AOP模式下的缓存方案
面向方法的数据集缓存 使用了autofac做为ioc容器,使用Autofac.Extras.DynamicProxy2作为方法拦截器,缓存面向方法,直接在方法上添加CachingAttribute特性 ...
- 我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器
回到目录 AOP面向切面的编程,也称面向方面的编程,我更青睐于前面的叫法,将一个大系统切成多个独立的部分,而这个独立的部分又可以方便的插拔在其它领域的系统之中,这种编程的方式我们叫它面向切面,而这些独 ...
- 03-spring框架—— AOP 面向切面编程
3.1 动态代理 动态代理是指,程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理生成工具(不是真实定义的类)在程序运行时由 JVM 根据反射等机制动态生成的.代理对象与目标 ...
- Unity容器实现AOP面向切面编程
为什么要有AOP 需求总是变化的,比如经常会对一些方法后期增加日志.异常处理.权限.缓存.事务的处理,遇到这种情况我们往往只能修改类. 为了应对变化,我们常常使用设计模式解决,但是也有其局限性:设计模 ...
- struts2.1笔记03:AOP编程和拦截器概念的简介
1.AOP编程 AOP编程,也叫面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容.利用A ...
- 使用Memcached、Spring AOP构建数据库前端缓存框架
数据库访问可能是很多网站的瓶颈.动不动就连接池耗尽.内存溢出等.前面已经讲到如果我们的网站是一个分布式的大型站点,那么使用 memcached实现数据库的前端缓存是个很不错的选择:但如果网站本身足够小 ...
- Spring框架 AOP面向切面编程(转)
一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...
随机推荐
- 后台获取ajax发送过来的值
user.CityId = int.Parse(HttpContext.Request[ "bindArea"]); 以上为获取方法:
- 2015-0306—DataLList
DataList具有repeater的所有功能,不同的是DataList自动将模板绘制成为一个表格,每一行数据都绘制成<tr>. 一.SQL的准备工作: 按照以下代码创建: create ...
- 使用单用户模式破解Linux密码
使用单用户模式破解Linux密码 特别说明:在实际工作应用中,安装Linux操作系统必须设置装载口令,否则很容易被破解. 1.使用reboot指令重启Linux操作系统 2.在进入操作系统数秒时,单击 ...
- [Guava源码分析]Ordering:排序
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3876466.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- UITableView学习笔记
//非原创 看TableView的资料其实已经蛮久了,一直想写点儿东西,却总是因为各种原因拖延,今天晚上有时间静下心来记录一些最近学习的TableView的知识.下面进入正题,UITableView堪 ...
- 去除wordpress由代发
在服务器上安装好wordpress后,通过程序发送邮件却显示...由<www@hostname>代发,解决办法很简单:进入程序文件夹wp-includes修改pluggable.php文件 ...
- PHP时间戳
strtotime strtotime("Today"); #今天凌晨0点的时间戳 strtotime('now'); #当前时间的时间戳 strtotime ( &quo ...
- Javascript this 解析
Javascript中,this是一个非常有用的关键字, this是在运行时基于函数的运行环境绑定的,但是,如果使用的时候不注意,很容易就出错了. ECMAScript Standard对this的定 ...
- C#函数运行超时则终止执行(任意参数类型及参数个数通用版)
/// <summary> /// 控制函数执行时间,超时返回null不继续执行 /// 调用方法 /// FuncTimeout.EventNeedRun action = delega ...
- jquery中简易tab切换
<!doctype html> <html> <head> <title>test</title> <meta content=&qu ...