Spring.Net使用IOC、AOP、屬性注入、構造函數注入以及代碼硬編IOC

 Spring.Net常被來用來作爲IOC容器和AOP工具,今日有空整理了一下,就個人使用的方法做個總結 ,儘量演示的細一點,大家都能看懂。

實現方式:硬編(代碼實現)和配置表兩種。配置文件的演示一下IOC、AOP、構造函數注入、以及屬性注入。

其他的如方法注入、方法替換、事件注入本次暫不作演示。

 

本文章涉及的演示實例下載地址:https://download.csdn.net/download/xuefuruanjian/11390775

 

總結:

1、Spring.Net可以通過接口、抽象類、父類、虛方法進行動態代理

2、可以編程方式也可以使用配置表的方式

3、IOC的時候接口、抽象類、父類、虛方法都可以,但AOP的話,接口、抽象類是沒有問題的,而動態代理父類和類本身的時候,執行方法需要是virtual,纔可以AOP。

 

實現方式:先以配置表來演示,最後以編程的方式(代碼實現)

 

一、配置表方式

配置表先放上來,以下4種演示共用這一份配置。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    </sectionGroup>
  </configSections>

  <spring>
    <!--容器配置-->
    <context>
      <resource uri="config://spring/objects"/>
      <!--xml文件方式,更改屬性,複製到輸出目錄:始終複製-->
      <!--<resource uri="file://~/Config/objects.xml"/>-->
      <!--嵌入程序集方式,assembly://程序集名/項目名/objects.xml,更改屬性,始終複製,生成操作,嵌入的資源-->
      <!--<resource uri="assembly://Spring.Net/Spring.Net/objects.xml"/>-->
    </context>

    <objects xmlns="http://www.springframework.net">
      <description>AOP例子</description>

      <!--id/name 必須要唯一的,type=類的全名稱,所在的程序集-->
      
      <!--攔截通知-->
      <object id="beforeAdvice" type="Spring.Net.Example.Aspects.LogBeforeAdvice,Spring.Net.Example"/>
      <object id="aroundAdvice" type="Spring.Net.Example.Aspects.LogAroundAdvice,Spring.Net.Example"/>
      <object id="afterAdvice" type="Spring.Net.Example.Aspects.LogAfterAdvice,Spring.Net.Example"/>
      <object id="exceptAdvice" type="Spring.Net.Example.Aspects.LogExceptAdvice,Spring.Net.Example"/>
      
      <!--屬性注入-->
      <object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
        <property name="Name" value="王五"/>
        <property name="Age" value="15"/>
      </object>
      
      <!--IOC-->
      <object id="iocStudentA" type="Spring.Net.Example.Commands.StudentA,Spring.Net.Example" />
      <object id="iocStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example" />
      <object id="iocStudentC" type="Spring.Net.Example.Commands.StudentC,Spring.Net.Example" />
      <object id="iocStudentD" type="Spring.Net.Example.Commands.StudentD,Spring.Net.Example" />

      <!--AOP-->
      <object id="aopStudentA" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="Target">
          <object type="Spring.Net.Example.Commands.StudentA, Spring.Net.Example" />
        </property>
        <property name="InterceptorNames">
          <list>
            <value>beforeAdvice</value>
            <value>aroundAdvice</value>
            <value>afterAdvice</value>
            <value>exceptAdvice</value>
          </list>
        </property>
      </object>
      <object id="aopStudentB" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="Target">
          <object type="Spring.Net.Example.Commands.StudentB, Spring.Net.Example" />
        </property>
        <property name="InterceptorNames">
          <list>
            <value>beforeAdvice</value>
            <value>aroundAdvice</value>
            <value>afterAdvice</value>
            <value>exceptAdvice</value>
          </list>
        </property>
      </object>
      <object id="aopStudentC" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="Target">
          <object type="Spring.Net.Example.Commands.StudentC, Spring.Net.Example" />
        </property>
        <property name="InterceptorNames">
          <list>
            <value>beforeAdvice</value>
            <value>aroundAdvice</value>
            <value>afterAdvice</value>
            <value>exceptAdvice</value>
          </list>
        </property>
      </object>
      <object id="aopStudentD" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="Target">
          <object type="Spring.Net.Example.Commands.StudentD, Spring.Net.Example" />
        </property>
        <property name="InterceptorNames">
          <list>
            <value>beforeAdvice</value>
            <value>aroundAdvice</value>
            <value>afterAdvice</value>
            <value>exceptAdvice</value>
          </list>
        </property>
      </object>

      <!--屬性注入-->
      <object id="attrStudentA" type="Spring.Net.Example.Commands.StudentA,Spring.Net.Example">
        <!--ref指向下面的屬性注入-->
        <property name="Friend" ref="UserInfo" />
        <!--<property name="Friend">
          <object type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
            <property name="Name" value="王五"/>
            <property name="Age" value="15"/>
          </object>
        </property>-->
      </object>
      <object id="attrStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example">
        <!--ref指向下面的屬性注入-->
        <property name="Friend" ref="UserInfo" />
      </object>
      <object id="attrStudentC" type="Spring.Net.Example.Commands.StudentC,Spring.Net.Example">
        <property name="Friend" ref="UserInfo" />
      </object>
      <object id="attrStudentD" type="Spring.Net.Example.Commands.StudentD,Spring.Net.Example">
        <property name="Friend" ref="UserInfo" />
      </object>
      
      <!--構造函數注入-->
      <!--autowire="constructor"根據構造函數注入 au-->
      <object id="constructorStudentE" type="Spring.Net.Example.Commands.StudentE,Spring.Net.Example">
        <!--<constructor-arg value="李四" type="string" index="0"/>
        <constructor-arg value="19" type="int" index="1"/>-->
        <constructor-arg index="2" ref="UserInfo"/>
        <constructor-arg index="1" type="int">
          <value><![CDATA[19]]></value>
        </constructor-arg>
        <constructor-arg index="0">
          <value><![CDATA[李四]]></value>
        </constructor-arg>
      </object>
      <object id="constructorStudentF" type="Spring.Net.Example.Commands.StudentF,Spring.Net.Example">
        <constructor-arg value="李四" type="string" index="0"/>
        <constructor-arg value="19" type="int" index="1"/>
        <constructor-arg index="2" ref="UserInfo"/>
      </object>
      <object id="constructorStudentG" type="Spring.Net.Example.Commands.StudentG,Spring.Net.Example">
        <constructor-arg value="李四" type="string" index="0"/>
        <constructor-arg value="19" type="int" index="1"/>
        <constructor-arg index="2" ref="UserInfo"/>
      </object>
      <object id="constructorStudentH" type="Spring.Net.Example.Commands.StudentH,Spring.Net.Example">
        <constructor-arg value="李四" type="string" index="0"/>
        <constructor-arg value="19" type="int" index="1"/>
        <constructor-arg index="2" ref="UserInfo"/>
      </object>
    </objects>
    
  </spring>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

攔截通知類(AOP使用)

namespace Spring.Net.Example.Aspects
{

    public class LogBeforeAdvice : IMethodBeforeAdvice
    {
        public void Before(MethodInfo method, object[] args, object target)
        {
            Console.WriteLine("[執行前通知]攔截的方法名—>" + method.Name);
            Console.WriteLine("[執行前通知]目標—>" + target);
            Console.WriteLine("[執行前通知]參數—>");
            if (args != null)
            {
                foreach (object arg in args)
                {
                    Console.WriteLine("\t: " + arg);
                }
            }
        }
    }



    public class LogAroundAdvice : IMethodInterceptor
    {
        public object Invoke(IMethodInvocation invocation)
        {
            Console.Out.WriteLine(String.Format("[環繞通知]攔截的方法名—> '{0}'", invocation.Method.Name));

            object returnValue = invocation.Proceed();

            Console.Out.WriteLine(String.Format("[環繞通知]返回—> '{0}'", returnValue));

            return returnValue;
        }
    }



    public class LogAfterAdvice : IAfterReturningAdvice
    {
        public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target)
        {
            Console.Out.WriteLine("[執行後通知]攔截的方法名—>" + method.Name);
            Console.Out.WriteLine("[執行後通知]目標—>" + target);
            Console.Out.WriteLine("[執行後通知]參數—>");
            if (args != null)
            {
                foreach (object arg in args)
                {
                    Console.Out.WriteLine("\t: " + arg);
                }
            }
            Console.Out.WriteLine("[執行後通知]返回值—>" + returnValue);
        }
    }



    public class LogExceptAdvice : IThrowsAdvice
    {
        public void AfterThrowing(Exception ex)
        {
            Console.Error.WriteLine($"異常—>{ex.Message}");
        }
    }
}

四個演示所用的接口、抽象類、父類

namespace Spring.Net.Example.Commands
{
    public interface IStudent
    {
        UserInfo Friend { get; set; }
        string Name { get; set; }
        int Age { get; set; }
        void Show();
    }

    public class BaseStudent
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Run()
        {
            Console.WriteLine($"我是父類裏的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }
    
    public abstract class AbstractStudent
    {
        public abstract void Read();
    }
}

 第1、2、3個示例使用的實體類

namespace Spring.Net.Example.Commands
{

    public class StudentA
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }


    public class StudentB : BaseStudent
    {
        public void Show()
        {
            Console.WriteLine($"我是{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }


    public class StudentC : AbstractStudent
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我是{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }

        public override void Read()
        {
            Console.WriteLine($"我是抽象類的重載,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }


    public class StudentD : IStudent
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我實現了接口的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }
}

 

1、IOC容器

接口、抽象類、父類、類IOC實例化實現方式基本一致,配置參考配置表IOC部分,以下爲示例

        static void Main(string[] args)
        {

            //****************IOC***************************

            IApplicationContext context = ContextRegistry.GetContext();

            //實例化類(StudentA可以繼承也可以不繼承都可以實例化)
            StudentA selfCommand = (StudentA)context["iocStudentA"];
            //StudentB selfCommand = (StudentB)context["iocStudentB"];
            //StudentC selfCommand = (StudentC)context["iocStudentC"];
            //StudentD selfCommand = (StudentD)context["iocStudentD"];
            selfCommand.Show();

            Console.WriteLine("--------");

            //實例化父類(StudentB繼承BaseStudent)
            BaseStudent parentCommand = (BaseStudent)context["iocStudentB"];
            parentCommand.Run();

            Console.WriteLine("--------");

            //實例化基類(StudentC繼承AbstractStudent)
            AbstractStudent abstractCommand = (AbstractStudent)context["iocStudentC"];
            abstractCommand.Read();


            Console.WriteLine("--------");

            //實例化接口(StudentD實現接口IStudent)
            IStudent interfaceCommand = (IStudent)context["iocStudentD"];
            interfaceCommand.Show();

            Console.ReadLine();
        }

 執行結果:

 

 

2、實現AOP

通知類在文章的開頭貼出爲了,請參考,配置參考配置表中AOP部分。

特別提醒:

1、Spring.Net爲了不破壞了OO的封裝性,所以沒有實現對字段攔截的支持。

2、代理接口之外的其他代理,如代理類,是隻有虛方法才能代理,同理屬性也是如此,只有virtual的屬性纔可以注入。如果發現已經在配置中配置了構造注入或屬性注入,而得到的代理對象(如下面調用的selfCommand)中,屬性還爲空的話,就要檢查屬性是不是沒有virtual了

3、建議按編程規範,類都實現接口,代理接口最方便。

上層調用如下:

 

    class Program
    {
        static void Main(string[] args)
        {

            //*****************AOP********************************

            IApplicationContext context = ContextRegistry.GetContext();

            //實例化類
            //執行方法爲虛方法時可以AOP
            StudentA selfCommand = (StudentA)context["aopStudentA"];
            //StudentB selfCommand = (StudentB)context["aopStudentB"];    
            //StudentC selfCommand = (StudentC)context["aopStudentC"];    
            //實現了接口的類,不能被代理類本身,可以代理爲接口,如下面第四個(IStudent)context["aopStudentD"]
            //StudentD selfCommand = (StudentD)context["aopStudentD"];    //異常

            selfCommand.Show();

            Console.WriteLine("--------");

            //實例化父類(StudentB繼承BaseStudent)
            //執行方法爲虛方法時可以AOP
            BaseStudent parentCommand = (BaseStudent)context["aopStudentB"];
            parentCommand.Run();

            Console.WriteLine("--------");

            //實例化基類(StudentC繼承AbstractStudent)
            AbstractStudent abstractCommand = (AbstractStudent)context["aopStudentC"];
            abstractCommand.Read();


            Console.WriteLine("--------");

            //實例化接口(StudentD實現接口IStudent)
            IStudent interfaceCommand = (IStudent)context["aopStudentD"];
            interfaceCommand.Show();


            Console.ReadLine();

        }
    }

執行結果

看結果:

AOP的時候,實例化爲(AbstractStudent)context["aopStudentC"]和 (IStudent)context["aopStudentD"]的時候,實現了AOP,而(BaseStudent)context["aopStudentB"] 和實例化成類本身(StudentA)context["aopStudentA"],只執行了方法本身,沒有實現AOP。這是爲什麼呢?是因爲執行的方法都不是虛方法(StudentA.Show()和BaseStudent.Run()),如下:


    public class StudentA
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }

    public class BaseStudent
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Run()
        {
            Console.WriteLine($"我是父類裏的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }

動態代理類或父類,需要執行方法是virtual纔可以AOP(StudentA.Show()和BaseStudent.Run()),現把兩個方法改爲如下:

    public class StudentA
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public virtual void Show()
        {
            Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }

    public class BaseStudent
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public virtual void Run()
        {
            Console.WriteLine($"我是父類裏的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }

結果:

這樣都實現了AOP。

 

AOP的配置屬性也羅列一下,供大家參考:

  • ProxyTargetType:布爾類型,如果目標類是被直接代理的,該屬性爲true;反之則只代理目標類所實現的接口(比如代理某個由接口定義的方法)。(按:目前默認的方式是代理接口)

  • Optimize:是否使用強制優化(aggressive optimization)來創建代理。除非很清楚相關的AOP代理是如何處理優化的,否則不要將其設爲true。這個屬性的確切含義會隨代理的實現方式不同而不盡相同,並且,強制優化通常是對代理的創建時間和運行性能的折衷。優化可能被某些代理實現類所忽略,也可能因其它屬性的某些值而被禁用(在後臺被禁用,不會有任何形式的通知),如ExposeProxy屬性等。

  • IsFrozen:代理工廠配置完成後是否允許改變通知。默認值爲false。

  • ExposeProxy:是否通過AopContext暴露當前代理,以便目標對象能夠訪問自己的代理對象。(若不使用AopContext則可通過IMethodInvocation接口獲得當前代理的引用)如果目標對象需要引用代理,並且ExposeProxy屬性的值爲true,那麼目標對象就可通過AopContext.CurrentProxy屬性獲取當前代理的引用。

  • AopProxyFactory:在生成代理時要使用的IAopProxyFactory實現類。該屬性允許我們選擇AOP代理對象的創建策略:是使用遠程代理還是動態生成IL,或是其它的方式,默認的實現類會使用動態生成IL的方式來創建基於對象組合的代理。

其它屬性包括:

  • ProxyInterfaces:一個字符串數組,用於保存要代理的接口名。(按:即目標類所實現的某個或某些接口。SDK參考文檔上該屬性的類型是void,是錯的)

  • InterceptorNames:一個字符串數組,保存要應用的IAdvisor、攔截器或其它通知的名稱。其中的順序很重要,排在前面的會先處理(按:使用編程方式時,”排在前面“是指後使用AddAdvice方法加入的攔截器)。列表中第一個攔截器會第一個攔截目標調用(當然如果它是MethodInterceptor或BeforeAdvice時)。名稱所指向的對象必須定義在當前容器或父容器中。這裏不能直接引用對象定義,否則IsSingleton屬性就沒有意義了。

  • IntroductionNames:引入通知對象定義的名稱列表。如果某個名稱指向的對象沒有實現IIntroductionAdvisor接口,AOP框架就會創建一個DefaultIntroductionAdvisor的實例並將該名稱分配給這個實例,這樣,引入通知對象的所有方法都會被添加到目標對象中去。如果使用實現了IIntroductionAdvisor的類,就可以精確的控制要引入的接口。

  • IsSingleton:表示工廠是否要返回唯一的代理對象,而不管GetObject方法被調用多少次(部分IFactoryObject的實現類提供了這個方法)。默認值是true。如果要應用基於實例的通知,就要將該屬性設爲false,且IsFrozen屬性也應該爲false。如果需要使用有狀態的通知——例如一個有狀態的、prototype模式的引入通知——就可以將該屬性設爲false。

 

另外需要說明的話是:實現了接口的類,不能被代理成類本身的類型,可以代理爲接口(IStudent)context["aopStudentD"]

            IApplicationContext context = ContextRegistry.GetContext();

            //StudentA selfCommand = (StudentA)context["aopStudentA"];    //正常
            //StudentB selfCommand = (StudentB)context["aopStudentB"];    //正常    
            //StudentC selfCommand = (StudentC)context["aopStudentC"];    //正常 

            //StudentD實現接口IStudent
            StudentD selfCommand = (StudentD)context["aopStudentD"];    //異常
            IStudent interfaceCommand = (IStudent)context["aopStudentD"];    //正常

 

 

創建了對象,如果是簡單對象就到此爲止,如果是複雜對象,則需要爲它的屬性賦值。

屬性賦值有兩種方法:屬性注入和構造器注入。

 

3、屬性注入


    class Program
    {
        static void Main(string[] args)
        {
            
            //*****************屬性注入********************************

            IApplicationContext context = ContextRegistry.GetContext();

            //實例化類
            StudentA selfCommand = (StudentA)context["attrStudentA"];
            selfCommand.Show();

            Console.WriteLine("--------");

            //實例化父類(StudentB繼承BaseStudent)
            BaseStudent parentCommand = (BaseStudent)context["attrStudentB"];
            parentCommand.Run();

            Console.WriteLine("--------");

            //實例化基類(StudentC繼承AbstractStudent)
            AbstractStudent abstractCommand = (AbstractStudent)context["attrStudentC"];
            abstractCommand.Read();


            Console.WriteLine("--------");

            //實例化接口(StudentD實現接口IStudent)
            IStudent interfaceCommand = (IStudent)context["attrStudentD"];
            interfaceCommand.Show();
            
            Console.ReadLine();

        }
    }

結果:

這裏主要演示屬性注入,不管是代理類、接口、抽象類、父類都生效。配置如下: 

      <!--聲明-->
      <object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
        <property name="Name" value="王五"/>
        <property name="Age" value="15"/>
      </object>
      
      <object id="attrStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example">
        <!--ref指向下面的屬性注入-->
        <property name="Friend" ref="UserInfo" />
      </object>     

 

配置還有一種寫法,把引用對象直接寫在屬性下面,如下:

      <object id="attrStudentB" type="Spring.Net.Example.Commands.StudentB,Spring.Net.Example">
        <!--ref指向下面的屬性注入-->
        <!--<property name="Friend" ref="UserInfo" />-->
        <property name="Friend">
          <object type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
            <property name="Name" value="王五"/>
            <property name="Age" value="15"/>
          </object>
        </property>
      </object>

4、構造函數注入

當默認的無參構造函數不存在,構造函數需要參數的時候,怎麼辦呢,可以在配置文件裏進行配置。

接口類、抽象類、父類繼續使用文章開頭貼出來的類,實體類和上層調用方法如下:

namespace Spring.Net.Example.Commands
{
    public class StudentE
    {
        public StudentE(string name, int age, UserInfo friend)
        {
            Name = name;
            Age = age;
            Friend = friend;
        }

        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我是類裏的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }


    public class StudentF : BaseStudent
    {
        public StudentF(string name, int age, UserInfo friend)
        {
            Name = name;
            Age = age;
            Friend = friend;
        }

        public void Show()
        {
            Console.WriteLine($"我是{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }


    public class StudentG : AbstractStudent
    {
        public StudentG(string name, int age, UserInfo friend)
        {
            Name = name;
            Age = age;
            Friend = friend;
        }

        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我是{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }

        public override void Read()
        {
            Console.WriteLine($"我是抽象類的重載,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }

    public class StudentH : IStudent
    {
        public StudentH(string name, int age, UserInfo friend)
        {
            Name = name;
            Age = age;
            Friend = friend;
        }

        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我是{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }
}


    class Program
    {
        static void Main(string[] args)
        {

            //*****************構造函數注入********************************

            IApplicationContext context = ContextRegistry.GetContext();

            //實例化類
            StudentE selfCommand = (StudentE)context["constructorStudentE"];
            selfCommand.Show();

            Console.WriteLine("--------");

            //實例化父類(StudentF繼承BaseStudent)
            BaseStudent parentCommand = (BaseStudent)context["constructorStudentF"];
            parentCommand.Run();

            Console.WriteLine("--------");

            //實例化基類(StudentG繼承AbstractStudent)
            AbstractStudent abstractCommand = (AbstractStudent)context["constructorStudentG"];
            abstractCommand.Read();


            Console.WriteLine("--------");

            //實例化接口(StudentH實現接口IStudent)
            IStudent interfaceCommand = (IStudent)context["constructorStudentH"];
            interfaceCommand.Show();

            Console.ReadLine();

        }
    }

結果爲:

這裏主要說明構造函數的參數注入,不管是代理類、接口、抽象類、父類都生效。

      <object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
        <property name="Name" value="王五"/>
        <property name="Age" value="15"/>
      </object>

      <object id="constructorStudentF" type="Spring.Net.Example.Commands.StudentF,Spring.Net.Example">
        <constructor-arg value="李四" type="string" index="0"/>
        <constructor-arg value="19" type="int" index="1"/>
        <constructor-arg index="2" ref="UserInfo"/>
      </object>

constructor-arg 有value、type、index三個參數,其中index是參數的序號,以0開始。type、index有時也可以省略。

內聯類型則需要同過ref屬性來設置,先配置映射,然後用ref引用。

構造函數參數解析有三種方法:

1)根據參數類型匹配(type)

        <constructor-arg type="string" value="李四" />
        <constructor-arg type="int" value="19" />

2)根據參數索引匹配(index)

        <constructor-arg index="0" value="李四" />
        <constructor-arg index="1" value="19" />

3)根據參數名稱匹配(name)

        <constructor-arg name="name" value="李四" />
        <constructor-arg name="age" value="19" />

當然也可以混着用

有時候參數裏有特殊字符,也可以換個寫法,使用<![CDATA[]]>,type、index有時也可以省略。

      <object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
        <property name="Name" value="王五"/>
        <property name="Age" value="15"/>
      </object>

     <object id="constructorStudentF" type="Spring.Net.Example.Commands.StudentF,Spring.Net.Example">
        <constructor-arg index="1" type="int">
          <value><![CDATA[19]]></value>
        </constructor-arg>
        <constructor-arg index="0">
          <value><![CDATA[李四]]></value>
        </constructor-arg>
        <constructor-arg index="2" ref="UserInfo"/>
      </object>

如果有AOP攔截的時候,可以寫在Target的對象映射裏

      <object name="UserInfo" type="Spring.Net.Example.Commands.UserInfo,Spring.Net.Example">
        <property name="Name" value="王五"/>
        <property name="Age" value="15"/>
      </object>

      <object id="constructorStudentF" type="Spring.Aop.Framework.ProxyFactoryObject">
        <property name="Target">
          <object type="Spring.Net.Example.Commands.StudentF, Spring.Net.Example">
            <constructor-arg value="張三" type="string" index="0"/>
            <constructor-arg value="20" type="int" index="1"/>
            <constructor-arg index="2" ref="UserInfo"/>
            <!--<constructor-arg>
              <value><![CDATA[李四]]></value>
            </constructor-arg>
            <constructor-arg>
              <value><![CDATA[19]]></value>
            </constructor-arg>-->
          </object>
        </property>
        <property name="InterceptorNames">
          <list>
            <value>beforeAdvice</value>
            <value>aroundAdvice</value>
            <value>afterAdvice</value>
            <value>exceptAdvice</value>
          </list>
        </property>
      </object>

 

 實現方式,直接編程

不需要配置表,直接硬編,也可以實現。AOP的話,父類代理或者類的代理需要把執行方法改爲virtual,要不沒有AOP。

namespace Spring.Net.Example.Commands
{
    public class StudentD : IStudent
    {
        public UserInfo Friend { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Show()
        {
            Console.WriteLine($"我實現了接口的方法,名字{this.Name},年齡{this.Age}");
            if (this.Friend != null)
                Console.WriteLine($"朋友是{Friend.Name},年齡{Friend.Age}");
        }
    }
}

    class Program
    {
        static void Main(string[] args)
        {


            //*****************編程式--硬編********************************

            ProxyFactory factory = new ProxyFactory(new StudentD());
            factory.AddAdvice(new LogBeforeAdvice());
            factory.AddAdvice(new LogAfterAdvice());
            factory.AddAdvice(new LogExceptAdvice());
            IStudent command = (IStudent)factory.GetProxy();

            command.Show();

            Console.ReadLine();
        }
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章