【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 ...
随机推荐
- js中的scroll和offset 的使用比较
1.offsetTop :当前对象到其上级层顶部的距离.不能对其进行赋值.设置对象到页面顶部的距离请用style.top属性. 2.offsetLeft :当前对象到其上级层左边的距离. ...
- php下载文件,添加响应头
//下载,添加响应头信息 header('Content-type:application/octet-stream'); header('Content-Disposition:attachment ...
- 开始ubuntu 14.04 的装X模式---终端模式下中文输入,听歌,上irc 开启framebuffer看电影 截图
先上图吧 卡卡的全是在tty1 下的操作,看电影,听歌,截图 ,看图 ,上irc 等等,相当适合在小白面前装屁! 需要安装的软件: 为了能正常显示中文:安装fbterm sudo apt-get i ...
- 转:Android studio Gradle
提高Android Studio中Gradle执行效率 分类: android studio2015-06-26 11:54 2374人阅读 评论(2) 收藏 举报 android studiogra ...
- php生成圆形图片
http://files.cnblogs.com/files/adtuu/circle_image.zip
- Translation002—Package Index(Android包索引)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 看本翻译前请您注意: 本人初学android,可能有的翻译不是非常准确,但本人尽最大努力,不清楚处会做标记,并附 ...
- 解决Handler与Activity同步冲突
这个问题可以由Handler的一个子类HandlerThread来解决. 程序参考自Mars老师的Android课程第一季第十五集. 代码以及注释有所改动,如下: package com.handle ...
- 关于C语言中的typedef
在C语言中定义一个结构体,要最好使用typedef,使用typedef,实际上就是为我们的结构体起了一个新的名字,即定义了一个新的类型,在后面书写自己代码的时候,就可以直接使用自己定义的新的类型第一变 ...
- html 布局;css3+jq 下拉菜单;table分页动态添加行;html5本地存储;简单易用的html框架
简单好用的html框架,预览图见最后: 源码: 1.页面布局使用table: table 嵌套 +iframe 布局: 2.下拉菜单为jq+css3 动画; css input 无边框,select下 ...
- ActiveMQ之Queue
Queue实现的是点到点模型,在以下的例子中,启动2个消费者共同监听一个Queue,然后循环给这个Queue发送多个消息. 代码如下: public class QueueTest { /** * @ ...