[转载]ASP.NET MVC路由匹配检测组件RouteDebug.dll

mikel阅读(1172)

[转载]ASP.NET MVC路由匹配检测组件RouteDebug.dll – Capricornus – 博客园.

以前使用RouteMonitor.dll进行MVC路由检测URL路径的映射匹配情况。由于公司电脑没有此组件,所以上网搜了下,结果才发现RouteMonitor.dll已经将名称改为了RouteDebug.dll 。具体参阅 官方网站。 下载地址:http://files.cnblogs.com/Capricornus/RouteDebug-Binary.zip

使用方法:

1. 在MVC项目中添加引用此组件

2. 在全局应用程序类Global.asax.cs中设置代码

3.匹配路由如下图:


我们可以使用Reflector反编译这个RouteDebugger.dll组件,查看一下原理。如图:

RouteDebug中包含了DebugHttpHandler、DebugRoute、DebugRouteHandler、RouteDebugger这4个类。

首先从我们调用RouteDebug.RouteDebugger.RewriteRoutesForTesting的着手。


RouteDebugger类:

首先,整个代码是使用System.Web.Routing命名空间下的RouteCollection.GetReadLock()锁定的,提供 一个对象,用于管理在从集合中检索对象时的线程安全性;然后遍历我们传过来的路由集合参数。用RouteDebug中的 DebugRouteHandler去替换原有RouteHandler,以便改变Http处理程序的方向,接着将Singletion属性的值添加到路 由结合中。


DebugRoute类:

DebugRoute继承与Route类,构造函数实现了构造可捕获所有URL地址的Route。


DebugRouteHandler路由处理程序类:

实现IHttpHanlder接口的实例化对象,传入了一个RequestContext对象实例。


DebugHttpHandler类:

通过ProcessRequest方法来处理请求,最后呈现在路由检测的页面上。

首先从RequestContext.RouteData可以得到RouteData类,RouteData类包含所请求路由的相关值。从 RouteData.Values获取路由的URL参数值和默认值集合,在从RouteData.Route获取路由的对象,在获取有关集合中与指定值匹 配的路由信息.

[转载]w3wp进程发生死锁ISAPI '..\aspnet_isapi.dll' 报告它自身有问题,原因'Deadlock detected'

mikel阅读(1178)

[转载]w3wp进程发生死锁ISAPI ‘..\aspnet_isapi.dll’ 报告它自身有问题,原因’Deadlock detected’ – 欢迎光临赵玉开的技术博客 – 博客园.

ISAPI ‘c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll’ 报告它自身有问题,原因如下: ‘Deadlock detected’

这个问题,字面意思是程序发生死锁了,它会导致w3wp进程重启。通常这个问题不好查到原因。我知道两个可能导致此问题的实例

1. 在程序中使用了lock或者ReaderWriterLock,锁资源发生了争用
下面是一小段代码:

1 //_rwLock的类型是ReaderWriterLock
2 _rwLock.AcquireWriterLock(100);
3 DoSomething();
4 _rwLock.ReleaseWriterLock();

这行代码是有问题的,如果在DoSomething()方法执行中发生一次异常,这个写锁就释放不了了,再次请求时就会等待直到超时,在多线程的情况下就会发生死锁’Deadlock detected’
正确的写法应该是:

01 try
02 {
03 _rwLock.AcquireWriterLock(100);
04 DoSomething();
05 }
06 finally
07 {
08 if (_rwLock.IsWriterLockHeld)
09 _rwLock.ReleaseWriterLock();
10 }

这样就算在DoSomething方法执行时发生了异常,也可以释放写锁。

2. 数据库连接的超时时间设置的很长而在设定的超时时间之内连接耗尽了,再次要求打开数据库连接时也可能会出现此问题。这个是数据库连接串的配置问题,超时时间要设置的适当,不要过长。

发生这个问题时的日志写的很笼统:
ISAPI ‘c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll’ 报告它自身有问题,原因如下: ‘Deadlock detected’。

有关更多信息,请参阅在 http://go.microsoft.com/fwlink/events.asp 的帮助和支持中心。

这样导致不容易找到问题发生在哪块,所以我记录两种发生此问题的实例,希望有用。

[转载]ASP.NET MVC Routing概述 (C#)

mikel阅读(952)

[转载]ASP.NET MVC Routing概述 (C#) – JasenKin – 博客园.

                                           ASP.NET MVC Routing概述

ASP.NET Routing模块的责任是将传入的浏览器请求映射为特有的MVC controller actions。

使用默认的Route Table
当你创建一个新的ASP.NET MVC应用程序,这个应用程序已经被配置用来使用ASP.NET Routing。 ASP.NET Routing 在2个地方设置。第一个,ASP.NET Routing 在你的应用程序中的Web配置文件(Web.config文件)是有效的。在配置文件中有4个与routing相关的代码片 段:system.web.httpModules代码段,system.web.httpHandlers 代码段,system.webserver.modules代码段以及 system.webserver.handlers代码段。千万注意不要删除这些代码段,如果没有这些代码段,routing将不再运行。第二个,更重 要的,route  table在应用程序的Global.asax文件中创建。这个Global.asax文件是一个特殊的文件,它包含ASP.NET 应用程序生命周期events的event handlers。这个route  table在应用程序的起始event中创将。

       在Listing 1中包含ASP.NET MVC应用程序的默认Global.asax文件.

Listing 1 – Global.asax.cs

 1 public class MvcApplication : System.Web.HttpApplication
 2     {
 3         public static void RegisterRoutes(RouteCollection routes)
 4         {
 5             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 6             routes.MapRoute(
 7                 "Default", // 路由名称
 8                 "{controller}/{action}/{id}", // 带有参数的 URL
 9                 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
10             );
11
12         }
13
14         protected void Application_Start()
15         {
16             AreaRegistration.RegisterAllAreas();
17
18             RegisterRoutes(RouteTable.Routes);
19         }
20     }

当一个MVC应用程序第一个启动,Application_Start() 方法被调用,这个方法反过来调用RegisterRoutes() 方法。

这个默认的route table包含一个单一的route。这个默认的route将url的第一个段映射为一个controller名称,url的第二个段映射为一个controller action,第三个段映射为命名为id的参数。
假如,你在网页浏览器的地址栏中键入下面的url:/Home/Index/3,这个默认的route将这个url映射为下面的参数:
controller = Home controller名称

action = Index controller action

id = 3 id的参数

当你请求/Home/Index/3这样的url,下面的代码将执行。HomeController.Index(3)

这个默认的route包含3个默认的参数。如果你没有提供一个 controller,那么 controller默认为Home。同样,action默认为Index,id参数默认为空字符串。
让我们来看一些关于默认的route怎么映射urls为controller actions的例子。假如你在你的浏览器地址栏中输入如下的url:/Home, 由于这些默认的route参数有一些相关的默认值,键入这样的URL,将导致HomeController类的Index()方法(如Listing 2)被调用。

1 namespace MvcRoutingApp.Controllers
 2 {
 3     [HandleError]
 4     public class HomeController : Controller
 5     {
 6         public ActionResult Index(string id)
 7         {
 8             ViewData["Message"] = "欢迎使用 ASP.NET MVC!";
 9
10             return View();
11         }
12
13         public ActionResult About()
14         {
15             return View();
16         }
17     }
18 }
19

在Listing 2中,这个HomeController 类包含一个名为Index()的方法。这个URL /Home导致Index()方法被调用,一个空的字符串将作为id参数的值。由于mvc框架调用controller actions的这种方式,这个URL /Home同样匹配HomeController类中的Index()方法(如Listing 3)。
Listing 3 – HomeController.cs (Index action with no parameter)

[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}

在Listing 3中,这个Index()方法不接收任何参数。这个URL /Home将导致Index()方法被调用。URL /Home/Index/3同样调用这个方法(ID被忽略)。
Listing 4 – HomeController.cs (Index action with nullable parameter)
[HandleError]
public class HomeController : Controller
{
public ActionResult Index(int? id)
{
return View();
}
}

在Listing 4中, Index() 方法有一个整数参数. 由于这个参数是可空参数 ,  Index() 将被调用而不引起错误.

最后, 使用 URL /Home 来调用如Listing 5中的Index() 方法 将导致异常,因为这个ID参数不是一个可空的参数。如果你试图去调用这个Index()方法,你将获得如下图所示的错误。

Listing 5 – HomeController.cs (Index action with Id parameter)
[HandleError]
public class HomeController : Controller
{
public ActionResult Index(int id)
{
return View();
}
}

另一方面,使用如Listing 5中的Index controller action,URL /Home/Index/3运行正常。Index controller action in Listing 5. /Home/Index/3请求将导致Index()方法被调用,ID参数拥有一个3的值。

总结


这是一个关于ASP.NET Routing的简要介绍. 应该了解了这个默认的route如何将URLs映射为controller actions。
创建自定义的Routes (C#)

这个教程,你将学会怎样添加一个自定义的route到一个ASP.NET MVC应用程序。你将学会在Global.asax文件中,怎样使用一个自定义的route来修改这个默认的route table。
对于许多简单的ASP.NET MVC 应用程序,这个默认的route  table将运行得很好。然而,你可能发现,你可能特定的routing 需求。那样的话,你可能需要创建一个自定义的route。
设想一下,例如,你正在建立一个博客应用程序,你可能想要去处理像/Archive/12-25-2009的输入请求。
当一个用户键入这个请求,你想要返回与日期为12/25/2009相符的博客实体。为了处理这种类型的请求,你需要去创建一个自定义的route。
在 Listing 1中,这个Global.asax文件中包含一个新的名为Blog的自定义route,它处理类似于/Archive/entry date的请求。
Listing 1 – Global.asax (with custom route)

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Web.Mvc;
 6 using System.Web.Routing;
 7 
 8 namespace MvcRoutingApp
 9 {
10     // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
11     // 请访问 http://go.microsoft.com/?LinkId=9394801
12 
13     public class MvcApplication : System.Web.HttpApplication
14     {
15         public static void RegisterRoutes(RouteCollection routes)
16         {
17             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
18             routes.MapRoute(
19                 "Blog", // 路由名称
20                 "Archive/{entryDate}/{id}", // 带有参数的 URL
21                 new { controller = "Archive", action = "Entry", id = UrlParameter.Optional } // 参数默认值
22             );
23             routes.MapRoute(
24                 "Default", // 路由名称
25                 "{controller}/{action}/{id}", // 带有参数的 URL
26                 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
27             );
28 
29         }
30 
31         protected void Application_Start()
32         {
33             AreaRegistration.RegisterAllAreas();
34 
35             RegisterRoutes(RouteTable.Routes);
36         }
37     }
38 }

你添加到route table的routes的顺序是很重要的。我们新自定义的blog route在现存的默认route之前添加。如果你颠倒了顺序,那么这个默认的route总是先调用而不是这个自定义的route。
这个自定义的blog toute匹配任何以 /Archive/ 开头的请求。所以,它匹配所有下列URLs:
/Archive/12-25-2009

/Archive/10-6-2004

/Archive/apple

这个自定义的route将输入的请求映射至名为Archive的controller,并且调用 Entry() action。当 Entry() action被调用的时候,这个输入的日期被当作名为entryDate的参数。
Listing 2 – ArchiveController.cs
public class ArchiveController : Controller
{

public string Entry(DateTime entryDate)
{
return “You requested the date:” + entryDate.ToString();
}

}

注意,在Listing 2中这个Entry()方法接收一个类型为DateTime的参数。MVC框架是足够智能的,它自动将URL中输入的date转换为一个DateTime值。如果URL中输入的date不能转换为DateTime,错误将被引发。

总结
这个教程演示怎样来创建一个自定义的route。你学会了怎样在Global.asax 文件中添加一个自定义的route到route table。我们讨论了怎样为blog实体将请求映射为名为ArchiveController的controller,名为Entry()的controller action。

[转载]c# 中内部类的简单介绍

mikel阅读(1075)

[转载]c# 中内部类的简单介绍 – 情缘 – 博客园.

最近在看java一方面的书籍,看到一个很奇怪的问题,java类中还可以再定义一个类,这种结构非常特殊!后来才发现我知识浅薄了,原来C#中也有内部类,之前都一直没有注意过这个语法结构!

使用内部类有这样几个好处:

(1)抽象外部类的某一状态下的行为,隐藏实现,通过修改该内的访问修饰符,可以设置仅有外部类可以访问该类

(2)扩展了命名空间,可以将外部类的类名作为内部类的一个命名空间(这里只是相当于,但不是真正的命名空间)

(3)内部类可以当作外部类的一个扩展,可以活的更好的封装。

上面的这些特点胡乱的总结了一下,可能有些词不达意,下面有些具体例子:

1.内部类的定义:

嵌套类:在一个类中定义另外一个类,主要分为静态嵌套类和非静态嵌套类(又称之为”内部类”)

内部类的定义结构:(1)在一个类中直接定义类(2)在一个方法中定义类(3)匿名内部类

2.外部类访问内部类

外部类访问内部类 例子

该段代码定义了一个外部类Person 和一个内部类Student, 其中内部类Student中使用了各种修饰符修饰的变量和方法,从上面的例子可以看出外部类只能够访问嵌套类中修饰符为public、internal的字段、方法、属性。

调用外部类的 Show()方法运行得到如下结果:

3.内部类访问外部类

内部类访问外部类 例子

1 namespace GameStatistical.Test.InnerClass
2 {
3 public class Person1
4 {
5 private string name;
6
7 public string Name
8 {
9 get { return name; }
10 set { name = value; }
11 }
12 private string sex;
13
14 public string Sex
15 {
16 get { return sex; }
17 set { sex = value; }
18 }
19
20 public void Show1()
21 {
22 Console.WriteLine(this.name + ==> + this.sex);
23 }
24
25 private static void Show2()
26 {
27 Console.WriteLine(===================>);
28 }
29
30 internal void Show3()
31 {
32 Console.WriteLine(this.name + ==> + this.sex);
33 }
34
35
36
37 public class Student
38 {
39 public void SetPer(string name, string sex)
40 {
41 Person1 p = new Person1();
42 p.name = name;
43 p.sex = sex;
44
45 p.Show3();
46 p.Show1();
47 }
48
49 }
50 }
51 }

这段代码同样定义了一个外部类Person1 和一个内部类Student,内部类中的SetPer()调用了外部类中的方法,写这段代码我们可以发现 嵌套类可以访问外部类的方法、属性、字段而不受访问修饰符的限制

4.内部类的继承

内部类继承例子1

1 namespace GameStatistical.Test.InnerClass
2 {
3 public class Person
4 {
5 public class Student
6 {
7 public static int age;
8 internal static int height;
9 private static string sex;
10
11 public virtual void Show()
12 {
13 Console.WriteLine(年龄:+age);
14 Console.WriteLine(身高:+height);
15 }
16
17 internal void Display()
18 {
19 Console.WriteLine(internal);
20 Console.WriteLine(年龄: + age);
21 Console.WriteLine(身高: + height);
22 }
23 }
24
25
26 public void Show()
27 {
28 Student.age = 21;
29 Student.height = 75;
30 Student student = new Student();
31 student.Show();
32 student.Display();
33 }
34 }
35 }

内部类继承,上面的内部类定义了父类,其中public virtual void Show() 使用virtual 修饰,可以用于子类重写这个方法,看内部类继承子类是否能够重写这个方法。

内部类继承例子2

1 namespace GameStatistical.Test.InnerClass
2 {
3 public class SubPerson:Person
4 {
5 public class SubStudent : Student
6 {
7 public override void Show()
8 {
9 base.Show();
10 }
11 }
12 }
13 }

上面的代码重写了Show() 这个方法,说明内部类的继承可以通过

5.反射内部类

对于这段代码,是从其他网站看到的,反射内部类我们不能直接通过 “.” 操作符直接来操作,而是通过 “+” 操作符。前面也提到过内部类也是一种有效的管理命名空间的方法,这里也是普通类和内部类的一点区别

反射内部类

Activator.CreateInstance(“GameStatistical.Test.InnerClass”, “GameStatistical.Test.InnerClass.ReflectionPerson+Student”);

反射普通类

Activator.CreateInstance(“GameStatistical.Test.InnerClass”, “GameStatistical.Test.InnerClass.ReflectionPerson.Student”);

在实际操作中,内部类好像使用的比较少,这里也只是非常简单的介绍,作为一个知识点总结起来。

[转载]JqueryNet—NJquery

mikel阅读(1125)

[转载]JqueryNet—NJquery – NSun快速开发 – 博客园.

Jquery可以说是非常成功的js框架,简单的操作就可以完成复杂的DOM操作。对DOM对象操作方法的封装是它成功的把很多对

象的共性提取转化为Jquery对象的通用操作方法。比如:所有对象的属性操作都可以用attr来完成对象的样式操作可以用css这

样的方法来完成,提取value可以用val方法来完成,隐藏了不同DOM对象的操作形式大大简化了操作的复杂度。

 

      介绍了Jquery为我们带来的方便,那么介绍下jquerynet。顾名思义,jquerynet是基于net以jquery的方式来实现操作,

这里操作的不是DOM对象,而是我们熟悉的asp.net服务器控件,服务器控件一般常见的有2种形式,一种是Htmlcontrol另一

种则是Webcontrol他们都是继承与Control,如果前端人员在其他编辑器中放置好表单元素后我们在控件属性加runat=”server” 

那么这个控件则变为htmlcontrol,当然普通的服务器控件则为webcontrol,有些则直接继承自control。jquerynet是封装这些

控件的操作方法,比如样式、属性、取值、事件。把这些相关的操作实现统一化隐藏他们的差异。当然这样的想法很早就有了,

一直没有去实现它。查过相关的资料,也没有找到相关的项目以及实现。
JqueryNet.JQuery.Get(a).Click("a()");

var c = JqueryNet.JQuery.Get(TextArea1).Val();
Response.Write(c.Value);
var c = JqueryNet.JQuery.Get(show).Children<HtmlInputControl>(p => p.Type == "checkbox");
foreach (var item in (List<HtmlInputControl>)c.Value)
{
     Response.Write(item.ID);
}

JqueryNet.JQuery.Get(FileUpload1).Val(Server.MapPath("~/Scripts") + "//" + FileUpload1.FileName);

var query = JqueryNet.JQuery.Get(Button4);
query.AddClass("t");
query.Height("200px");

JqueryNet.JQuery.Get(Select1).Val().Value);

同样支持方法连写:

JQueryNet.JQuery.Get(Button4).AddClass(“t”).Height(“200px”);

以上为相关的服务器控件操作。如果有兴趣的朋友希望与我联系。

实现比较繁琐,一步步改进中。。

Code URL:http://njquery.codeplex.com

Subversion URL: https://njquery.svn.codeplex.com/svn

[转载]理解MVC应用程序的执行过程

mikel阅读(1184)

[转载]理解MVC应用程序的执行过程 – JasenKin – 博客园.

基于ASP.NET MVC Web应用程序的请求首先通过一个UrlRoutingModule的对象(HTTP模块)。这个模块匹配请求,并且执行路由选择。这个 UrlRoutingModule对象选择第一个匹配当前请求的路由对象。如果没有路径匹配,这个UrlRoutingModule什么也不做,让这个请 求返回给常规的ASP.NET或者IIS来请求处理。

从这个被选中的Route对象,UrlRoutingModule对象获得IRouteHandler对象(IRouteHandler对象与Route 对象是相互关联的)。一般来说,在一个MVC应用程序中,它将是MvcRouteHandler实例。这个IRouteHandler实例创建一个 IHttpHandler对象,并且将它传递给IHttpContext对象。默认情况下,MVC IHttpHandler实例就是MvcHandler对象。然后,这个MvcHandler对象选择controller,controller将最终 提交这个请求。
这个module 和 handler是ASP.NET MVC框架的入口点。它们执行下列行为:

选择合适的controller。
获得一个具体controller实例。
调用controller的执行方法。

下表列出了一个MVC Web项目的执行的各阶段。

阶段 详细
接收应用程序的第一次请求 在Global.asax文件中, Route对象 被添加到RouteTable对象.
执行路由选择 UrlRoutingModule 模块使用第一个在RouteTable 集合中匹配的Route 对象来创建RouteData对象, 然后它将使用这个RouteData对象来创建RequestContext (IHttpContext)对象.
创建MVC request handler MvcRouteHandler 创建MvcHandler类的一个实例,并且将它传递给RequestContext实例.
创建controller MvcHandler对象使用RequestContext实例来确认IControllerFactory 对象(DefaultControllerFactory类的一个实例) ,以用来创建conteoller实例。
执行controller MvcHandler 实例调用controller的执行method.
调用action 大部分controllers 继承自Controller基础类. 与controller相关联的ControllerActionInvoker 对象决定这个controller类的哪个方法将被调用 , 然后再调用那个方法.
执行result 一个典型的action 方法可能接收用户输入,准备合适的响应数据, 然后通过返回一个result的类型来执行这个result. 这个内置的能够执行的result 类型 包含以下类型: ViewResult (它呈现一个视图,并且是最常用的result类型), RedirectToRouteResult, RedirectResult, ContentResult, JsonResult以及EmptyResult.

[转载]工欲善其事必先利其器-简单几步打造顺手的python开发工具(windows,Linux多版本)

mikel阅读(980)

[转载]工欲善其事必先利其器-简单几步打造顺手的python开发工具(windows,Linux多版本) – 懒人居 – Coding for fun – 博客园.

初学一门语言,一般来说第一道门槛是开发工具的选择,以及配置,用记事本写代码写写helloworld尚堪一用,但是一旦需要进行稍微规模大一点的开发立马就捉襟见肘了,所以本文的目的在于给打算学习Python的Tx一个快速入手的指南。

方法零,用EditPlus或者UtralEdit等加强版记事本,语法高亮,ok,但是自动补全,智能感知等就不要想了,杯具,据说某些对IDE有强烈怨念的大牛喜欢这种完全反IDE的方法来开发

方法一,如果你正在使用Eclipse,那么恭喜你,你只需要安装PyDev这个插件就可以了,这个插件可以在

http://pydev.org/ 获得,你也可以通过将urlhttp://pydev.org/updates 加入Eclipse的UpdateManager来安装这个插件。这个插件的特征列表可以在 http://pydev.org/manual_adv_features.html 这个地方找到,功能很全不过智能感知的功能经常抽筋,所以很多时候还是要靠你自己了。

方法二,这个方法我没试过,据说,据说VS.NET直接装上IronPython就可以当作Python的IDE,嗯,有用过的同学可以回复告诉我们使用体验,

方法三 ,windows下的同学可以下载NetBeans的python earlyaccess版本,或者JetBrains的PyCharm(此物据说是测试版,正式版本可能会收费)

方 法四,如果你对全功能的,除了生娃哇什么都能替你完成的superIDE厌倦了,想要更加轻便的,轻巧的,不会动辄好几百M的庞大身躯,一启动好几百M上 G的内存消耗的话,那么一些轻便的IDE可能会更适合你,比如windows下可以用,Ulipad(推荐,国产,Python社区Limodou大牛力 作) ,KomodoEdit(阉割版 KomodoIDE),经过我的试用就这两个比较好用,其余的比如Eric,太复杂了,WindIDE因为要钱所以压根就没看过,SPE到处都是作者要捐 赠的广告-囧。

Ulipad相对来说很好安装,你如果装了WxPython的话。只需要 svn checkout http://ulipad.googlecode.com/svn/trunk/ ulipad-read-only 就可以签出最新版的源代码了,运行只需要 python UliPad.py即可(经过实验,Ulipad在linux下运行会有一些怪异的情况出现,建议在Windows下使用)

KomodoEDIT相对来说麻烦一点,大家可以到官网 http://www.activestate.com/komodo-edit 去下载,这个东西是基于Mozilla的框架很是新鲜,用浏览器做外壳的编辑器,可以和Firefox一样安装插件

方 法五, 如果你懒得连IDE都不想去下载安装,并且是疯狂的DIY分子,那么可以尝试用强力的编辑器自己改装成自己独一无二的酷IDE,代码高亮,自动补全,智能 感知,我所期待的功能一个不少。那么适合的编辑器有超能的Emacs,vim还有图形界面的Gedit。由于Emacs用Lisp做插件,这个我还很 弱,vim本身的命令式编辑我还在适应过程中,所以剩下的就是很有亲和力的Gedit了,这个编辑器是Ubuntu的桌面环境自带的文本编辑器,虽然你刚 装好Ubuntu后打开它看着和记事本一样简洁,但是这个家伙绝对不简单。所以最后我来给大家展示一下用Gedit来构建Python开发工具的过程。

首先,假设我们刚装好了Ubuntu,这个时候在应用程序->附件->文本编辑 就可以打开Gedit了,太简单了,简直和记事本一模一样嘛,如下图:

接下来我们要做的就是安装Gedit的官方插件包,方法是在终端窗口中输入 sudo apt-get install  gedit-plugins

然后我们就可以开始对Gedit进行个性化的配置了,打开  编辑->首选项,如下图:

默认情况下只启动了自动换行,我在这里把所有的勾都打上

然后点击编辑器,进行下一步配置:

在这里我们需要把默认关闭的自动缩进打开,并且将默认的 空格替代制表符的设置从8改成4,文件保存就不用选了,自动备份对svn工作目录下开发会造成很大的困扰的,这个要记得关掉。然后点击字体和颜色:

图里选择的Darkmate的配色方案是我在Gedit的官网下载的,可以把Gedit的编辑区伪造成TextMate的样式,呵呵 ,安装方法很简单,点击添加,找到下载的配色方案xml文件就行了,接下来选插件,进入功能配置

这 里直接把所有的勾上就行了,然后在菜单里就出现了对应的功能,有的作用于编辑区的就会在对应于特定的文件格式自动启动。 这个时候Gedit具备了,代码高亮,自动完成,自动补全还有一堆其他的编辑器功能,但是现在的智能感知不能根据上下文,而是根据当前文件或者打开文件中 的Token来匹配的,为了追求完美的效果,我在Gedit的官网上找到了一个正在开发中的插件,也就是Python 的智能感知插件,这个东西现在还在源码状态,所以只有在Github上去Clone下来,我打了个包放在本文结尾,需要的同学可以自己下载。这个插件安装 很简单,首先开一个终端。然后进入这个目录:

看到那个plugins目录了没,如果没有这个目录就mkdir plugins。如果有就把下载的插件cp进去就行了。cp进去了后重新打开Gedit,在插件那个地方就能看到这个插件了,到哪里打上勾就能用了。

最后再开启侧栏和底栏后我们来看看成品:

插件下载地址:/Files/Alexander-Lee/geditpycompletion_src.tar.gz.zip 由于不能上传.tar.gz的文件所以请在下载后把.zip去掉再解压

[转载]spring依赖注入

mikel阅读(1201)

[转载]spring依赖注入 – C’est la vie – 博客园.

使用构造器注入

使用属性setter方法注入

使用Field注入(用于注解方式)

注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。

1.手工装配依赖对象

手工装配依赖对象,在这种方式中又有两种编程方式

*  在xml配置文件中,通过在bean节点下配置

*  在java代码中使用@Autowired或@Resource注解方式进行装配

依赖注入–手工装配–XML方式

通过setter方法注入依赖

<bean>元素的< property >子元素指明了使用它们的set方法来注入。可以注入任何东西,从基本类型到集合类,甚至是应用系统的bean。

通过setter方法注入依赖

*   简单bean配置

配置bean的简单属性,基本数据类型和String。

<beanid=”personService” class=”com.test.bean.impl.PersonServiceImpl”>

<!– 基本类型,string类型 –>

<propertyname=”age”value=”20″></property>

<propertyname=”name” value=”张无忌”></property>

</bean>

通过setter方法注入依赖

*引用其它bean

<beanid=”person”class=”com.test.bean.Person” />

<beanid=”personService”

class=”com.test.bean.impl.PersonServiceImpl”>

<!– 引用类型 –>

<propertyname=”person” ref=”person” />

</bean>

* 内部bean

<beanid=”personService”class=”com.test.bean.impl.PersonServiceImpl”>

<!– 内部bean注入 –>

<propertyname=”personClass”>

<beanclass=”com.test.bean.PersonClass” />

</propert>

</bean>

这种方式的缺点是你无法在其它地方重用这个personClass实例,原因是它是专门为personService而用。

*装配集合

若bean的属性是集合类型,按如下处理:

A、装配List和数组:

<!– 装配list –>

<propertyname=”lists”>

<list>

<value>list1</value>

<value>list2</value>

<refbean=”person”/>

</list>

</property>

<!–装配数组 –>

<property name=”obj”>

<list>

<value>obj1</value>

<value>obj2</value>

<refbean=”person”/>

</list>

</property>

B、 装配set:

<!–装配set –>

<property name=”sets”>

<set>

<value>set1</value>

<value>set2</value>

<refbean=”person”/>

</set>

</property>

set使用方法和list一样,不同的是对象被装配到set中,而list是装配到List或数组中装配。

*装配集合

C、装配map:

<!– 装配map–>

<propertyname=”maps”>

<map>

<entrykey=”01″>

<value>map01</value>

</entry>

<entrykey=”02″>

<value>map02</value>

</entry>

</map>

</property>

map中的<entry>的数值和<list>以及<set>的一样,可以使任何有效的属性元素,需要注意的是key值必须是String的。

D、装配Properties:

<!–装配Properties  –>

<property name=”props”>

<props>

<prop key=”01″>prop1</prop>

<prop key=”02″>prop2</prop>

</props>

</property>

E、设置null:

<!–装配null –>

<property name=”listnull”>

<null/>

</property>

通过参数的顺序:

<constructor-argindex=”0″>

<value>张三</value>

</constructor-arg>

<constructor-argindex=”1″>

<value>56</value>

</constructor-arg>

通过构造函数注入依赖

<!–通过参数的类型 –>

<constructor-argtype=”java.lang.Integer”>

<value>56</value>

</constructor-arg>

<constructor-argtype=”java.lang.String”>

<value>张三</value>

</constructor-arg>

依赖注入–手工装配—注解方式

在java代码中使用@Autowired或@Resource注解方式进行装配的前提条件是。

1、引入context命名空间 需要在xml配置文件中配置以下信息:

<beansxmlns=”http://www.springframework.org/schema/beans”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xmlns:context=”http://www.springframework.org/schema/context”

xsi:schemaLocation=”http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd”>

<context:annotation-config/>

</beans>

2、在配置文件中添加context:annotation-config标签

<context:annotation-config/>

这个配置隐式注册了多个对注释进行解析处理的处理器

AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,

PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor

注: @Resource注解在spring安装目录的lib\j2ee\common-annotations.jar

在java代码中使用@Autowired或@Resource注解方式进行装配,这两个注解的区别是:@Autowired 默认按类型装配,

@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。

@Autowired

privatePersonDao  personDao;//用于字段上

@Autowired

publicvoid setPersonDao(PersonDaopersonDao) { //用于属性的set方法上

this.personDao = personDao;

}

@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。

@Autowired(required=false)

privatePersonDao  personDao;//用于字段上

@Autowired(request=false)

public voidsetPersonDao(PersonDaopersonDao) {  //用于属性的set方法上

this.personDao = personDao;

}

如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:

@Autowired@Qualifier(“personDao”)

privatePersonDao  personDao;//用于字段上

@Autowired

publicvoidsetPersonDao(@Qualifier(“personDao”) PersonDao personDao) {//用于属性的set方法上

this.personDao= personDao;

}

@Qualifier注解也能够被指定为构造器的参数或者方法的参数:

@Resource注解和@Autowired一样,也可以标注在字段或属性的setter方法上.

@Resource注解默认按名称装配。

名称可以通过@Resource的name属性指定,如果没有指定name属性,

当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象

当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。

@Resource(name=”personDao”)

privatePersonDaopersonDao;//用于字段上

@Resource(name=”personDao”)

publicvoidsetPersonDao(PersonDao personDao) {//用于属性的set方法上

this.personDao = personDao;

}

后一种相当于xml配置文件中的

<propertyname=“personDao”ref=”personDao” />

注意:如果没有指定name属性,并且按照默认的名称找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。

2.自动装配依赖对象

对于自动装配,大家了解一下就可以了,实在不推荐大家使用。例子:

<beanid=“foo”class=“…Foo” autowire=“autowire type”>

autowire属性取值如下

*  byType:按类型装配,可以根据属性的类型,在容器中寻找跟该类型匹配的bean。如果发现多个,那么将会抛出异常。如果没有找到,即属性值为null。

* byName:按名称装配,可以根据属性的名称,在容器中寻找跟该属性名相同的bean,如果没有找到,即属性值为null。

*constructor与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。

*autodetect :首先尝试使用constructor来自动装配,然后使用byType方式。不确定性的处理与constructor方式和byType方式一致。

通过在classpath自动扫描方式把组件纳入spring容器中管理

前面的例子我们都是使用XML的bean定义来配置组件。在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。

spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了@Component、@Service、@Controller、 @Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。

要使用自动扫描机制,我们需要打开以下配置信息:

1、引入context命名空间 需要在xml配置文件中配置以下信息:

<beansxmlns=”http://www.springframework.org/schema/beans”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xmlns:context=”http://www.springframework.org/schema/context”

xsi:schemaLocation=”http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd”>

<context:component-scanbase-package=”cn.itcast”/>

</beans>

2、在配置文件中添加context:component-scan标签

<context:component-scanbase-package=”cn.itcast”/>

其中base-package为需要扫描的包(含子包)。

注:

1、在使用组件扫描元素时,AutowiredAnnotationBeanPostProcessor和 CommonAnnotationBeanPostProcessor会隐式地被包括进来。 也就是说,连个组件都会被自动检测并织入 – 所有这一切都不需要在XML中提供任何bean配置元数据。

2、功能介绍

@Service用于标注业务层组件、

@Controller用于标注控制层组件(如struts中的action)、

@Repository用于标注数据访问组件,即DAO组件。

而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

//Dao层

importorg.springframework.stereotype.Repository;

importcom.test.dao.PersonDao;

@Repository(“personDao”)

publicclassPersonDaoBean implements PersonDao {

}

//业务层

importjavax.annotation.Resource;

importorg.springframework.stereotype.Service;

importcom.test.dao.PersonDao;

importcom.test.service.PersonService;

@Service(“personService”)

publicclassPersonServiceBean implements PersonService {

@Resource(name=”personDao”)

privatePersonDao personDao;

}

[转载]软件架构师之AOP

mikel阅读(980)

[转载]软件架构师之AOP – 倪大虾 – 博客园.

如果要做为一名合格的软件架构师,AOP是必须知道的一门技术。那么AOP是什么呢,这就是今天所讨论的内容(也是本人最近一阵子的学习总结,希望大家多多指点)。

AOP,全称Aspect Oriented Programming,中文名称叫面向方面编程,也叫面向切面编程

在实际项目开发过程中,我们往往会注意到有一些模块/功能,如权限,缓存等,需要存在于软件的各个业务模块中,而这些模块/功能又与业务模块没有任何关系,甚至在设计业务模块时我们完全不用考虑这些模块/功能的存在,但是在开发过程中才发现这些模块/功能会给我们带来无尽的烦恼。因为传统的OOP方法考虑问题的出发点往往是要解决问题的本身和延伸,所以遇到此类情况时传统的OOP方法就很难解决。然而对业务模块和此类模块稍作分析,我们就会发现,其实它们本质是相同的,只是解决的问题不同,对一个软件的关注点不同,如下图所示:  

结合自己的经验,由图可知,日志,安全,事务等一类的模块在一个软件项目中的位置,AOP要解决的就是此类问题。 AOP的目标便是对这些“横切关注点”和业务模块解耦,从而提升软件的稳定性,扩展性。

AOP通常包含以下主要概念:

  1. 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中横切关注点中一个很好的例子。
  2. 连接点(Joinpoint):程序执行过程中明确的点,如方法的调 用或特定的异常被抛出。
  3. 通知(Advice):在特定的连接点AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
  4. 切入点(Pointcut):指定一个通知将被引发的一系列连接点 的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。
  5. 引入(Introduction):添加方法或字段到通知化类。
  6. 接口(IsModified),来简化缓存。
  7. 目标对象(Target object):包含连接点的对象。也被用来 引用通知化或代理化对象。
  8. AOP代理: AOP框架创建的对象,包含通知。
  9. 织入(Weaving):组装方面创建通知化对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他一些纯 Java AOP框架, 使用运行时织入。

AOP通知类型包括:

  1. Around通知: 包围一个连接点的通知,如方法调用。这是最强大的通知。Aroud通知在方法调用前后完成自定义的行为。它们负责选择继续执行连接点或直接返回它们自己的返回值或抛出异常来短路执行。
  2. Before通知: 在一个连接点之前执行的通知,但这个通知 不能阻止流程继续执行到连接点(除非它抛出一个异常)。
  3. Throws通知: 在方法抛出异常时执行的通知。
  4. After returning通知: 在连接点正常完成后执行的通知, 例如,如果一个方法正常返回,没有抛出异常。
  5. Around通知是最通用的通知类型。大部分基于拦截器的AOP框架如Nanning和JBoss4只提供 Around通知。

通常AOP的关注点有以下几方面:

  1. 权限(Authentication)
  2. 缓存(Cache)
  3. 内容传递(Context passing)
  4. 错误处理(Error handling)
  5. 懒加载(Lazy loading)
  6. 调试(Debug)
  7. 日志(Log)
  8. 跟踪,优化,校准(tracing, profiling and monitoring)
  9. 性能优化(Performance optimization)
  10. 持久化(Persistence)
  11. 资源池(Resource pooling)
  12. 同步(Synchronization)
  13. 事务(Transactions)

了解了AOP的应用场景,下面以权限为例,比较一下传统方法与AOP方法各自的实现,说明AOP技术的应用。

传统方法:

1 BusinessA ClassicsPermission() {
2 if (tag == "Pass") {
3 return new BusinessA();
4 }
5 throw new Exception("你没有权限操作BusinessA.");
6 }

这种是常见的OO做法,它带来以下一些问题:

1、业务逻辑冗余:权限校验过程并不是业务逻辑执行的一部分,这个工作是属于系统的,但是,在这种情况下,我们不得不把系统的权限校验过程和业务逻辑执行过程掺杂在一起,造成混乱。

2、代码冗余:使用这种方法,我们必须所有的业务逻辑代码中包含权限验证代码,使得同样校验的代码充斥在整个软件中,造成代码冗余。

3、紧耦合:使用这种方法,在业务或权限任何一方发生改变时都有可能影响到其他部分,造成耦合。下面所有的问题都是因此而来。

4、不易扩展:依次类推,如果要添加其他横向模块,将导致代码冗余,耦合泛滥,到最后甚至不可收拾;

5、不灵活:使用这种方法,任何一个横向变化都有可能导致代码的修改;

然而,我们利用AOP就可以很方便的解决上述问题,如下

1 [PermissionValidate]
2 class BusinessA { }

上面是AOP的实现方法,可以看到,业务与权限几乎没有关系,上面出现的冗余,耦合问题迎刃而解。

通过上面描述可知,AOP方法解决的是横向问题,那么它是如何实现的呢?答案是代理。代理对于客户,业务都是透明的,只是在其中加入的控制,而这些控制可以根据需求灵活的改变而不影响客户与业务。代理的基本原理如下图:  

由图可知,AOP关注的是aProxy,它将横向业务及变化放在客户与业务的中间,而不影响二者。

综上所述,AOP是一种解决软件中横向问题(公共模块)的思想,为软件架构师解决此类问题提供了一种行之有效的方法。

注:文中部分内容为本人学习时收集整理而来。