Инициализация контекста Spring (java)

Я новичок в Spring, и у меня проблемы с инициализацией базового контекста, и я не могу найти простого учебника. Итак, что я хочу сделать, это базовую инъекцию зависимостей, и я видел, что мне нужно только пометить классы как @Componant или @Service и внедрить их непосредственно в целевые поля с помощью @Autowired. Для этого мне нужно правильно настроить мой весенний контекст (мне нужно создать веб-службу + использовать JPA, поэтому я хочу создать веб-приложение)

Я использую JDK 1.8, maven 3.2.1.

Я хочу сделать базовую инъекцию зависимостей. => Я хочу внедрить туда экземпляр storeImpl, но это приведет к исключению нулевого указателя => это отлично работает без внедрения (private Store storeImpl = new storeImpl();)

package com.mycompany.app.controller;

@Controller
public class Controller
{
    @Autowired
    private Store storeImpl;

    public void use()
    {
        storeImpl.get();
    }
}


package com.mycompany.app.store;

public interface Store {
    boolean get();

}


package com.mycompany.app.store;

@Component
public class StoreImpl implements Store {
    @Override
    public boolean get()
    {
        return true;
    }
}

=> моя основная (пока я тестирую с ней свое приложение):

public class App
{
    public static void main(String[] args)
    {
        Controller controller = new Controller();
        controller.use();
    }
}

=> мой файл pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-app</name>
  <url>http://maven.apache.org</url>

    <properties>
        <spring.version>4.0.4.RELEASE</spring.version>
    </properties>

  <dependencies>
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
      </dependency>

      <dependency>
          <groupId>org.jsoup</groupId>
          <artifactId>jsoup</artifactId>
          <version>1.7.1</version>
      </dependency>

      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.12.6</version>
          <scope>provided</scope>
      </dependency>




      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>${spring.version}</version>
      </dependency>

      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>${spring.version}</version>
      </dependency>

      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>${spring.version}</version>
      </dependency>


      <dependency>
          <groupId>org.springframework.data</groupId>
          <artifactId>spring-data-jpa</artifactId>
          <version>1.5.2.RELEASE</version>
      </dependency>


      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-core</artifactId>
          <version>4.3.5.Final</version>
      </dependency>

      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.0.1</version>
          <scope>provided</scope>
      </dependency>
  </dependencies>

  <build>
    <plugins>
        <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
      </plugin>
    </plugins>
    </build>
</project>

=> мой файл web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <display-name>Archetype Created Web Application</display-name>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/META-INF/spring-context.xml</param-value>

    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

=> мой spring-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--<context:component-scan base-package="com.mycompany.app"/>-->
    <context:component-scan base-package="com.mycompany.app">
       <!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />-->
    </context:component-scan>

</beans>

=> архитектура моего проекта


my-app
  src
    main
      java
        com.mycompagny.app
          controller
            Controller.java
          store
            Store.java
            StoreImpl.java

          app.java

       ressources
         META-INF
           spring-context.xml

       webapp
         WEB-INF
           web.xml


  test
   java

pom.xml

=> трассировка стека main()

Exception in thread "main" java.lang.NullPointerException
    at com.mycompany.app.controller.Controller.run(Controller.java:25)
    at com.mycompany.app.App.main(App.java:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Итак, моя проблема в том, что мое введенное поле (storeImpl) равно нулю. И я думаю, что я что-то пропустил с инициализацией контекста? Еще раз спасибо за вашу помощь и ваш ответ


person user3615742    schedule 08.05.2014    source источник
comment
в чем именно проблема?:   -  person geoand    schedule 08.05.2014
comment
Определите bean-компонент для вашего класса реализации в spring xml   -  person Keerthivasan    schedule 08.05.2014
comment
моя проблема в том, что мое введенное поле (storeImpl) равно нулю. Я думаю, что context.xml никогда не инициализировался. Я думаю, что с аннотацией мне не нужно помечать bean-компонент в context.xml? даже я это делаю, поле все равно пустое: с   -  person user3615742    schedule 08.05.2014
comment
Ваш вопрос долгий. Однако есть несколько подсказок: только Spring bean-компоненты могут встраивать в себя другие Spring-бины. Ваш контроллер не снабжен аннотацией компонента Sprig. Интерфейсы не должны быть аннотированы аннотациями компонентов. Их реализация должна быть. И тип внедряемого поля (хранилища) должен быть типом интерфейса, а не типом реализации. Так что это должен быть Store, а не StoreImpl. Я также не понимаю, почему вы повторяете одну и ту же конфигурацию в двух файлах xml (и почему у вас их 2).   -  person JB Nizet    schedule 08.05.2014
comment
Вы используете сканирование компонентов, поэтому не определяйте bean-компоненты в контексте. Опять же, это приводит к дублированию компонентов. На данный момент из-за длины и редактирования вашего поста я совершенно не понимаю, что у вас есть и почему это не работает. Пожалуйста, перепишите свой пост с кодом, который у вас есть сейчас, я потерялся.   -  person M. Deinum    schedule 08.05.2014
comment
хорошо, я переписываю весь пост, еще раз спасибо!   -  person user3615742    schedule 08.05.2014
comment
Вы не используете Spring. Ваш основной класс ничего не делает, ваша конфигурация практически бесполезна. Вы не делаете ничего, связанного с Интернетом, поэтому не знаете, почему у вас вообще есть web.xml. В своем классе main вы создаете экземпляр Controller самостоятельно, Spring никогда не собирается внедрять его для вас, для этого вам нужно загрузить файл xml и использовать экземпляр Controller, созданный Spring.   -  person M. Deinum    schedule 08.05.2014
comment
большое спасибо ! он работает с: ApplicationContext ctx = new FileSystemXmlApplicationContext (путь к классам: META-INF/spring-context.xml); Контроллер a = (Контроллер) ctx.getBean(controller); но я должен определить bean-компоненты в весеннем контексте, аннотаций недостаточно: еще раз спасибо за ваше время и доброту!   -  person user3615742    schedule 08.05.2014


Ответы (2)


У вас есть пара проблем (следующее видно из вашего поста).

  1. Смешивание банок разных версий Spring
  2. Неверное расположение аннотаций
  3. Дублирование в контексте вашего приложения.
  4. Использование версионных файлов XSD.
  5. Конфликтующие версии в web.xml

<сильный>1. Смешивание Jars разных версий Spring

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.0.3.RELEASE</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.0.4.RELEASE</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>4.0.3.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.0.1.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.0.1.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>3.0.5.RELEASE</version>
  </dependency>

Ваша помпа завалена банками из разных весенних версий (3.0.5, 4.0.1, 4.0.3 и 4.0.3). Если вы хотите неприятностей, то это путь. Всегда придерживайтесь одной версии фреймворка и не смешивайте jar-файлы из разных версий. Это не только для Spring, но и для каждой (многобанковской) среды.

Используйте мощь maven, чтобы помочь вам, укажите свойство для хранения версии Spring, которую вы хотите использовать, и используйте это свойство.

<properties>
    <spring.version>4.0.4.RELEASE</spring.version>
</properties>
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring.version}</version>
  </dependency>

Возможно, вам придется добавить еще пару в зависимости от того, какие зависимости использует Spring Data JPA, если у него разные версии.

<сильный>2. Неверное расположение аннотаций

@Service
public interface Store {
    boolean get();
}

Аннотации не наследуются от интерфейсов, поэтому помещать аннотацию в интерфейс практически бесполезно. В Spring есть некоторые хаки для определенных аннотаций, таких как @Transactional, но не для этого. Переместите аннотацию в конкретную реализацию и не размещайте ее на интерфейсе.

@Service
public class Controller {
    @Autowired
    private Store storeImpl;

    public void use() {
       storeImpl.get();
    }
}

Я не вижу здесь ничего, ни @Controller, ни чего-то еще, ни @RequestMapping, поэтому я не уверен, как вы думаете, что Spring обнаруживает и обрабатывает этот класс.

<сильный>3. Дублирование в контексте вашего приложения.

<context:annotation-config /> удалите его из своего контекста, поскольку это уже подразумевается использованием <context:component-scan />.

<mvc:annotation-driven /> должен быть только в XML-файле, загруженном DispatcherServlet в вашем случае (если вы разместили фактический код), который должен быть dispatcher-servlet.xml.

У вас есть один и тот же элемент <context:component-scan .. /> в обоих ваших XML-файлах, это приведет к дублированию bean-компонентов. Файлы, загруженные ContextLoaderListener, должны загружать все, кроме @Controllers, а DispatcherServlet должны загружать только @Controllers и игнорировать все остальное. Для этого используйте фильтры включения/исключения при сканировании компонентов.

Используйте это для ContextLoaderListener.

<context:component-scan base-package="com.mycompany.app">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype. Controller" />
<context:component-scan>

Используйте это для DispatcherServlet.

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

Также не импортируйте конфигурацию DispatcherServlet в ContextLoaderListener, так как это снова приведет к дублированию компонентов.

<сильный>4. Использование файлов XSD с версиями.

xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

В расположениях вашей схемы используются версионные файлы XSD, рекомендуется использовать неверсионные xsd-файлы. Это гарантирует, что версия xsd, принадлежащая вашей текущей версии spring, будет загружена.

xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<сильный>5. Конфликт версий в web.xml

<!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app id="WebApp_ID" version="2.4"
     xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

Что вы хотите версию 2.3 от 2.4? Вы включаете servlet-api 2.5 в свой pom, и я ожидаю, что вам нужна версия 3.0. Измените свой заголовок (и зависимость maven) соответственно.

Измените заголовок web.xml на следующий.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     version="3.0">

Обновите файл pom.xml, включив в него спецификацию сервлета 3.0.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
    <scope>provided</scope>
</dependency>
person M. Deinum    schedule 08.05.2014
comment
Спасибо за отличный ответ! очень полезно! Я внес некоторые изменения, но у меня все еще есть проблема: s Поэтому я редактирую свой вопрос, чтобы он был более конкретным. - person user3615742; 08.05.2014
comment
Я только что закончил переписывать весь пост, чтобы прояснить ситуацию. еще раз спасибо !!! - person user3615742; 08.05.2014

Вы должны определить bean-компонент в своем Spring xml

<bean id="storeImpl" class="com.mycompany.app.store.StoreImpl">
       <!-- collaborators and configuration for this bean go here -->
</bean>

Таким образом, компонент @Autowired будет внедрен фреймворком Spring.

person Keerthivasan    schedule 08.05.2014