2

Spring MVC アプリケーションを作成しています。

コントローラーは、サービス層のサービス [名前: TestExecutionOrchestratorService.java] の 1 つに依存します。TestExecutionOrchestratorService は、いくつかの他のサービス [名前: JUnitTestExecutorService、QTPTestExecutorService] に依存します。構成は、これらのサービスをマップに挿入するように設定されています。

Controller と TestExecutionOrchestratorService は、アノテーションを使用して自動配線されます。TestExecutionOrchestratorService とその依存関係は、XML 構成を使用して接続されています。

私が解決しようとしている依存関係の問題:

Controller は TestExecutionOrchestratorService のオブジェクトを取得しています。TestExecutionOrchestratorService は、注入された依存関係サービスのマップを取得しています [出力されたログ メッセージでわかります]。この Map を TestExecutionOrchestratorService のインスタンス変数として保存します。ただし、コントローラー内の TestExecutionOrchestratorService オブジェクトのインスタンスには、依存関係の挿入中にマップが設定されていないようです。言い換えると:

Controller---DEPENDS ON--->TestExecutionOrchestratorService---DEPENDS ON--->Map[of JUnitTestExecutorService, QTPTestExecutorService] Controller に設定された TestExecutionOrchestratorService のインスタンスでは、Map は空です。ログ メッセージから、サーバーの起動中に Map が挿入されていることがわかりました。

コードと XML ファイルは次のとおりです。

リスト 1 - コントローラー

    /**
     * Handles requests for the application home page.
     */
    @Controller
    public class HomeController {

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    @Autowired
    private TestExecutionOrchestratorService testExecutionOrchestratorService;

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! the client locale is "+ locale.toString());

        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

        String formattedDate = dateFormat.format(date);

        model.addAttribute("serverTime", formattedDate );

        //ISSUE: Call to the service layer. The Map in the service is empty even though dependency injection is happening
                //there.
        if (testExecutionOrchestratorService != null) {
          logger.info("testExecutionOrchestratorService is not null. Executing it...");
          testExecutionOrchestratorService.runTests();
        }
        else {
          logger.info("testExecutionOrchestratorService is null. Why Why Why??");
        }


        return "home";
    }

}

リスト 2 - TestExecutionOrchestratorService

    /*
     * This class is the entry point into test execution. It takes the request to execute tests
     * and calls the appropriate test executors.
     */

    @Service("testExecutionOrchestratorService")
    public class TestExecutionOrchestratorService implements TestResultsReporter {
    /* List of executor services */
    private Map<String, TestExecutorService> testExecutors = new HashMap<String, TestExecutorService>();

  private static final Logger logger = LoggerFactory.getLogger(TestExecutionOrchestratorService.class);



  /*
   * For Spring's dependency injection - to inject all the test executors.
   */
  public void setExecutormap(Map<String, TestExecutorService> exMap) {
    if (exMap != null) {
      Set<Entry<String, TestExecutorService>> mapEntrySet = exMap.entrySet();
      logger.error("TestExecutionOrchestratorService [setExecutorMap]: Got a map of test executors. The entries are:");
      for (Entry<String, TestExecutorService> mapE: mapEntrySet) {
        logger.error("Key: " + mapE.getKey() + ", Value: " + mapE.getValue().getExecutorName());
      }

      //ISSUE: testExecutors is showing as null in the "runTests" method that is called by the Controller. Why??
      testExecutors.putAll(exMap);  
    }
    else {
      logger.error("TestExecutionOrchestratorService [setExecutorMap]: Got a null executors map");  
    }
  }


  /* runTests - Calls upon the various executors to run the tests.
   * ISSUE: The Controller is calling this method but the Map set in 'setExecutorMap' is not being found. */
  public void runTests() {
    logger.error("TestExecutionOrchestratorService [runTests]: Entering the method");
    /* Create a unique test run ID. This will be the current time stamp. */
    String testRunTimestamp = new Timestamp(new Date().getTime()).toString(); 
    logger.error("TestExecutionOrchestratorService [runTests]: Will execute executors with test run ID: " + testRunTimestamp);
        /* Call each executor and ask them to run their default tests. */

        if ((testExecutors != null) && (!testExecutors.isEmpty())) {
          logger.error("TestExecutionOrchestratorService [runTests]: test executors are available. Will execute them.");
          Collection<TestExecutorService> teServices = testExecutors.values();
          for (TestExecutorService teService: teServices) {

          teService.runTests(testRunTimestamp, null, this);

          }
        }
        else {
          /* ISSUE: THIS IS WHERE EXECUTION IS ALWAYS COMING */
          logger.error("TestExecutionOrchestratorService [runTests]: There are no test executors available.");
        }

    }
}

リスト 3 - Spring の Web コンテキスト XML ファイル (root-context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="..">


<!-- Root Context: defines shared resources visible to all other web components -->

<!-- Defining services -->
<!-- The following services are defined here: TestExecutionOrchestratorService,
JUnitTestExecutorService, QTPTestExecutorService -->
<!-- Definition of the JUnitTestExecutorService -->
<bean id="junitexecutor" name="junitexecutor" class="com.testing.autofwk.execution.JUnitTestExecutorService" />
<!-- Definition of the QTPTestExecutorService -->
<bean id="qtpexecutor" name="qtpexecutor" class="com.testing.autofwk.execution.QTPTestExecutorService" />
<!-- Definition of the TestExecutionOrchestratorService -->
<bean id="testexecutororchestrator" name="testexecutororchestrator" class="com.testing.autofwk.execution.TestExecutionOrchestratorService">
  <property name="executormap">
    <map>

       <entry key="junit">
         <ref local="junitexecutor"/>
       </entry>
       <entry key="qtp">
         <ref local="qtpexecutor"/>
       </entry>
    </map>
  </property>
</bean>


<context:component-scan base-package="com.testing.autofwk.execution" />

</beans>

リスト 4 - MVC アプリケーション ディスパッチャーのコンテキスト XML ファイル (servlet-context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="..">

<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
</beans:bean>

<context:component-scan base-package="com.testing.autofwk" />



</beans:beans>
4

1 に答える 1

2

複数を作成しているようでTestExecutionOrchestratorService、間違ったものがコントローラーに挿入されています。root-context.xml がロードされると 1 つのオブジェクトが作成されます。 にはTestExecutionOrchestratorServiceアノテーション@Serviceがあるため、クラスがスキャンされるときに他の Bean が作成されます。

さらに、ディスパッチャのコンテキスト XML ファイルが原因で、一部のパッケージは 2 回スキャンされます。

同じクラスを複数回スキャンしないように、ディスパッチャーのコンテキスト XML ファイルで次のようなものを使用することをお勧めします。

<context:component-scan base-package="com.testing.autofwk" use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>

そしてルートコンテキストで:

<context:component-scan base-package="com.testing.autofwk">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
于 2013-01-04T18:50:29.030 に答える