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();
        }
    }

 

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