admin 管理员组文章数量: 1184232
2024年1月13日发(作者:解释程序是)
教程
目 录
教程(一)控制反转(依赖注入)(基础篇) ............................................................................................................................................................................ 3
教程(二)环境搭建(基础篇) ............................................................................................................................................................................................... 7
教程(三)实现一个简易的IoC框架(练习篇) ................................................................................................................................................................. 10
教程(四)对象的创建(基础篇) ......................................................................................................................................................................................... 13
教程(五)容器中对象的作用域(基础篇) ......................................................................................................................................................................... 16
教程(六)依赖注入(应用篇) ............................................................................................................................................................................................. 21
教程(七)依赖对象的注入(基础篇) 上 ........................................................................................................................................................................... 26
教程(八)集合类型的注入(基础篇) ................................................................................................................................................................................. 29
教程(九)打造简易的依赖注入框架(练习篇) ................................................................................................................................................................. 34
教程(十)方法的注入(基础篇) ......................................................................................................................................................................................... 40
教程(十一)自定义对象行为(基础篇) ............................................................................................................................................................................. 45
教程(十二)面向切面编程(基础篇) ................................................................................................................................................................................. 47
教程(十三)AOP的概念(基础篇) .................................................................................................................................................................................... 53
教程(十四)AOP的通知类型(基础篇) ............................................................................................................................................................................ 56
教程(十五)AOP的配置(基础篇) .................................................................................................................................................................................... 62
教程(十六)事务管理(应用篇) ......................................................................................................................................................................................... 72
教程(十七)事务传播行为(基础篇) ................................................................................................................................................................................. 83
教程(十八)整合NHibernate(基础篇) ............................................................................................................................................................................. 86
教程(十九)整合NHibernate和 MVC(基础篇) ........................................................................................................................................... 101
教程(二十)整合Remoting(应用篇) .............................................................................................................................................................................. 116
教程(二十一)整合Web Service(应用篇) ..................................................................................................................................................................... 121
教程(二十二)整合(应用篇) ...................................................................................................................................................................... 126
教程(二十三)整合NVelocity(应用篇) ......................................................................................................................................................................... 130
教程(一)控制反转(依赖注入)(基础篇)
在学习这个控制反转(IoC)和面向切面(AOP)的容器框架之前,我们先来看一下什么是控制反转(IoC)。
控制反转(Inversion of Control,英文缩写为IoC),也叫依赖注入(Dependency Injection)。我个人认为控制反转的意思是依赖对象(控制权)发生转变,由最初的类本身来管理依赖对象转变为IoC框架来管理这些对象,使得依赖脱离类本身的控制,从而实现松耦合。
我们先来看一段代码
namespace Dao
{
public interface IPersonDao
{
void Save();
}
public class PersonDao : IPersonDao
{
public void Save()
{
ine("保存 Person");
}
}
}
namespace SpringNetIoC
{
class Program
{
private static void NormalMethod()
{
IPersonDao dao = new PersonDao();
();
ine("我是一般方法");
}
}
}
Program必然需要知道IPersonDao接口和PersonDao类。为了不暴露具体实现,我可以运用设计模式中的抽象工厂模式(Abstract Factory)来解决。
namespace DaoFactory
{
public static class DataAccess
{
public static IPersonDao CreatePersonDao()
{
return new PersonDao();
}
}
}
namespace SpringNetIoC
{
class Program
{
private static void FactoryMethod()
{
IPersonDao dao = PersonDao();
();
ine("我是工厂方法");
}
}
}
这时,Program只需要知道IPersonDao接口和工厂,而不需要知道PersonDao类。然后我们试图想象,要是有这样的工厂框架帮我们管理依赖的对象就好了,于是控制反转出来了。
Program
using System;
using c;
using ;
using ;
using Dao;
using DaoFactory;
using t;
/>
using t;
namespace SpringNetIoC
{
class Program
{
static void Main(string[] args)
{
//NormalMethod();// 一般方法
//FactoryMethod();// 工厂方法
IoCMethod();// IoC方法"
ne();
}
private static void NormalMethod()
{
IPersonDao dao = new PersonDao();
();
ine("我是一般方法");
}
private static void FactoryMethod()
{
IPersonDao dao = PersonDao();
();
ine("我是工厂方法");
}
private static void IoCMethod()
{
IApplicationContext ctx = text();
IPersonDao dao = ect("PersonDao") as IPersonDao;
if (dao != null)
{
();
ine("我是IoC方法");
}
}
}
}
一个简单的控制反转程序例子就实现了。
这样从一定程度上解决了Program与PersonDao耦合的问题,但是实际上并没有完全解决耦合,只是把耦合放到了XML 文件中,通过一个容器在需要的时候把这个依赖关系形成,即把需要的接口实现注入到需要它的类中。我个人认为可以把IoC模式看做是工厂模式的升华,可以把 IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的。
教程(二)环境搭建(基础篇)
一、环境下载及安装
到Spring的官方网站下载框架的安装文件()。目前最新的版本是1.3。下载并解压后就可以了。
我们使用框架经常用到的一下几个文件:
(必要)
(必要)
(可选)
在以后的博客里我们会学习一些与NHibernate和 MVC结合的例子,可以到Hibernate的官方网站和的官方网站下载各自的框架安装文件。
在基于XML的工厂中,这些对象定义表现为一个或多个
xmlns:xsi="/2001/XMLSchema-instance" xsi:schemaLocation=" /xsd/">
同样也可以找到解压目录下的-1.3.0-RC1docschema,把里面的几个.xsd复制到VS2008安装目录下的Microsoft Visual Studio 9.0XmlSchemas文件夹。
必要的时候可以安装建立程序的模板
二、建立一个应用程序
我们新建一个的文件,然后从手册中复制来一段配置模板
xmlns:xsi="/2001/XMLSchema-instance" xsi:schemaLocation=" /xsd/">
目前我找到了实例化容量的两种方式:
1.实际物理路径
IResource input = new FileSystemResource(@"D:");//实际物理路径
IObjectFactory factory = new XmlObjectFactory(input);
2.程序集下寻找配置文件
string[] xmlFiles = new string[]
{
"file://"
};
IApplicationContext context = new XmlApplicationContext(xmlFiles);
IObjectFactory factory = (IObjectFactory)context;
ne();
目前我一般采用后者(程序集下寻找配置文件),这样维护起来比较方便。
这种方式需满足URI语法。
file://文件名
assembly://程序集名/命名空名/文件名
然而更好的方式是在配置文件或添加自定义配置节点
在配置文件中要引入
IApplicationContext ctx = text();ine(ect("PersonDao").ToString());
好了,的环境配置就先讲到这里。
教程(三)实现一个简易的IoC框架(练习篇)
讲了这么多理论,我们来手动实现一个简易的IoC框架的,这样可以加深IoC的理论知识。
一、思路
在我们使用框架的时候,首先需要实例化容器, 然后调用IoC容器IObjectFactory接口中GetObject方法获取容器中的对象。通过这一点就可以告诉我们制作IoC容器需要写一个获取 XML文件内容的方法和申明一个Dictionary
二、分析
要获取XML文件的内容,在3.5的语法中,我自然而然想到了Linq To XML。需要实例XML中配置的对象,我们想到了使用反射技术来获取对象的实例。
三、代码实现
工厂
MyXmlFactory
using System;
using c;
using ;
using ;
using ;
using tion;
namespace MyselfIoC
{
public class MyXmlFactory
{
private IDictionary
public MyXmlFactory(string fileName)
{
InstanceObjects(fileName);// 实例IoC容器
}
///
/// 实例IoC容器
///
///
private void InstanceObjects(string fileName)
{
XElement root = (fileName);
var objects = from obj in ts("object")objectDefine = ionary(
k => ute("id").Value,
v =>
{
string typeName = ute("type").Value;
Type type = e(typeName);
return Instance(type);
}
);
}
///
/// 获取对象
///
///
///
public object GetObject(string id)
{
object result = null;
if (nsKey(id))
{
result = objectDefine[id];
}
return result;
select obj;
}
}
}
2.调用
Program
using System;
using c;
using ;
using ;
namespace MyselfIoC
{
class Program
{
static void Main(string[] args)
{
AppReGIStry();
ne();
}
static void AppRegistry()
{
MyXmlFactory ctx = new MyXmlFactory(@"D:");
ine(ect("PersonDao").ToString());
}
}
}
好了,一个简易的IoC框架就基本实现了。
教程(四)对象的创建(基础篇)
学过了前面的课程,我们来一起学习的IoC容器对象的创建。
创建对象一般有3种方式:1.构造器创建,2.静态工厂创建,3.实例工厂创建
多数情况下,容器会根据对象定义中的type属性值去直接调用相应类型的某个构造器。另外,容器也可以调用工厂方法来创建对象,这时type属性的值就应该是包含工厂方法的类型(按:而不是要创建的类型,但通过该对象定义的名称获取的则是由工厂方法所创建的对象)。工厂方法的产品对象可以是工厂方法所在的类型,也可以是其它类型(按:很多情况下工厂方法位于单独的类型中),这无关紧要。(摘自中文手册)
一、通过构造器创建对象
通过构造器创建对象需要满足这几个条件:1.指明对象类型type="类全名,程序集名"(
Program
class Program
{
static void Main(string[] args)
{
IApplicationContext ctx = text();
Person person = (Person)ect("modernPerson");
();
ne();
}
}
从上面代码我们可以看出,把对象交给容器进行管理,ModernPerson类不需要知道具体使用什么工具,仅仅是机械化的工作。至于使用的什么工具,则由配置文件决定,所有对象由容器管理,这样可以实现动态的拆装组建和组件重用。我个人理解依赖注入是反射工厂的加强版。
教程(七)依赖对象的注入(基础篇) 上
一、属性注入
上篇我们简单提到依赖注入的用途。回顾一下所讲内容,发现在object节点下使用了
值类型的注入是需要使用property 节点的value属性。如
作为内联类型可以使用如下:
同理,内联类型可以是循环引用的对象(见代码处)。
二、构造函数注入
构造器注入使用constructor-arg标签作为标识。同样具有于属性注入相同的方式,使用name、ref、value作为构造器注入的属性,如下:
程序的代码如下:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person Friend { get; set; }
}
PersonDao
public class PersonDao
{
private Person argPerson;
private int intProp;
public PersonDao(Person argPerson, int intProp)
{
son = argPerson;
p = intProp;
}
public void Get()
{
//构造函数注入的整型参数
ine(("intProp:{0}", intProp));
//构造函数注入的Person
ine(("argPerson Name:{0}", ));
ine(("argPerson Age:{0}", ));
//内联对象Friend
ine(("argPerson Friend Name:{0}", ));
ine(("argPerson Friend Age:{0}", ));
//内联对象的循环引用
ine(("argPerson Friend Friend Name:{0}", ));
ine(("argPerson Friend Friend Age:{0}", ));
}
}
/>
Program
class Program
{
static void Main(string[] args)
{
IApplicationContext ctx = text();
PersonDao dao = ect("personDao") as PersonDao;
();
ne();
}
}
输出效果如下:
教程(八)集合类型的注入(基础篇)
还支持集合类型的注入。而且使用起来也比较方便。
一、ILIst类型
使用
在元素中设置 element-type 属性表示泛型T的类型,例如 element-type="int" ,代表int型。
二、IDictionary类型
使用
同理,
完整代码如下:
Domain
public class Happy
{
public override string ToString()
{
return "每天都开心,每天都有好心情";
}
}
public class OneYear
{
public override string ToString()
{
return "快乐的一年";
}
}
public class Person
{
public IList
public IList HappyYears { get; set; }
public IList
IDictionary,例如 public IDictionary HappyDic { get; set; } public IDictionary } />
Program
class Program
{
static void Main(string[] args)
{
IApplicationContext ctx = text();
Person person = ect("person") as Person;
ine("空值");
string bestFriend = iends == null ? "我的朋友太多了"ine(bestFriend);
ine();
ine("IList");
foreach (var item in ears)
{
ine(item);
}
ine();
ine("泛型Ilist
foreach (int item in )
{
ine(item);
}
ine();
ine("IDictionary");
foreach (DictionaryEntry item in ic)
{
ine( + " 是 " + );
}
ine();
ine("泛型IDictionary
foreach (KeyValuePair
{
: "我只有一个好朋友";
ine( + " 是 " + );
}
ne();
}
}
输入结果如下:
教程(九)打造简易的依赖注入框架(练习篇)
我们在第三篇中学习里一个简易的IoC框架。今天我们接着上次的程序,实现带参数构造函数对象的实例和属性的注入。
我们知道可以通过反射获取类的构造函数及参数(GetConstructors方法);可以获取属性和属性的类型(GetProperties方法)。通过Activator的CreateInstance(Type type, params object[] args)方法可以创建带参数构造函数的实例。通过SetValue方法可以给属性赋值,这
样一来,我们就上次的代码稍加改造就可以实现属性的注入了。
下面是完成的代码:
Domain
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class PersonDao
{
private int intProp;
public PersonDao(int intProp)
{
p = intProp;
}
public Person Entity { get; set; }
public override string ToString()
{
return "构造函数参数intProp为:" + p;
}
}
ObjectFactory
public class ObjectFactory
{
private IDictionary
private ObjectFactory(string fileName)
{
InstanceObjects(fileName);// 实例IoC容器
DiObjects(fileName);// 属性注入
}
new Dictionary
private static ObjectFactory instance;
private static object lockHelper = new object();
public static ObjectFactory Instance(string fileName)
{
if (instance == null)
{
lock (lockHelper)
{
instance = instance ?? new ObjectFactory(fileName);
}
}
return instance;
}
/**////
/// 实例IoC容器
///
///
private void InstanceObjects(string fileName)
{
XElement root = (fileName);
var objects = from obj in ts("object")
select obj;
//无参构造函数
objectDefine = (obj =>
t("constructor-arg") == null).ToDictionary(
k => ute("id").Value,
v =>
{
string typeName = ute("type").Value;
Type type = e(typeName);
return Instance(type);
}
);
//有参构造函数
foreach (XElement item in (obj =>
t("constructor-arg") != null))
{
string id = ute("id").Value;
string typeName = ute("type").Value;
Type type = e(typeName);
var args = from property in structors()[0].GetParameters()
join el in ts("constructor-arg")
on equals ute("name").Value
select Type(ute("value").Value,
terType);
object obj = Instance(type, y());
(id, obj);
}
}
/**////
/// 属性注入
///
///
private void DiObjects(string fileName)
{
XElement root = (fileName);
var objects = from obj in ts("object")
select obj;
foreach (KeyValuePair
{
foreach (var el in (e =>
ute("id").Value == ).Elements("property"))
{
Type type = e();
//获取属性
foreach (PropertyInfo property in perties())
{
if ( == ute("name").Value)
{
if (ute("value") != null)
{
//设置属性值
ue(,
Type(ute("value").Value,
tyType), null);
}
else if (ute("ref") != null)
{
object refObject = null;
if (nsKey(ute("ref").Value))
{
refObject = objectDefine[ute("ref").Value];
}
//设置关联对象属性
ue(, refObject, null);
}
}
}
}
}
}
/**////
/// 获取对象
///
///
///
public object GetObject(string id)
{
object result = null;
if (nsKey(id))
{
result = objectDefine[id];
}
return result;
}
}
Program
class Program
{
static void Main(string[] args)
{
ObjectFactory factory
ce(@"F:ExerciseSpringNetStep1SpringNet_");
PersonDao dao = (PersonDao)ect("personDao");
ine("姓名:" + );
ine("年龄:" + );
ine(dao);
ne();
}
}
输入结果:
=
教程(十)方法的注入(基础篇)
多数用户都会将容器中的大部分对象布署为singleton模式。当一个singleton对象需要和另一个singleton对象协作,或者一个非singleton对象需要和另一个非singleson对象协作时,都能很好的处理它们的依赖关系。但是,如果对象的生存周期不同,就可能会产生问题。例如,假设一个singleton对象A要使用一个非singleton(原型)对象B,A中的每个方法都会用到B的新实例。由于 A是singleton对象,容器只有会创建它一次,也就是说只有一次给A的属性赋值的机会,所以不可能在每次A需要的时候都给它注入一个新的B。
有一种解决的办法有点违背控制反转原则:类A可以通过实现IObjectFactoryAware接口来获取容器的引用,并调用GetObject("B")在每次需要的时候从容器中请求一个(新的)对象B。但这并不是一个很好的解决方案,因为客户代码此时必须要和发生紧耦合。
通过方法注入,我们可以用更优雅的方式解决类似的问题。(摘自中文手册)
一、查询方法注入
可以动态覆盖对象的抽象方法或虚方法,并且可以在容器内查找已命名对象,查询方法注入就利用了这些功能。个人感觉查询方法注入类似抽象工厂,为之不同的是,可以不用写抽象的实现代码,通过配置文件动态的切换组件。
在lookup-method节点配置name和object属性
实现代码如下:
LookupMethod
//注意,可以直接在配置中定义这个类的对象
public abstract class ObjectFactory
{
//或者可以是一个虚方法
public abstract PersonDao CreatePersonDao();
}
public class PersonDao
{
public void Save()
{
ine("保存数据");
}
}
二、替换任意方法
替换任意方法在项目中使用的很少,实现方法也比较复杂。至于为什么使用替换任意方法,我还不是很清楚,如果有知
道使用场景的朋友可以给我留言。我个人认为其用途是:实现非派生类方法的重写或在IoC框架中简易的AOP拦截(这一点又不确定,以后我会写AOP方面的博客)。
首先继承IMethodReplacer接口并实现Implement方法,object[] arguments为传入的参数。其次在replaced-method节点配置name和replacer属性,和增加arg-type节点且配置返回类型match属性
代码如下:
ReplacedMethod
public class UserDao
{
//虚方法
public virtual string GetValue(string input)
{
return null;
}
}
//实现IMethodReplacer接口
public class ReplaceValue : IMethodReplacer
{
public object Implement(object target, MethodInfo method, object[] arguments)
{
string value = (string)arguments[0];
return "获取到:" + value;
}
}
三、事件注入
在的IoC框架中,除了提供方法注入以外,还提供事件的注入。通过事件的注入,可以使架构体系的耦合降到最低。(参考 clingingboy的 学习笔记(3)-注册事件注入)
在listener节点处配置event和method属性指明事件名和绑定的方法,并增加ref节点设置object属性来指明调用哪个IoC容器对象。
实现代码:
Listener
//先定义一个委托
public delegate string OpenHandler(string arg);
public class Door
{
public event OpenHandler OpenTheDoor;
public void OnOpen(string arg)
{
//调用事件
if (OpenTheDoor != null)
{
ine(OpenTheDoor(arg));
}
}
}
public class Men
{
public string OpenThisDoor(string arg)
{
return "参数是:" + arg;
}
}
调用部分代码:
Program
class Program
{
static void Main(string[] args)
{
IApplicationContext ctx = text();
ine("查询方法");
ObjectFactory factory = (ObjectFactory)ect("objectFactory");
PersonDao().Save();
ine();
ine("替换方法");
UserDao dao = (UserDao)ect("userDao");
ine(ue("Liu Dong"));
ine();
ine("事件注册");
Door door = (Door)ect("door");
("Opening!");
ine();
ne();
}
}
输入效果:
教程(十一)自定义对象行为(基础篇)
通过几个专门的接口来控制容器中对象的行为。说到对象的行为无非就要提到对象的生命周期控制。类似在WinForm开发,Form生命周期中,Load方法为Form的载入方法和Dispose方法为Form的销毁方法。都能完美的实现这些需求。
一、生命周期接口
在使用框架的时候通常遇到怎样初始化和销毁非托管资源(如数据库连接)的麻烦,下面的解决方案可能对您有所帮助。
1.初始化行为
继承alizingObject接口或者配置object节点的init-method属性,的IoC框架就会帮我们在该对象被实例后调用配置好的初始化方法。
2.销毁行为
继承sable接口或者在object节点配置destroy-method属性,会帮我们在容器被销毁时调用它。
实现代码:
Person
public class Person
{
public void Init()
{
ine("我长大了");
}
public void Destroy()
{
ine("我衰老了");
}
}
init-method="Init" destroy-method="Destroy" /> 二、抽象对象定义和子对象定义 对象定义可能会包含大量的信息,比如与容器相关的信息(即初始化方法、静态工厂方法名等)、构造器参数和属性值等。子对象定义是指从一个父对象定义中继承了配置数据的对象定义。子对象定义可以根据需要重写或添加某些配置的值。使用父对象和子对象的定义方式可能会节省大量的键入工作。实际上这是设计模式中模板模式的一种形式。个人认为可以解决“子类”与“父类”之间的耦合。 在object节点中设置parent属性来指明是继承关系,而并非正真意义的继承。 实现代码:
public abstract class Parent
{
public string Name { get; set; }
}
public class Child
{
public string Name { get; set; }
}
我们可以看出Child类并没有继承Parent类。
输出效果:
教程(十二)面向切面编程(基础篇)
AOP即面向切面编程(ASPect Oriented Programming的缩写),是OOP(面向对象编程)的一种延续形式。是通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术,它从一个不同于OOP的角度来看待程序的结构:OOP将应用程序分解为一系列表现为继承关系的对象;AOP 则把程序分解为一系列方面(aspects)或者关注点(concerns)。AOP将诸如事务管理等本来横向分布在多个对象中的关注点进行了模块化处理(这些关注点也常称为横切(crosscutting)关注点)。在中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的完成业务逻辑仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
下面我举个例子来说明这一切:
场景:业务类CompanyManager在调用Save方法的时候需要调用SecurityManager类判断权限是否足够(图1)。
图1
准备条件:
public class CompanyDao
{
public void Save()
{
ine("保存数据");
}
}
public interface ICompanyManager
{
string UserName { get; set; }
void Save();
}
public interface ISecurityManager
{
bool IsPass(string userName);
}
SecurityManager
public class SecurityManager : ISecurityManager
{
/**////
/// 判断权限
///
///
///
public bool IsPass(string userName)
{
return userName == "admin";
}
}
第一种实现方式,我们通常会这样做:直接在CompanyManager类中调用ISecurityManager接口的IsPass方法判断权限。
SimpleCompanyManager
public class SimpleCompanyManager : ICompanyManager
{
可通过外部注入的属性#region 可通过外部注入的属性
public string UserName { get; set; }
public CompanyDao Dao { get; set; }
#endregion
public void Save()
版权声明:本文标题:Spring.net教程 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1705120642a473594.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论