【问题标题】:Solving "Robot legs" p‌r‌o‌b‌l‌e‌m with Spring IOC (DI)使用 Spring IOC (DI) 解决“机器人腿”p‌r‌o‌b‌l‌e‌m
【发布时间】:2012-11-25 06:30:01
【问题描述】:

使用 Guice,可以执行以下操作:

interface Leg {}

_

class LeftLeg implements Leg {
    public String toString() {
        return "LeftLeg";
    }
}

_

class RightLeg implements Leg {
    public String toString() {
        return "RightLeg";
    }
}

_

class Robot {
    final Leg leftLeg_;
    final Leg rightLeg_;

    @Inject
    Robot(@Named("left") Leg leftLeg, @Named("right") Leg rightLeg) {
        leftLeg_ = leftLeg;
        rightLeg_ = rightLeg;
    }

    public String toString() {
        return "leftLeg_=" + leftLeg_ + ", rightLeg_=" + rightLeg_;
    }
}

_

class RobotTest {
    @Test
    public void t1() throws Exception {
        Injector inj = Guice.createInjector(new AnGuiceModule());
        Robot r = inj.getInstance(Robot.class);
        assertEquals(r.toString(), "leftLeg_=LeftLeg, rightLeg_=RightLeg");
    }
}

_

class AnGuiceModule extends AbstractModule {
    protected void configure() {
        bind(Leg.class).annotatedWith(Names.named("left")).to(LeftLeg.class);
        bind(Leg.class).annotatedWith(Names.named("right")).to(RightLeg.class);
    }
}

如何在 Spring 3.x(3.1.x 或 3.2)中使用 JSR-330(可选)注解和 JavaConfig,而不使用 XML 配置来实现相同的功能?

【问题讨论】:

    标签: java spring dependency-injection ioc-container guice


    【解决方案1】:

    interface Leg {}

    _

     @Component
     class LeftLeg implements Leg {
      public String toString() {
        return "LeftLeg";
      }
     }
    

    _

    @Component
    class RightLeg implements Leg {
      public String toString() {
        return "RightLeg";
     }
    }
    

    _

    class Robot {
      @Autowired
      Leg leftLeg_;
      @Autowired
      Leg rightLeg_;
    
    
    
      public String toString() {
        return "leftLeg_=" + leftLeg_ + ", rightLeg_=" + rightLeg_;
     }
    }
    

    _

    @RunWith(SpringJUnit4ClassRunner.class)
    class RobotTest {
      @Autowired
      Robot r;
      @Test
      public void t1() throws Exception {
         System.out.println(r);
     }
    }
    

    【讨论】:

    • 如何进行构造函数注入? ...我更正了我的问题并声明了字段 final 以便更清楚地表明我需要不可变的 Robot 而且我想使用 JSR-330 注释而不是特定于 Spring 的
    • 您的回答中我不明白的另一件事是:leftLeg_ 如何绑定到class LeftLegrightLeg_class RightLeg
    【解决方案2】:

    你可以这样做;虽然这个使用了 Spring 注释、@Qualifier 和 @Autowired,但我看不出有任何理由不使用 @Named 和 @Inject,但您应该尝试:

    public class MovieRecommender {
    
      private MovieCatalog movieCatalog;
      private CustomerPreferenceDao customerPreferenceDao;
    
      @Autowired
      public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
                          CustomerPreferenceDao customerPreferenceDao) {
          this.movieCatalog = movieCatalog;
          this.customerPreferenceDao = customerPreferenceDao;
      }
    
      // ...
    }
    

    示例取自reference

    【讨论】:

      【解决方案3】:

      我能找到的最接近的如下(Robot 和 Leg* 类的定义没有改变):

      public class RobotTest {
      
          @Test
          public void t1() throws Exception {
              ApplicationContext ctx = new 
                     AnnotationConfigApplicationContext(RobotConfig.class, Robot.class);
              Robot r = ctx.getBean(Robot.class);
              assertEquals("leftLeg_=LeftLeg, rightLeg_=RightLeg", r.toString());
          }
      }
      
      @Configuration
      class RobotConfig {
      
          @Bean
          public Leg leftLeg() {
              return new LeftLeg();
          }
      
          @Bean
          public Leg rightLeg() {
              return new RightLeg();
          }
      
      }
      

      替代方案是:

      public class RobotTest {
      
          @Test public void t1() throws Exception {
              ApplicationContext ctx = new 
                     AnnotationConfigApplicationContext(RobotConfig.class);
              Robot r = ctx.getBean(Robot.class);
              assertEquals("leftLeg_=LeftLeg, rightLeg_=RightLeg", r.toString());
          }
      }
      
      @Configuration
      class RobotConfig {
      
         @Bean @Scope("prototype") public Robot robot() {
             return new Robot(leftLeg(), rightLeg());
         }
      
          @Bean @Scope("prototype") public Leg leftLeg() {
              return new LeftLeg();
          }
      
          @Bean @Scope("prototype") public Leg rightLeg() {
              return new RightLeg();
          }
      }
      

      【讨论】:

      【解决方案4】:

      spring forum 上描述了一种有趣的方法。 您需要以某种方式获取对子上下文的引用,我不喜欢那里介绍的方法,但我应该有其他方法。

      用法:

        <bean name="someBean" class="playground.spring.BeanImportFactoryBean">
              <property name="applicationContext" ref="privateCtx"/>
              <property name="importBeanName" value="importBean"/>
          </bean>
      

      FactoryBean 代码:

      public class BeanImportFactoryBean implements FactoryBean, BeanNameAware {
          transient private final Log log = LogFactory.getLog(this.getClass());
      
          private String beanName;
          private ApplicationContext applicationContext;
          private String importBeanName;
      
          public BeanImportFactoryBean() {
          }
      
          public void setBeanName(String beanName) {
              this.beanName = beanName;
          }
      
          public void setApplicationContext(ApplicationContext applicationContext) {
              this.applicationContext = applicationContext;
          }
      
          public void setImportBeanName(String importBeanName) {
              this.importBeanName = importBeanName;
          }
      
          protected String getUsedBeanName() {
              String returnName;
              if (importBeanName == null) {
                  returnName = beanName;
              } else {
                  returnName = importBeanName;
              }
              return returnName;
          }
      
          public Object getObject() throws Exception {
              return this.applicationContext.getBean(getUsedBeanName());
          }
      
          public Class getObjectType() {
              return this.applicationContext.getType(getUsedBeanName());
          }
      
          public boolean isSingleton() {
              return this.applicationContext.isSingleton(getUsedBeanName());
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-01
        • 1970-01-01
        • 2011-01-14
        • 2014-02-06
        • 2015-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多