当前位置:网站首页>iMedicalLIS监听程序(2)
iMedicalLIS监听程序(2)
2022-08-05 03:28:00 【Walk in loosing】
从监听程序确立了面向接口编程,和M调用方法约定之后。那么实现面向接口就是第一步实现了。本篇就介绍监听实现最基础结构,检验网站、生成PDF程序等各个都有该结构存在。
spring.net为Java的spring框架在.net的实现。名为spring企业级运行框架。主要提供的功能有IOC、AOP、数据访问等。我主要用到spring.net的IOC和AOP及依附spring的Log4Net写日志。详细可参照spring.net官方文档。我的spring.net经历来自N软的启航计划培训,当时的微软金牌讲师战法全老师给我们上了很多天课,很受用,在spring之前我主要用到面向对象继承编程,对多态接口没实际用上,用的接口都是直接new对象的,所以是假的面向接口编程。
度娘的介绍:
Spring.NET为建立企业级应用提供了一套轻量级的解决方案。通过Spring.NET,我们可以用统一且透明的方式来配置应用程序。Spring.NET的重点是为中间层提供声明式事务管理,以及一个功能齐全的ASP.NET扩展框架。Spring.NET是非侵入式的,代码对框架本身不会产生任何依赖。
Spring.Core 库是框架的基础, 提供依赖注入功能。Spring NET中大多数类库依赖或扩展了Spring.Core的功能。IObjectFactory接口提供了一个简单而优雅的工厂模式,移除了对单例和一些服务定位stub的必要。允许你将真正的程序逻辑与配置解耦。作为对IObjectFactory 的扩展,IApplicationContext接口也在Spring.Core库中,
Spring DOTNET 是一个关注于.NET企业应用开发的应用程序框架。它能够提供很多方面的功能,例如控制反转(Inversion of Control,英文缩写为IoC)、依赖注入(Dependency Injection,英文缩写DI)、面向方面编程(AOP)、数据访问抽象, 以及ASP DOTNET集成等。基于java的spring框架的核心概念和价值已被应用到.NET。Spring DOTNET 1.0 包含一个完全功能的依赖注入容器和AOP库。后续的发布将包含对ASP DOTNET、Remoting和数据访问的支持。
我的介绍:
要想达到面向接口编程,就要求调用方不看到具体实现类。调用方都是针对接口操作。而直接new对象的方式就决定了不能真正意义的面向接口编程。因为使用放确实依赖了实现类。为此需要IOC进行控制反转。IOC通过容器实现工厂模式的设计模式。使用放传入接口类型返回配置的实现类。以此解耦new依赖,达到面向接口编程。AOP实现的是动态代理模式,AOP在IOC返回对象时候用IL语言把返回类和配置的拦截器实现类融合得到一个动态的和请求类实现相同接口的代理类。这样就能动态按配置实现切面效果。如:统一的异常捕获、统一的日志、统一的性能监测、统一的SQL日志。而这些统一的功能随时可以按配置开启和关闭而不侵入代码。这就是引入spring的强大之处。具体IOC和AOP实现可以参照我博客IOC和AOP实现。
此示例说明以下:
1.实现面向接口编程
2.使用spring.net
3.使用log4net
4.为什么检验的监听程序、网站、生成PDF程序有问题老是说看Logs,好习惯就是有问题看Logs。
5.检验web的后台通过容器取业务对象同理,都是借助容器和AOP解耦和实现统一切面,按名称找实现类就行或者到Conf配置找。
6.DotNet太low的印象一般来自拖拖拽拽拉低门槛,大部分人又没引入框架思想。
7.DotNetCore在spirng.net的延续
效果如下(使用者不必关心实现类是谁,随时可以在配置换实现。获得的对象自带随时可关闭和开启的切面功能):
1.先创建一个工程引入和包装spring.net和log4net
2.对容器进行包装
using System;
using System.Collections.Generic;
using Common.Logging;
using Spring.Context;
using Spring.Util;
using LIS.Core.BaseException;
using Spring.Context.Support;
using DemoDll.Util;
namespace DemoDll.Context
{
///<summary NoteObject="Class">
/// [功能描述: 框架容器,该容器是整个框架的核心,不可轻易改动]<br></br>
/// [创建者: 张联珠]<br></br>
/// [创建时间: 20220801]<br></br>
/// <说明>
///
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
public class ObjectContainer : IApplicationContextAware
{
#region 字段
/// <summary>
/// ObjectContainer实例
/// </summary>
private static readonly ObjectContainer instance = new ObjectContainer();
/// <summary>
/// IApplicationContext接口实例,运用程序上下文
/// </summary>
private IApplicationContext applicationContext;
#endregion
/// <summary>
/// 运用程序上下文
/// </summary>
IApplicationContext IApplicationContextAware.ApplicationContext
{
set {
applicationContext = value; }
}
#region 构造
/ <summary>
/ 私有的构造函数,私有化防治外部创建
/ </summary>
//private ObjectContainer()
//{
//}
#endregion
#region 共有方法
#region 非静态方法
/// <summary>
/// 对象容器是否包含指定名称的对象
/// </summary>
/// <param name="name">对象名称</param>
/// <returns>如果对象容器包含指定名称的对象,则为 true;否则为 false。</returns>
public bool InstanceContainsObject(string name)
{
// 验证applicationContext是否已经被初始化
CheackApplicationContext();
if (name == string.Empty)
{
LogUtils.WriteExceptionLog("传入参数为空:", new Exception("查询容器是否包含指定名称的对象时ObjectContainer.InstanceContainsObject(name参数为空)。"));
}
//检查参数是否为空
AssertUtils.ArgumentHasText(name, "name", "查询容器是否包含指定名称的对象时ObjectContainer.InstanceContainsObject(name参数为空)。");
//返回是否包含对象
return applicationContext.ContainsObject(name);
}
/// <summary>
/// 对象容器是否包含指定对象类型
/// </summary>
/// <param name="type">对象类型</param>
/// <returns>如果对象容器包含指定的类型,则为 true;否则为 false。 </returns>
public bool InstanceContainsObject(Type type)
{
// 验证applicationContext是否已经被初始化
CheackApplicationContext();
if (type == null)
{
LogUtils.WriteExceptionLog("传入参数为空:", new Exception("查询容器是否包含指定类型的对象时ObjectContainer.InstanceContainsObject(type参数为空)。"));
}
//检查参数是否为空
AssertUtils.ArgumentNotNull(type, "type", "ObjectContainer.InstanceContainsObject(type参数为空)。");
//返回是否包含对象,用类型
return InstanceContainsObject(type.FullName);
}
/// <summary>
/// 按名称返回对象
/// </summary>
/// <param name="name">对象名称</param>
/// <returns>返回对象</returns>
public object InstanceGetObject(string name)
{
// 验证applicationContext是否已经被初始化
CheackApplicationContext();
if (name == string.Empty)
{
LogUtils.WriteExceptionLog("传入参数为空:", new Exception("按名称返回对象时ObjectContainer.InstanceContainsObject(name参数为空)。"));
}
//检查参数是否为空
AssertUtils.ArgumentHasText(name, "name", "ObjectContainer.InstanceContainsObject(name参数为空)。");
//通过名称返回对象
return applicationContext.GetObject(name);
}
/// <summary>
/// 按类型返回对象
/// </summary>
/// <param name="type">对象类型</param>
/// <returns>返回对象</returns>
public object InstanceGetObject(Type type)
{
//通过类型返回对象
return InstanceGetObject(type, false);
}
/// <summary>
/// 按类型返回对象,如果对象不存在则根据createIfNotFound决定是否自动按类型创建对象
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="createIfNotFound">如果不存在是否自动创建对象</param>
/// <returns>返回的对象</returns>
public object InstanceGetObject(Type type, bool createIfNotFound)
{
// 验证applicationContext是否已经被初始化
CheackApplicationContext();
if (type == null)
{
LogUtils.WriteExceptionLog("传入参数为空:", new Exception("按类型返回对象时ObjectContainer.InstanceContainsObject(type参数为空)。"));
}
//检查参数是否为空
AssertUtils.ArgumentNotNull(type, "ObjectContainer.InstanceContainsObject(type参数为空)。");
// 如果类型是接口
if (type.IsInterface)
{
//获得类型名
var names = applicationContext.GetObjectNamesForType(type);
//没获得
if (names.Length <= 0)
{
LisCoreException ex = new LisCoreException("NotFindDefinitions", String.Format("NotFindDefinitionsInfo", type.FullName));
LogUtils.WriteExceptionLog("框架创建实例时发生了异常,未获得类型全名:",ex);
throw ex;
}
//获得多个的话,返回第一个
else if (names.Length == 1)
{
return InstanceGetObject(names[0]);
}
//获得一个,正常返回
else
{
return InstanceGetObject(names[0]);
}
}
else
{
//如果没找到且设置未找到自动创建
if (!InstanceContainsObject(type.FullName) && createIfNotFound)
{
return ObjectUtils.InstantiateType(type);
}
//返回对象
return InstanceGetObject(type.FullName);
}
}
/// <summary>
/// 按类型返回强类型的对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <returns>返回的对象</returns>
public T InstanceGetObject<T>()
{
return InstanceGetObject<T>(false);
}
/// <summary>
/// 按接口类型返回对象集合
/// </summary>
/// <typeparam name="T">接口类型</typeparam>
/// <returns>对象集合</returns>
public IList<T> InstanceGetObjects<T>()
{
// 验证applicationContext是否已经被初始化
CheackApplicationContext();
//获取对象
var objects = applicationContext.GetObjectsOfType(typeof(T));
List<T> lstObject = new List<T>();
//填充集合
if (objects != null)
{
foreach (var obj in objects.Values)
{
lstObject.Add((T)obj);
}
}
//返回数据
return lstObject;
}
/// <summary>
/// 按类型返回强类型的对象,如果对象不存在则根据createIfNotFound决定是否自动按类型创建对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="createIfNotFound">找不到时是否自动创建对象</param>
/// <returns>返回的对象</returns>
public T InstanceGetObject<T>(bool createIfNotFound)
{
return (T)InstanceGetObject(typeof(T), createIfNotFound);
}
/// <summary>
/// 按名称返回强类型的对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="name">对象名称</param>
/// <returns>返回的对象</returns>
public T InstanceGetObject<T>(string name) where T : class
{
// 验证applicationContext是否已经被初始化
CheackApplicationContext();
if (name == string.Empty)
{
LogUtils.WriteExceptionLog("传入参数为空:", new Exception("按名称返回强类型对象时ObjectContainer.InstanceContainsObject(name参数为空)。"));
}
//检查参数是否为空
AssertUtils.ArgumentHasText(name, "name", "ObjectContainer.InstanceContainsObject(name参数为空)。");
//如果上下文不包含要取的对象
if (!applicationContext.ContainsObject(name))
{
//创建对象
var t = (T)ObjectUtils.InstantiateType(typeof(T));
//创建失败的话,抛异常
if (t == null)
{
LisCoreException ex=new LisCoreException("CantCreateInstance",
string.Format(
"CantCreateInstanceInfo",
typeof(T).FullName));
LogUtils.WriteExceptionLog("按名称返回强类型的对象时发生异常,不能创建指定类型的对象:",ex);
throw ex;
}
return t;
}
Type type = applicationContext.GetType(name);
if (!(typeof(T).IsAssignableFrom(type)))
{
LisCoreException ex=new LisCoreException("TypeNotMatch", string.Format(
"TypeNotMatchInfo",
typeof(T).FullName, type.FullName));
LogUtils.WriteExceptionLog("按名称返回强类型的对象时发生异常,所取对象不能转换为目标对象:", ex);
throw ex;
}
return (T)InstanceGetObject(name);
}
/// <summary>
/// 返回实际的对象类型,返回的类型是传入类型或传入类型的子类型
/// </summary>
/// <param name="type">类型</param>
/// <returns>实际的对象类型</returns>
public Type InstanceGetRealType(Type type)
{
// 验证applicationContext是否已经被初始化
CheackApplicationContext();
if (type == null)
{
LogUtils.WriteExceptionLog("传入参数为空:", new Exception("返回实际对象的类型时ObjectContainer.InstanceContainsObject(type参数为空)。"));
}
//检查参数是否为空
AssertUtils.ArgumentNotNull(type, "ObjectContainer.InstanceContainsObject(type参数为空)。");
//如果不包含,直接返回
if (!InstanceContainsObject(type))
{
return type;
}
//返回类型
return applicationContext.GetType(type.FullName);
}
/// <summary>
/// 是否包含指定关键字的消息。
/// </summary>
/// <param name="key">消息关键字</param>
/// <returns>true:包含 false:不包含</returns>
public bool InstanceContainsMessage(string key)
{
try
{
this.applicationContext.GetMessage(key);
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 从资源文件中取得消息。
/// </summary>
/// <param name="key">消息关键字</param>
/// <param name="msgParams">消息参数</param>
/// <returns>消息</returns>
public string InstanceGetMessage(string key, params string[] msgParams)
{
try
{
return this.applicationContext.GetMessage(key, msgParams);
}
catch
{
LisCoreException ex=new LisCoreException("NotFindResource", String.Format("NotFindResourceInfo", key));
LogUtils.WriteExceptionLog("从资源文件中取得消息时发生异常:",ex);
throw ex;
}
}
#endregion
#region 静态方法
/// <summary>
/// 返回唯一的ObjectContainer实例
/// </summary>
/// <returns>ObjectContainer实例</returns>
public static ObjectContainer GetInstance()
{
return instance;
}
/// <summary>
/// 对象容器是否包含指定对象类型
/// </summary>
/// <param name="type">对象类型</param>
/// <returns>如果对象容器包含指定的类型,则为 true;否则为 false。 </returns>
public static bool ContainsObject(Type type)
{
return GetInstance().InstanceContainsObject(type);
}
/// <summary>
/// 对象容器是否包含指定名称的对象
/// </summary>
/// <param name="name">对象名称</param>
/// <returns>如果对象容器包含指定名称的对象,则为 true;否则为 false。</returns>
public static bool ContainsObject(string name)
{
return GetInstance().InstanceContainsObject(name);
}
/// <summary>
/// 按类型返回强类型的对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <returns>返回的对象</returns>
public static T GetObject<T>()
{
return GetInstance().InstanceGetObject<T>();
}
/// <summary>
/// 按类型返回强类型的对象,改方法支持获得对象时给一个属性设置值
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="propName">属性名称</param>
/// <param name="propValue">属性值</param>
/// <returns>返回的对象</returns>
public static T GetObject<T>(string propName,object propValue)
{
//获得类型
Type type=typeof(T);
//获取实体
T obj = GetInstance().InstanceGetObject<T>();
if (obj == null)
{
throw new Exception("spring 服务“" + type.FullName + "”注册的实现信息缺失!");
}
Type proxyType = obj.GetType().GetInterface("LIS.DAL.DataAccess.IBaseService");
if (proxyType != null)
{
//获得属性信息
System.Reflection.PropertyInfo propertyInfo = proxyType.GetProperty(propName);
//设置属性值
if (propertyInfo != null && propValue != null && propertyInfo.PropertyType == propValue.GetType())
{
propertyInfo.SetValue(obj, propValue, null);
}
}
else
{
//获得属性信息
System.Reflection.PropertyInfo propertyInfo = type.GetProperty(propName);
//设置属性值
if (propertyInfo != null && propValue != null && propertyInfo.PropertyType == propValue.GetType())
{
propertyInfo.SetValue(obj, propValue, null);
}
}
return obj;
}
/// <summary>
/// 按接口类型返回对象集合
/// </summary>
/// <typeparam name="T">接口类型</typeparam>
/// <returns>对象集合</returns>
public static IList<T> GetObjects<T>()
{
return GetInstance().InstanceGetObjects<T>();
}
/// <summary>
/// 按类型返回强类型的对象,如果对象不存在则根据createIfNotFound决定是否自动按类型创建对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="createIfNotFound">是否自动创建对象</param>
/// <returns>返回的对象</returns>
public static T GetObject<T>(bool createIfNotFound)
{
return GetInstance().InstanceGetObject<T>(createIfNotFound);
}
/// <summary>
/// 按名称返回强类型的对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="name">对象名称</param>
/// <returns>返回的对象</returns>
public static T GetObject<T>(string name) where T : class
{
return GetInstance().InstanceGetObject<T>(name);
}
/// <summary>
/// 按名称返回对象
/// </summary>
/// <param name="name">对象名称</param>
/// <returns>返回对象</returns>
public static object GetObject(string name)
{
return GetInstance().InstanceGetObject(name);
}
/// <summary>
/// 按类型返回对象
/// </summary>
/// <param name="type">对象类型</param>
/// <returns>返回对象</returns>
public static object GetObject(Type type)
{
return GetInstance().InstanceGetObject(type);
}
/// <summary>
/// 按类型返回对象,如果对象不存在则根据createIfNotFound决定是否自动按类型创建对象
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="createIfNotFound">是否自动创建对象</param>
/// <returns>返回的对象</returns>
public static object GetObject(Type type, bool createIfNotFound)
{
return GetInstance().InstanceGetObject(type, createIfNotFound);
}
/// <summary>
/// 返回实际的对象类型,返回的类型是传入类型或传入类型的子类型
/// </summary>
/// <param name="type">类型</param>
/// <returns>实际的对象类型</returns>
public static Type GetObjectRealType(Type type)
{
return GetInstance().InstanceGetRealType(type);
}
/// <summary>
/// 从资源文件中取得消息。
/// </summary>
/// <param name="key">消息关键字</param>
/// <param name="msgParams">消息参数</param>
/// <returns>消息</returns>
public static string GetMessage(string key, params string[] msgParams)
{
return GetInstance().InstanceGetMessage(key, msgParams);
}
/// <summary>
/// 是否包含指定关键字的消息。
/// </summary>
/// <param name="key">消息关键字</param>
/// <returns>true:包含 false:不包含</returns>
public static bool ContainsMessage(string key)
{
return GetInstance().InstanceContainsMessage(key);
}
/// <summary>
/// 初始化并获取运用程序上下文
/// </summary>
/// <returns></returns>
public static IApplicationContext GetContext()
{
return GetInstance().InnerGetContext();
}
/// <summary>
/// 刷新容器
/// </summary>
public static void RefreshContainer()
{
GetInstance().applicationContext=ContextRegistry.GetContext();
}
#endregion
#endregion
#region 私有方法
/// <summary>
/// 初始化并获得上下文
/// </summary>
/// <returns>运用程序上下文</returns>
private IApplicationContext InnerGetContext()
{
GetInstance().CheackApplicationContext();
return applicationContext;
}
/// <summary>
/// 验证applicationContext是否已经被初始化
/// </summary>
private void CheackApplicationContext()
{
if (applicationContext == null)
{
try
{
applicationContext = ContextRegistry.GetContext();
if (applicationContext == null)
{
var ex = new LisCoreException("NotInstantiatedContex", "NotInstantiatedContexInfo");
LogUtils.WriteExceptionLog("初始化运用程序上下文发生异常,请检查配置文件:", ex);
throw ex;
}
}
catch (Exception e)
{
if (applicationContext == null)
{
var ex = new LisCoreException("NotInstantiatedContex", "NotInstantiatedContexInfo"+e.InnerException.Message);
LogUtils.WriteExceptionLog("初始化运用程序上下文发生异常,请检查配置文件:", ex);
throw ex;
}
}
}
}
#endregion
}
}
3.对日志进行包装
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Logging;
using System.Text.RegularExpressions;
namespace DemoDll.Util
{
///<summary NoteObject="Class">
/// [功能描述: 日志辅助工具]<br></br>
/// [创建者: 张联珠]<br></br>
/// [创建时间: 20220801]<br></br>
/// <说明>
///
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
public static class LogUtils
{
#region 静态成员
/// <summary>
/// 书写异常日志
/// </summary>
/// /// <param name="message">日志内容</param>
/// <param name="exception">异常对象</param>
public static void WriteExceptionLog(string message, Exception exception)
{
LogManager.GetLogger("Exception").Error(message, exception);
}
/// <summary>
/// 书写性能日志
/// </summary>
/// <param name="message">日志内容</param>
public static void WriteCapabilityLog(string message)
{
LogManager.GetLogger("Capability").Info(message);
}
/// <summary>
/// 书写安全日志
/// </summary>
/// <param name="message">日志内容</param>
public static void WriteSecurityLog(string message)
{
LogManager.GetLogger("Security").Info(message);
}
/// <summary>
/// 书写操作日志
/// </summary>
/// <param name="message">日志内容</param>
public static void WriteOperationLog(string message)
{
LogManager.GetLogger("Operation").Info(message);
}
/// <summary>
/// 书写调试日志
/// </summary>
/// <param name="message">日志内容</param>
public static void WriteDebugLog(string message)
{
LogManager.GetLogger("Debug").Debug(message);
}
/// <summary>
/// 书写调试日志
/// </summary>
/// <param name="message">日志内容</param>
public static void WriteSqlLog(string message)
{
LogManager.GetLogger("SqlLog").Debug(ReplaceSpaceToOne(message));
}
/// <summary>
/// 把多个空格替换成一个
/// </summary>
/// <param name="str">要处理的串</param>
/// <returns>结果</returns>
private static string ReplaceSpaceToOne(string str)
{
string resultString = string.Empty;
try
{
resultString = Regex.Replace(str, "\\s{2,}", " ");
return resultString;
}
catch
{
return str;
}
}
#endregion
}
}
4.使用切面功能的拦截器
异常拦截器
using System;
using AopAlliance.Intercept;
using LIS.Core.BaseException;
using DemoDll.Util;
namespace DemoDll.Aop
{
///<summary NoteObject="Class">
/// [功能描述: 业务异常拦截器,一方面写日志,另一方面整个业务层的facade层不让抛出非底层异常,即使抛出了其他异常,也转换成业务异常]<br></br>
/// [创建者: 张联珠]<br></br>
/// [创建时间: 20220801]<br></br>
/// <说明>
///
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
public class BusinessExceptionAdvice : IMethodInterceptor
{
/// <summary>
/// 业务异常拦截调用方法
/// </summary>
/// <param name="invocation">方法信息</param>
/// <returns>返回值</returns>
public object Invoke(IMethodInvocation invocation)
{
try
{
return invocation.Proceed();
}
//捕获业务异常
catch (BusinessException ex)
{
//写日志
LogUtils.WriteExceptionLog(ex.Message, ex);
//抛出异常
throw ex;
}
//捕获数据库异常
catch (DataAccessException ex)
{
//写日志
LogUtils.WriteExceptionLog(ex.Message, ex);
//抛出异常
throw ex;
}
//捕获框架异常
catch (LisCoreException ex)
{
//写日志
LogUtils.WriteExceptionLog(ex.Message, ex);
//抛出异常
throw ex;
}
//如果不是这三类异常,把异常转化成业务异常,不让直接抛出普通异常,因为WCF部署时会导致通道异常
catch (Exception ex)
{
//写日志
LogUtils.WriteExceptionLog(ex.Message, ex);
BusinessException be = new BusinessException("未定义的业务异常,不是由业务逻辑主动抛出,由框架转换成业务异常了",ex.Message);
//抛出异常
throw be;
}
}
}
}
性能拦截器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using AopAlliance.Intercept;
using DemoDll.Util;
namespace DemoDll.Aop
{
///<summary NoteObject="Class">
/// [功能描述: 性能拦截器,进行性能方面的日子书写工作]<br></br>
/// [创建者: 张联珠]<br></br>
/// [创建时间: 20220801]<br></br>
/// <说明>
///
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
public class CapabilityAdvice : IMethodInterceptor
{
/// <summary>
/// 业务异常拦截调用方法
/// </summary>
/// <param name="invocation"></param>
/// <returns></returns>
public object Invoke(IMethodInvocation invocation)
{
Stopwatch watch = new Stopwatch();
watch.Start();
var result = invocation.Proceed();
//写性能日志
LogUtils.WriteCapabilityLog("执行类" + invocation.TargetType.Name + "的方法" + invocation.Method.Name +"耗时:" + watch.Elapsed.TotalSeconds.ToString());
return result;
}
}
}
操作日志拦截器
using AopAlliance.Intercept;
using DemoDll.Util;
using System.Text;
namespace DemoDll.Aop
{
///<summary NoteObject="Class">
/// [功能描述: 操作日志拦截器,对容器对象的符合条件的方法都书写方法输入输出日志]<br></br>
/// [创建者: 张联珠]<br></br>
/// [创建时间: 20220801]<br></br>
/// <说明>
///
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
public class OperationLogAdvice : IMethodInterceptor
{
/// <summary>
/// 拦截方法
/// </summary>
/// <param name="invocation">方法实例</param>
/// <returns>方法返回值</returns>
public object Invoke(IMethodInvocation invocation)
{
//输出类名,方法名
string methodString = string.Format("类名:{0}方法名:{1}", invocation.TargetType.Name, invocation.Method.Name);
StringBuilder sb = new StringBuilder();
sb.Append(methodString);
LogUtils.WriteOperationLog(methodString);
//有参数
if (invocation.Arguments != null && invocation.Arguments.Length > 0)
{
foreach (var arg in invocation.Arguments)
{
if (arg != null)
{
sb.Append("参数:" + arg.ToString());
}
else
{
sb.Append("参数:null");
}
}
LogUtils.WriteOperationLog(sb.ToString());
}
//执行方法
var result = invocation.Proceed();
//有结果的话,写出结果到日志
if (result != null)
{
sb.Append("结果:" + result.ToString());
}
LogUtils.WriteOperationLog(sb.ToString());
return result;
}
}
}
SQL日志拦截器
using System;
using AopAlliance.Intercept;
using DemoDll.Util;
using System.ComponentModel;
namespace DemoDll.Aop
{
///<summary NoteObject="Class">
/// [功能描述: SQL日志的拦截器,把通过数据访问层执行的sql都写入sql日志,方便查看]<br></br>
/// [创建者: 张联珠]<br></br>
/// [创建时间: 20220801]<br></br>
/// <说明>
///
/// </说明>
/// <修改记录>
/// <修改时间></修改时间>
/// <修改内容>
///
/// </修改内容>
/// </修改记录>
/// </summary>
public class SqlLogAdvice : IMethodInterceptor
{
/// <summary>
/// 是否要输出SQL关键字
/// </summary>
[DefaultValue(true)]
public bool OutputKey {
get; set; }
/// <summary>
/// 是否要输出SQL
/// </summary>
[DefaultValue(true)]
public bool OutputSql {
get; set; }
/// <summary>
/// 拦截方法
/// </summary>
/// <param name="invocation">方法实例</param>
/// <returns>方法返回值</returns>
public object Invoke(IMethodInvocation invocation)
{
string key = invocation.Arguments[0].ToString();
var result = invocation.Proceed();
if (this.OutputKey)
{
LogUtils.WriteOperationLog("SQL关键字: " + key);
}
if (this.OutputSql)
{
LogUtils.WriteOperationLog("SQL语句: " + result.ToString());
}
return result;
}
}
}
5.然后建一个测试工程,引入spring的配置
<?xml version="1.0"?>
<configuration>
<!--spring配置-->
<configSections>
<sectionGroup name="spring">
<!---此三项必须配置-->
<!--参数段-->
<section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
<!--运用程序上下文段-->
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<!--配置总节点段-->
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
<!---->
</sectionGroup>
<sectionGroup name="common">
<!--日志段-->
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
</sectionGroup>
<!--日志段-->
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<common>
<logging>
<!--日志适配器-->
<factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net">
<arg key="configType" value="FILE-WATCH"/>
<arg key="configFile" value="~/Conf/Log4Net.xml"/>
</factoryAdapter>
</logging>
</common>
<spring>
<!--引入多个文件配置,按功能分类对象配置用-->
<context>
<!--引入当前config的object节点-->
<resource uri="config://spring/objects"/>
<!--引入相对路径下的Conf下配置-->
<resource uri="~/Conf/AopConfig.xml"/>
<resource uri="~/Conf/ObjConfig.xml"/>
</context>
<objects>
<!--配置接口的实现类-->
<object id="Student" type="DemoDll.Test.Student,DemoDll" singleton="false">
</object>
</objects>
<parsers>
<parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"/>
<parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data"/>
<parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop"/>
</parsers>
</spring>
<appSettings>
<add key="WebServiceAddress" value=""/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
</startup>
</configuration>
配置AOP,我实现的测试类是Student所以配置靶点加上了.*dent。告诉spring那些匹配对象要加切面。
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net" xmlns:aop="http://www.springframework.net/aop">
<!--必须让Spring.NET容器管理DefaultAdvisorAutoProxyCreator类-->
<object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop"/>
<!-- 操作方法日志 -->
<object id="OperationLogAdvice" type="DemoDll.Aop.OperationLogAdvice, DemoDll" />
<!-- 操作方法日志拦截 -->
<object type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
<property name="advice" ref="OperationLogAdvice"/>
<property name="patterns">
<list>
<value>.*Service</value>
<value>.*Facade</value>
<value>.*Dal</value>
<value>.*Table</value>
<value>.*dent</value>
</list>
</property>
</object>
<!-- 异常处理日志拦截 -->
<object id="BllExceptionAdvice" type="DemoDll.Aop.BusinessExceptionAdvice, DemoDll" />
<!-- 异常处理日志拦截 -->
<object type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
<property name="advice" ref="BllExceptionAdvice"/>
<property name="patterns">
<list>
<value>.*Service</value>
<value>.*Facade</value>
<value>.*Dal</value>
<value>.*Table</value>
<value>.*dent</value>
</list>
</property>
</object>
<!-- 性能日志拦截 -->
<object id="CapabilityAdvice" type="DemoDll.Aop.CapabilityAdvice, DemoDll" />
<!-- 性能日志拦截 -->
<object type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor, Spring.Aop">
<property name="advice" ref="CapabilityAdvice"/>
<property name="patterns">
<list>
<value>.*Service</value>
<value>.*Facade</value>
<value>.*Dal</value>
<value>.*Table</value>
<value>.*dent</value>
</list>
</property>
</object>
</objects>
配置log4net
<?xml version="1.0" encoding="utf-8" ?>
<log4net debug="false">
<appender name="ExceptionRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="DatePattern" value="yyyy-MM-dd.'log'" />
<file value="Logs/异常日志.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1024KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %15logger %appdomain %location -- %message %exception %newline" />
</layout>
</appender>
<appender name="DebugRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="DatePattern" value="yyyy-MM-dd.'log'" />
<file value="Logs/调试日志.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1024KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date -- %message %exception %newline" />
</layout>
</appender>
<appender name="OperationRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="DatePattern" value="yyyy-MM-dd.'log'" />
<file value="Logs/方法日志.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1024KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
<appender name="SqlRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="DatePattern" value="yyyy-MM-dd.'log'" />
<file value="Logs/Sql语句日志.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1024KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
<appender name="CapabilityRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="DatePattern" value="yyyy-MM-dd.'log'" />
<file value="Logs/性能.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1024KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
<appender name="SecurityRollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="LockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="DatePattern" value="yyyy-MM-dd.'log'" />
<file value="Logs/安全.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1024KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG"/>
</root>
<logger name="Exception">
<appender-ref ref="ExceptionRollingLogFileAppender" />
</logger>
<logger name="Operation">
<appender-ref ref="OperationRollingLogFileAppender"/>
</logger>
<logger name="Debug">
<appender-ref ref="DebugRollingLogFileAppender" />
</logger>
<logger name="SqlLog">
<appender-ref ref="SqlRollingLogFileAppender" />
</logger>
<logger name="Capability">
<appender-ref ref="CapabilityRollingLogFileAppender"/>
</logger>
<logger name="Security">
<appender-ref ref="SecurityRollingLogFileAppender"/>
</logger>
</log4net>
6.测试代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SpringLog4Net
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
/// <summary>
/// 加载
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FrmMain_Load(object sender, EventArgs e)
{
DemoDll.Test.IStudent stu = DemoDll.Context.ObjectContainer.GetObject<DemoDll.Test.IStudent>();
stu.Say("我是zhanglianzhu!");
DemoDll.Util.LogUtils.WriteDebugLog("通过Log4Net写日志,日志可以通过配置开启或关闭");
}
}
}
7.运行之后,正常得到对象,正常表现出切面功能,在Logs文件夹下各日志输出了
在DotNetCore之后已经自带容器了,所以spring.net没落了,那么在dotnetcore一样想继承spring.net代码资产怎么办。
可以自己读取spring.net格式配置xml反射实现容器
/// <summary>
/// 构造器
/// </summary>
private static ContainerBuilder builder = new ContainerBuilder();
/// <summary>
/// 初始化IOC容器
/// </summary>
public static void InitIoc()
{
//读取IOC路径下的XML配置文件来反射构造IOC
string IocPath = Path.Combine(AppContext.BaseDirectory, LIS.Core.MultiPlatform.LISConfigurtaion.Configuration["IocConfPath"]);
if (Directory.Exists(IocPath))
{
DirectoryInfo asmxdi = new DirectoryInfo(IocPath);
FileInfo[] asmxFiles = asmxdi.GetFiles();
if (asmxFiles != null && asmxFiles.Length > 0)
{
foreach (FileInfo fi in asmxFiles)
{
if (fi.Extension.ToLower() == ".xml")
{
string confStr = ReadTxt(fi.FullName);
//创建一个xml文档
XmlDocument xmlDoc = new XmlDocument();
//为文档导入数据
xmlDoc.LoadXml(confStr);
//获得根节点
XmlNode root = xmlDoc.LastChild;
//得到返回值节点
XmlNodeList objConfs = root.ChildNodes;
if(objConfs!=null&& objConfs.Count>0)
{
foreach(XmlNode node in objConfs)
{
if(node.Name!= "object")
{
continue;
}
string typeStr= node.Attributes["type"].Value;
string idStr = "";
if (node.Attributes["id"]!=null)
{
idStr = node.Attributes["id"].Value;
}
string[] typeArr = typeStr.Split(',');
string singletonStr = node.Attributes["singleton"].Value;
Type serviceType = GetType(typeArr[0], typeArr[1]);
Type [] interArr=serviceType.GetInterfaces();
if(interArr!=null&& interArr.Length>0)
{
if(idStr!=null&&idStr!="")
{
if(!dicIdTypes.ContainsKey(idStr))
{
dicIdTypes.Add(idStr, interArr[0]);
}
else
{
throw new Exception("已包含id为:"+idStr+"的容器配置了!");
}
}
foreach(Type it in interArr)
{
if(!dicTypes.ContainsKey(it))
{
dicTypes.Add(it, serviceType);
}
}
}
}
}
}
}
}
}
}
/// <summary>
/// 注册
/// </summary>
/// <typeparam name="TInterface">接口</typeparam>
/// <typeparam name="TImplementation">实现类</typeparam>
public static void Register<TInterface, TImplementation>() where TImplementation : TInterface
{
if (!dicTypes.ContainsKey(typeof(TInterface)))
{
dicTypes.Add(typeof(TInterface), typeof(TImplementation));
}
}
/// <summary>
/// 注册一个单例实体
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="instance">单例</param>
public static void Register<T>(T instance) where T : class
{
builder.RegisterInstance(instance).SingleInstance();
}
/// <summary>
/// 构建IOC容器
/// </summary>
public static IServiceProvider Build(IServiceCollection services)
{
//注册程序集
if (otherAssembly != null)
{
foreach (var item in otherAssembly)
{
builder.RegisterAssemblyTypes(Assembly.Load(item));
}
}
//注册类型
if (typesList != null)
{
foreach (var type in typesList)
{
builder.RegisterType(type);
}
}
//注册类型
if (dicTypes != null)
{
foreach (var dicType in dicTypes)
{
builder.RegisterType(dicType.Value).As(dicType.Key);
}
}
//构造容器
builder.Populate(services);
container = builder.Build();
return new AutofacServiceProvider(container);
}
然后在Startup.cs里调用初始化容器,别的使用容器的地方就不用改了,在spring.net时候的配置也一样用。从实现上看.netcore的容器实现的更高明一点,他没管配置部分,只给你提供往容器放对象和取对象的功能。你自己怎么放对象和取那就任意发挥了。如果简单new对象写死往容器加就难以发挥功效了。可以自己解析配置反射对象来初始化容器。配置可以是xml、json、数据库各种能表示的东西。从spring.net的.netcore,变的是框架,不变的是灵魂。
iMedicalLIS技术系列篇–爱好–产品–事业
边栏推荐
- 2022高处安装、维护、拆除考试题模拟考试题库及在线模拟考试
- How to Add Category-Specific Widgets in WordPress
- Call Alibaba Cloud oss and sms services
- [TA-Frost Wolf_may-"Hundred Talents Project"] Graphics 4.3 Real-time Shadow Introduction
- Use Unity to publish APP to Hololens2 without pit tutorial
- Use SuperMap iDesktopX data migration tool to migrate map documents and symbols
- 测试薪资这么高?刚毕业就20K
- The most effective seven performance testing techniques of software testing techniques
- Solana NFT开发指南
- How to sort multiple fields and multiple values in sql statement
猜你喜欢
[论文笔记] MapReduce: Simplified Data Processing on Large Clusters
Industry Status?Why do Internet companies prefer to spend 20k to recruit people rather than raise their salary to retain old employees~
2022-08-04 The sixth group, hidden from spring, study notes
大像素全景制作完成后,推广方式有哪些?
引领数字医学高地,中山医院探索打造未来医院“新范式”
dmp (dump) dump file
开发Hololens遇到The type or namespace name ‘HandMeshVertex‘ could not be found..
Use SuperMap iDesktopX data migration tool to migrate ArcGIS data
Dive into how it works together by simulating Vite
[TA-Frost Wolf_may-"Hundred Talents Project"] Graphics 4.3 Real-time Shadow Introduction
随机推荐
Object.defineProperty monitors data changes in real time and updates the page
ffmpeg pixel format basics
Slapped in the face: there are so many testers in a certain department of byte
leetcode-每日一题1403. 非递增顺序的最小子序列(贪心)
High Item 02 Information System Project Management Fundamentals
【七夕节】浪漫七夕,代码传情。将爱意变成绚烂的立体场景,给她(他)一个惊喜!(送代码)
STM32 uses stm32cubemx LL library series tutorial
[TA-Frost Wolf_may-"Hundred Talents Project"] Graphics 4.3 Real-time Shadow Introduction
public static
List asList(T... a) What is the prototype? Common open source databases under Linux, how many do you know?
Native js realizes the effect of selecting and canceling all the multi-select boxes
【Daily Training】1403. Minimum Subsequence in Non-Increasing Order
Solana NFT开发指南
今年七夕,「情蔬」比礼物更有爱
One hundred - day plan -- -- DAY2 brush
cross domain solution
Use Unity to publish APP to Hololens2 without pit tutorial
From "useable" to "easy to use", domestic software is self-controllable and continues to advance
ffmpeg enumeration decoders, encoders analysis
冰蝎V4.0攻击来袭,安全狗产品可全面检测