把Autofac玩的和javaSpring一樣6


大家好,今天來介紹我開源的一個autofac.Annotation項目 源碼:https://github.com/yuzd/Autofac.Annotation

  • 本項目是autofa的一個擴展組件,autofac是一個老牌的DI容器框架 ,支持netframework和netcore
  • Annotdation是注解的意思,在java項目里面 注解的概念和 csharp里面的 Attribute 的概念是一樣的。

本項目的目的 降低玩DI容器的門檻,快速實現依賴注入 自動裝配 以及攔截器,AOP切面編程

基於參考 Java的 Spring注解方式開發思想,

所有autofac容器的注冊 和 裝配 都是依賴標簽來完成。

這樣一來 一方面很容易分清楚 哪些是DI 哪些非DI, 哪些是攔截器,哪些需要攔截器,輕松實現切面編程, 代碼也好看,吸收java的spring框架的優越的地方,配合.net語法的優越性,編程效率能夠大大提升。

支持的標簽一覽

標簽名稱 使用位置 使用說明
AutoConfiguration 打在class上面 自動裝配class里面帶有Bean標簽的方法
Bean 打在方法上面 配合AutoConfiguration標簽使用
Component 打在class上面 自動注冊
Autowired 打在構造方法的Parameter,類的Property,類的Field 自動裝配
PropertySource 打在class上面 配合Value標簽使用,設置Value的數據源,支持json,xml,支持資源內嵌
Value 打在構造方法的Parameter,類的Property,類的Field 靜態數據裝配,支持強大的EL表達式
Aspect 打在class上面 開啟攔截器,默認注冊為類攔截器,也可以指定為接口型攔截器(和pointcut的區別是它是打在哪個class哪個才會生效)
Pointcut 打在class上面 切面配置,一個切面攔截N多個對象

針對每個標簽的使用文檔 請移步wiki文檔傳送門

https://github.com/yuzd/Autofac.Annotation/wiki

 

下面介紹一下最最常用的功能也就是注冊和自動裝配

 

Componet標簽把類型注冊到DI容器

原理解釋

框架會掃描打了Componet標簽的class。如果Componet標簽里面指定了要注冊的類型,則會只注冊為這個類型到DI容器。如果沒有指定則會把當前class(參考下面的4),以及父類,以及接口都會注冊到DI容器(參考下面的1,2和3)。

如何修改這個默認配置呢,比如關閉自動注冊父類和接口。 可以參考 https://github.com/yuzd/Autofac.Annotation/issues/11

Componet有哪些屬性

屬性名稱 類型 含義
Service Type 注冊指定單個的類型
Key String 注冊指定單個的key(為了同個類型注冊多次避免歧義)
Services Type[] 注冊指定多個的類型
Keys String[] 注冊指定多個的key(如果指定多個類型又想避免歧義可以搭配上面一起使用)
AutofacScope Enum

InstancePerDependency(每次都是一個新實例,默認) SingleInstance(單例)

InstancePerLifetimeScope(每個scope獲取新的實例) InstancePerRequest(根據每個請求一個實例)

可以在插件初始化的時候指定一個默認的 參考下方的截圖說明

AutoActivate bool 當指定Scope為單例的時候 默認false 當DI容器初始化完成后會自動完成實例化
InitMethod string 當實例化后自動執行的方法名稱
DestroyMethod string 當實例會DI容器回收會自動執行的方法名稱
Ownership Enum LifetimeScope(DI容器管理自動回收策略,默認)External(自己手動管理實例回收)
Interceptor Type 指定攔截器類型
InterceptorType Enum Interface(使用接口模式) Class(使用class的虛方法模式)
InterceptorKey string 如果同一個類型的攔截器有多個 可以指定Key
InjectPropertyType Enum 屬性自動裝配的類型 ,Autowired(代表打了Autowired標簽的才會裝配),All(代表全部自動裝配)

Componet的常用構造方法

  1. 默認的構造方法

//默認的構造方法會把當前class,以及父類,以及接口都會注冊到DI容器
//這里只會注冊A8DI容器
[Component]
public class A8
{
   
}

//通過A8類型可以裝配成功
[Autowired]
public A8 A8 { get; set; }

·························································

public class B
{

}

//這里會把A8  B 都注冊到DI容器
[Component]
public class A8B
{
   
}


//通過A8類型可以裝配成功
[Autowired]
public A8 A8 { get; set; }

//通過B類型也可以裝配成功 拿到的是A8類型
[Autowired]
public B B { get; set; }
··························································

public interface IA
{
    
}

public interface IB:IA
{
    
}

public class B:IB
{

}

//這里會把A8  B IB IA 全都注冊到DI容器 
//如果你指向注冊A8 可以參考https://github.com/yuzd/Autofac.Annotation/issues/11 去配置
[Component]
public class A8B
{
   
}


//通過A8類型可以裝配成功 
[Autowired]
public A8 A8 { get; set; }

//通過B類型也可以裝配成功 拿到的是A8類型
[Autowired]
public B B { get; set; }

//通過IB類型也可以裝配成功 拿到的是A8類型
[Autowired]
public IB IB { get; set; }

//通過IA類型也可以裝配成功 拿到的是A8類型
[Autowired]
public IA IA { get; set; }

  1. 注冊為指定類型


public class B
{

}

//這個構造方法就是將A6注冊為B類型 
[Component(typeof(B))]
public class A6:B
{

}

//可以通過下面的方式自動裝配 因為上面注冊的是B類型 通過B類型可以裝配成功 拿到的是A6類型
[Autowired]
public B B { get; set; }

//通過下面的方式自動裝配會失敗 會失敗 會失敗
[Autowired]
public A6 A6 { get; set; }

  1. 同一個注冊類型有多個 采用Key方式解決歧義

public interface ITestAutowiredModal
{
}

// ITestAutowiredModal這個類型被注冊多個了 避免歧義用"abc"來解決
[Component("abc")]
public class TestAutowiredModal1:ITestAutowiredModal
{
}

// ITestAutowiredModal這個類型被注冊多個了 避免歧義用"def"來解決
[Component("def")]
public class TestAutowiredModal2:ITestAutowiredModal
{
}

//可以用下面的方式來自動裝配 拿到的是TestAutowiredModal1類型對象
[Autowired("abc")]
 public ITestAutowiredModal TestAutowiredModal1 { get; set; }

//如果不指定的話會先嘗試根據byType模式匹配,因為是指定了Key 所以根據byType拿不到,拿不到就會再次根據屬性名稱 abc 去匹配,就和上面的方式一樣了 
[Autowired]
 public ITestAutowiredModal abc { get; set; }


//可以用下面的方式來自動裝配 拿到的是TestAutowiredModal2類型對象
[Autowired("def")]
 public ITestAutowiredModal TestAutowiredModal2 { get; set; }
 

1. 把一個類型注冊到DI容器

image

  • 上面的例子就是把Student類型注冊到容器

2. 把當前類型和父類注冊到DI容器

image

  • 上面的例子就是把Student2類型注冊到容器
  • 並且把Person類型也注冊到容器根據Person類型拿到的是Student2的實體

3. 把當前類型和接口注冊到DI容器

image

  • 上面的例子就是把Student3類型注冊到容器
  • 並且把ISay也注冊到容器根據ISay類型拿到的是Student3的實體

4. 當繼承了父類或者接口 想要指定注冊類型怎么辦?

image

  • 上面的例子就是只能通過ISay拿到Student3的實體
  • 不能通過Student3類型拿到!!

5. 怎么指定實例是單例,每次都是新的實例,還是每個Scope一個實例呢?

image

  • 如上圖所示 可以指定AutofacScope屬性
  • 如果不指定就是每次獲取的一個新的實例

6. 當同一個類型多次注冊,如何區分得到我想要的?

image

  • 如上圖 ISay類型有2個實現類 Student3 和 Student4 分別指定了 Key的值
  • 通過ISay + “Student3” 可以獲取到 Student3的實體
  • 通過ISay + “Student4” 可以獲取到 Student4的實體

7.支持注冊類型可以自動實例化對象

image

  • 如上所示,設定AutoActivate = true代表是啟動自動實例化
  • AutofacScope = AutofacScope.SingleInstance 代表單例模式
  • Student5類型會對象會自動實例化 並且以單例的方式存儲在DI容器內

8.支持設置實例化時運行指定方法

image

  • 如上所示 設置 InitMethod 和 DestroyMethod
  • 當實例從DI容器初始化時就會調用 InitMethod
  • 當DI容器Dispose的時候會觸發調用DestroyMethod

另外

image

  • InitMethod支持注入
  • DestroyMethod只能是無參數方法

Autowired自動裝配

Autowired有哪些屬性

屬性名稱 類型 含義
Name String 搭配Component指定Key的時候使用,消除一個類型被多個注冊帶來的歧義
Required bool 默認裝載失敗會報錯 設置為false裝載失敗不會報錯
CircularDependencies bool 是否支持循環注入 默認是false 不支持,插件初始化的時候可以設置一個默認值

 

打在構造方法上 屬性

image

在單例的對象里面Autowired多實例

使用ObjectFactory來實現,和Lazy的區別是 ObjectFactory修飾的每次獲取都是從容器里面獲取一遍。而Lazy只有首次才會去容器獲取。

image

延遲自動裝配Lazy


[Component]
public class TestLazyModel1
{
    [Autowired]
    public Lazy<TestAutowiredModal4> TestAutowiredModal4 { get; set; }
    
    [Autowired]
    public TestAutowiredModal3 TestAutowiredModal3 { get; set; }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM