代码之家  ›  专栏  ›  技术社区  ›  Anthony Waqas Raja

如何在Spring.net中更改配置

  •  3
  • Anthony Waqas Raja  · 技术社区  · 15 年前

    IOC容器的一个优点是,可以在对象图的底部交换模拟服务。然而,在Spring.net中,这似乎比在其他IOC容器中要困难得多。下面是一些代码,它们在Unity中执行,并具有Spring.NET代码;

    namespace IocSpringDemo
    {
        using Microsoft.Practices.Unity;
        using NUnit.Framework;
    
        using Spring.Context;
        using Spring.Context.Support;
    
        public interface ISomeService
        {
            string DoSomething();
        }
    
        public class ServiceImplementationA : ISomeService
        {
            public string DoSomething()
            {
                return "Hello A";
            }
        }
    
        public class ServiceImplementationB : ISomeService
        {
            public string DoSomething()
            {
                return "Hello B";
            }
        }
    
        public class RootObject
        {
            public ISomeService SomeService { get; private set; }
    
            public RootObject(ISomeService service)
            {
                SomeService = service;
            }
        }
    
        [TestFixture]
        public class UnityAndSpringDemo
        {
            [Test]
            public void UnityResolveA()
            {
                UnityContainer container = new UnityContainer();
                container.RegisterType<ISomeService, ServiceImplementationA>();
                RootObject rootObject = container.Resolve<RootObject>();
                Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
            }
    
            [Test]
            public void UnityResolveB()
            {
                UnityContainer container = new UnityContainer();
                container.RegisterType<ISomeService, ServiceImplementationB>();
                RootObject rootObject = container.Resolve<RootObject>();
                Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
            }
    
            [Test]
            public void SpringResolveA()
            {
                IApplicationContext container = ContextRegistry.GetContext();
                RootObject rootObject = (RootObject)container.GetObject("RootObject");
                Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
            }
    
            [Test]
            public void SpringResolveB()
            {
                // does not work - what to do to make this pass?
                IApplicationContext container = ContextRegistry.GetContext();
                RootObject rootObject = (RootObject)container.GetObject("RootObject");
                Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
            }
        }
    }
    

    为了使用Spring,需要在app.config文件中包含以下内容。显然,这只适用于第一次弹簧测试,而不是第二次。可以在配置文件中放置多个弹簧配置吗?如果是,语法是什么?如何访问它们?或者有其他方法可以做到这一点?

      <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"/>
        </context>
        <objects xmlns="http://www.springframework.net">
          <object name="RootObject" type="IocSpringDemo.RootObject, IocDemo" autowire="constructor" />
          <object name="service" type="IocSpringDemo.ServiceImplementationA, IocDemo" autowire="constructor" />
        </objects>
      </spring>
    

    更新

    下面是一个部分答案,基于 the links that Marko Lahma gave to Mark Pollack's blog .以上测试通过,代码如下:

    public static class SpringHelper
    {
        public static T Resolve<T>(this IApplicationContext context, string name)
        {
            return (T)context.GetObject(name);
        }
    
        public static void RegisterType<T>(this GenericApplicationContext context, string name)
        {
            context.RegisterType(name, typeof(T));
        }
    
        public static void RegisterType(this GenericApplicationContext context, string name, Type type)
        {
            IObjectDefinitionFactory objectDefinitionFactory = new DefaultObjectDefinitionFactory();
            ObjectDefinitionBuilder builder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, type);
            builder.SetAutowireMode(AutoWiringMode.AutoDetect);
    
            context.RegisterObjectDefinition(name, builder.ObjectDefinition);
        }
    }
    

        [Test]
        public void SpringResolveA()
        {
            GenericApplicationContext container = new GenericApplicationContext();
            container.RegisterType<RootObject>("RootObject");
            container.RegisterType<ServiceImplementationA>("service");
    
            RootObject rootObject = container.Resolve<RootObject>("RootObject");
            Assert.AreEqual("Hello A", rootObject.SomeService.DoSomething());
        }
    
        [Test]
        public void SpringResolveB()
        {
            GenericApplicationContext container = new GenericApplicationContext();
            container.RegisterType<RootObject>("RootObject");
            container.RegisterType<ServiceImplementationB>("service");
    
            RootObject rootObject = container.Resolve<RootObject>("RootObject");
            Assert.AreEqual("Hello B", rootObject.SomeService.DoSomething());
        }
    

    这给我提出了几个问题:

    • 我想将此技术集成到使用常规容器的现有代码中。为什么我必须使用不同的容器类型, GenericApplicationContext 在这种情况下?如果我想从app.config或web.config中的现有Spring配置中将数据读取到此对象中,该怎么办?它会像通常的上下文一样工作吗?然后我可以用代码在这些注册上写数据吗?

    • 我该怎么说呢 ISomeService 是否创建为单例?我的意思不是向容器提供一个单实例,而是提供容器来创建实例,解析其构造函数,并在需要该类型时使用它。

    • 我怎样才能做到 container.RegisterType<ISomeService, ServiceImplementationA>(); ?我想注册类型映射,以便在构造函数需要该类型的所有情况下使用。

    • 具体做什么 container.RegisterType<ServiceImplementationA>("service"); 怎么办?好像是挂号的 ServiceImplementationA 作为实施 异构服务 但是 异构服务 从未提及,因此可能存在歧义。例如如果 服务实施A 实现了多个接口。

    • 注册的字符串名称是什么?它不适用于空字符串,但它似乎并不重要。

    我是不是想用一种弹簧不起作用的方式?我试着像其他IOC容器一样使用它,但它不太管用。

    2 回复  |  直到 15 年前
        1
  •  3
  •   Marko Lahma    15 年前

    正在添加为新答案,尝试解决开放点…

    我想把这项技术结合起来 在现有代码中使用 容器。我为什么要用 不同的容器类型, 此中的GenericApplicationContext 案例?如果我想把数据读到 此对象来自现有弹簧 在app.config或web.config中配置? 它会像通常的上下文一样工作吗? 我可以在上面写数据吗 用代码注册?

    Spring针对不同的初始化策略有具体的应用上下文实现。最常用的是genericapplicationContext(manual)、xmlapplicationContext(xml文件)和webapplicationContext(非常类似于xmlapplicationContext,但是为web使用而定制的)。它们都实现了公共接口:IApplicationContext,这是访问这些容器的首选方式。

    不规则地用代码更改注册通常意味着您需要直接使用特定的子类。对于GenericApplicationContext和StaticApplicationContext,这是很自然的,但通常将xmlApplicationContext视为仅限XML,这样就“固定”了XML定义。

    如何指定IsomeService是 要创建为单件?我不 意味着向提供单个实例 容器,但容器 创建实例,解析其 构造函数,并在该类型 是需要的。

    SpringHelper就是这样做的,默认情况下,Spring中的所有对象都是单例对象。可以通过使用false调用ObjectDefinitionBuilder的Setsingleton方法来更改此行为。

    我怎样才能做到 container.registerType();?我想 注册所有要使用的类型映射 在这种情况下, 建造师。

    Spring使用对象名(ID)来区分不同的实现。因此,如果您想让特定的类型为特定的实例提供服务,以防有许多备选方案,那么您应该按名称引用这个特定的实例。如果您使用的是autowiring,并且您的对象依赖于接口isomeservice,并且只有一个注册的对象实现了它,那么autowiring可以设置它而不产生歧义。

    具体做什么 container.registertype(“服务”); 怎么办?好像是挂号的 服务实施A作为 实施isomeservice,但是 IsomeService从未提到过,所以 可能存在歧义。例如,如果 已实现的服务实施 多个接口。

    从前面的回答继续,这将以“service”的名称注册serviceimplementationa类型的singleton。这个对象带有所有它实现的接口(当然还有它的具体类型)的自动连接候选者。

    指定给的字符串名称是什么 注册?它不适用于 空字符串,但它似乎 不管是什么。

    如前所述,这非常重要。该名称是该上下文中的唯一ID(父上下文可能具有同名的对象),可以用于访问特定的对象注册。简而言之,如果其他框架将类型关联为对象注册的键,那么Spring使用名称。

        2
  •  3
  •   Marko Lahma    15 年前

    在单元测试中,Unity使用代码配置,Spring.net使用XML(app.config)配置,这有点像苹果和橙子的比较。

    如果您使用XML路由,那么您可以注释掉旧的实现A,并将B实现定义为要使用的实现-配置的内容都是正确的?另一个选项是为每个场景(配置设置)提供专用的XML文件,并通过上下文的资源定义将其包含在内(您现在有了内联资源)。其他选项包括文件系统和程序集, see the web configuration section 在Spring.net的手册中有一个很好的例子。

    如果您选择代码配置路径,我建议您检查 Spring.NET Recoil 即将来临 CodeConfig .

    推荐文章