spring.net结合普通三层(实现IOC 及AOP中的异常记录功能)
首先先引用一下AOP相关知识;
AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。
OOP是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等来定义彼此的关系;AOP是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只需要修改这个行为即可。
AOP是使用切面(aspect)将横切关注点模块化,OOP是使用类将状态和行为模块化。在OOP的世界中,程序都是通过类和接口组织的,使用它们实现程序的核心业务逻辑是十分合适。但是对于实现横切关注点(跨越应用程序多个模块的功能需求)则十分吃力,比如日志记录,验证等
最近一直在学习spring.net的知识;结合先前学习的内容做一个跟普通三层相结合的实例;主要是演示spring.net中关于AOP的功能;首先了解一下我实例的项目架构;
其中ISpringNetBLL,ISpringNetDAL分别为逻辑层跟数据层的接口层;因为本实例重点是运用结合spring.net所以代码都是非常简单;并无结合数据库的操作;
具体代码分别如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ISpringNetBLL { //可以给BLL层定义一个统一的接口 然后再定义一个抽象类来继承接口 public interface IUserOperate { string UserLogin( string UserName); } } |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Spring.Core; using Spring.Context; using Spring.Context.Support; namespace ISpringNetBLL { public abstract class BaseBLL:IUserOperate { public BaseBLL() { } public abstract string UserLogin( string UserName); } } |
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ISpringNetDAL { public interface IUserOperateDAL { string UserLogin( string UserName); } } |
接下来我们看一下SpringNetAop层的内容;此层主要是实现一些AOP的代码,以及特性和一个统一调用spring.net的类;记录日志我们使用Log4Net来实现;
1:Aspects 文件夹里存放的几个类分别是Spring.net几种AOP的通知模式;因为本实例主要是要演示异常的调用所以我们调用的是类LoggingThrowsAdvice.cs;有关Log4Net的运用大家可以搜索一下,不是本文的重点;这边有个要注意此处是类库运用Log4net,所以在读取配置文件时要写成@"bin\\Log4Net.config";而配置文件Log4Net.config属性要设置为:始终复制 嵌入的资源;
using System.Linq; using System.Text; using SpringNetCommon; using System.Reflection; using Spring.Aop; using log4net; using log4net.Core; [assembly: log4net.Config.XmlConfigurator(ConfigFile = @"bin\\Log4Net.config" , Watch = true )] namespace SpringNetAop.Aspects { public class LoggingThrowsAdvice:IThrowsAdvice { private ILog logger; public LoggingThrowsAdvice() { logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); log4net.Config.XmlConfigurator.Configure( new System.IO.FileInfo( "Log4Net.config" )); } public void AfterThrowing(Exception ex) { logger.Warn( String.Format( "异常的内容为: {0}" , ex)); } } } |
Log4Net.config配置的内容如下:配置实现的功能是每天生成一个记录文件
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="System.Configuration.IgnoreSectionHandler" /> </configSections> <log4net> <appender name="RollingLogRootFileAppender" type="log4net.Appender.RollingFileAppender"> <!--日志的路径--> <file value=".\Log\WanLog" /> <!--是否覆盖,默认是追加true--> <appendToFile value="true"/> <!--文件滚动周期(每日创建新日志文件)--> <datePattern value="yyyyMMdd".txt""/> <!--设置无限备份=-1 ,最大备份数为1000--> <maxSizeRollBackups value="1000"/> <!--名称是否可以更改为false为可以更改--> <staticLogFileName value="false" /> <!--文件滚动选项Composite表示根据日期和大小来滚动--> <rollingStyle value="Composite" /> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}[%t][%-5p][%c]%m%n%exception%n" /> </layout> </appender> <root> <level value="All" /> <appender-ref ref="RollingLogRootFileAppender" /> </root> </log4net> </configuration>
2:Attributes存放的是一个重写的特性;spring.net特性来定位要调用AOP;这边主要注意是要继承Attribute;
using System.Collections.Generic; using System.Linq; using System.Text; namespace SpringNetAop.Attributes { public class LoggingAttributes:Attribute { public LoggingAttributes() { } } }
3:SpringNetHelp文件夹存放的是一个统一调用spring.net的类;因为我把spring.net的配置文件存放在UI层;所以要注意调用的路径问题;配置文件我们在UI层进行;
using Spring.Core; using Spring.Context; using Spring.Context.Support; using Spring.Core.IO; using Spring.Objects.Factory; using Spring.Objects.Factory.Xml; namespace SpringNetAop.SpringNetHelp { public class GetAppContext { private static IApplicationContext applicationContext = null; public GetAppContext() { } public static IApplicationContext ApplicationContext { get { applicationContext = new XmlApplicationContext("~/Config/Objects.xml"); return applicationContext; } } } }
接下来我们看一下逻辑层跟数据层的代码;
首先看一下数据层的代码;我们为要进行异常记录的方法加上特性[LoggingAttributes]
using System.Linq; using System.Text; using ISpringNetDAL; using SpringNetAop.Attributes; namespace SpringNetDAL { public class UserOperateDAL:IUserOperateDAL { [LoggingAttributes] public string UserLogin(string UserName) { throw new Exception("我是DAL层的异常"); } } }
看BLL层的具体代码如下:
using Spring.Core; using SpringNetAop; using Spring.Core.IO; using Spring.Objects.Factory.Xml; using Spring.Objects.Factory; using Spring.Context.Support; using Spring.Context; namespace SpringNetBLL { public class UserOperate:BaseBLL { private IUserOperateDAL _userOperatedal = null; public UserOperate() { } [LoggingAttributes] public override string UserLogin(string UserName) { // throw new Exception("我是BLL层异常内容啊"); _userOperatedal = (IUserOperateDAL)SpringNetAop.SpringNetHelp.GetAppContext.ApplicationContext.GetObject("UserOperateDal"); return _userOperatedal.UserLogin(UserName); } } }
接着看一下UI层;这边主要是两个配置文件就是Objects.xml 以及App.config; 其中Objects.xml文件的属性设置:始终复制 生成操作为内容;
App.config的内容如下(关于spring.net配置的说明大家可以搜索园内的spring.net知识或者可以查看spring.net提供的帮助手册,都有很详细的说明):
<?xml version="1.0"?> <configuration> <configSections> <sectionGroup name="spring"> <!--提供Spring对应用程序上下文的支持--> <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/> <!--提供Spring对 对象容器的支持--> <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/> </sectionGroup> </configSections> <spring> <context> <resource uri="file://~/Config/Objects.xml"/> <!--<resource uri="assembly://SpringNetUI/SpringNetUI.Config/Objects.xml"/>--> </context> </spring> </configuration>
Objects.xml文件的内容:
<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <object name="UserOperateDal" type="SpringNetDAL.UserOperateDAL,SpringNetDAL"/> <!--环绕通知拦截 运用特性--> <object id="aroundAdvisor" type="Spring.Aop.Support.AttributeMatchMethodPointcutAdvisor, Spring.Aop"> <property name="Advice"> <object type="SpringNetAop.Aspects.LoggingAroundAdvice, SpringNetAop" /> </property> <property name="Attribute" value="SpringNetAop.Attributes.LoggingAttributes, SpringNetAop" /> </object> <!--后置通知拦截 运用名称--> <object id="afterAdvisor" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop"> <property name="Advice"> <object type="SpringNetAop.Aspects.LoggingAfterAdvice, SpringNetAop" /> </property> <property name="MappedNames"> <list> <value>*UserLogin</value> </list> </property> </object> <!--异常通知拦截 程序所有都支持 不设置条件--> <object id="throwsAdvice" type="SpringNetAop.Aspects.LoggingThrowsAdvice, SpringNetAop" /> <object id="myServiceCommand" type="Spring.Aop.Framework.ProxyFactoryObject"> <property name="Target"> <object type="SpringNetBLL.UserOperate, SpringNetBLL" /> </property> <property name="InterceptorNames"> <list> <value>aroundAdvisor</value> <value>afterAdvisor</value> <value>throwsAdvice</value> </list> </property> </object> </objects>
UI层调用BLL的代码;使用的是Spring.net的IOC
using Spring.Context; using Spring.Context.Support; using Spring.Core.IO; using Spring.Objects.Factory.Xml; using Spring.Objects.Factory; using ISpringNetBLL; using SpringNetAop; using SpringNetBLL; namespace SpringNetUI { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { try { IUserOperate command = (IUserOperate)SpringNetAop.SpringNetHelp.GetAppContext.ApplicationContext.GetObject("myServiceCommand"); command.UserLogin(this.textBox1.Text.Trim()); } catch { } } } }
运行程度得到的结果如下:
2013-04-06 22:28:57[1][WARN ][SpringNetAop.Aspects.LoggingThrowsAdvice]异常的内容为: System.Exception: 我是DAL层的异常
在 SpringNetDAL.UserOperateDAL.UserLogin(String UserName) 位置 F:\测试网址\SpringNETDemo\SpringNetDAL\UserOperateDAL.cs:行号 14
在 SpringNetBLL.UserOperate.UserLogin(String UserName) 位置 F:\测试网址\SpringNETDemo\SpringNetBLL\UserOperate.cs:行号 30
在 _dynamic_SpringNetBLL.UserOperate.UserLogin(Object , Object[] )
在 Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target, Object[] arguments)
在 Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint()
在 Spring.Aop.Framework.AbstractMethodInvocation.Proceed()
在 Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptor.Invoke(IMethodInvocation invocation)
本文的源代码不懂得上传;若有人需要可以留下邮箱;本文的内容是个人学习spring.net的知识,若有错误的地方欢迎指出;