[英]GWT + Spring Boot @Autowired is not working
I have created a application in GWT + Spring Boot and when I try to use @Autowired
- I get NullPointerException
.我在 GWT + Spring Boot 中创建了一个应用程序,当我尝试使用
@Autowired
- 我得到NullPointerException
。 Apparently @Autowired
does not work and does not insert the bean in the right place.显然
@Autowired
不起作用并且没有将 bean 插入到正确的位置。 How can I fix this situation?我该如何解决这种情况?
Exception while dispatching incoming RPC call分派传入的 RPC 调用时出现异常
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract java.util.List com.myGWT.springbootapp.client.UserService.list()' threw an unexpected exception: java.lang.NullPointerException
com.google.gwt.user.server.rpc.UnexpectedException:服务方法“public abstract java.util.List com.myGWT.springbootapp.client.UserService.list()”引发意外异常:java.lang.NullPointerException
File web.xml
文件
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>userService</servlet-name>
<servlet-class>com.myGWT.springbootapp.server.UserServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>userService</servlet-name>
<url-pattern>/gwtApp/service</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>GWTApp.html</welcome-file>
</welcome-file-list>
</web-app>
pom.xml pom.xml
<name>spring-boot-app</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<gwt.version>2.7.0</gwt.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<!-- GWT -->
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>${gwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-codeserver</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>apache-jsp</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${gwt.version}</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>target</directory>
</fileset>
<fileset>
<directory>builds</directory>
<includes>
<include>**/*.*</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>deploy</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<executions>
<execution>
<id>deploy</id>
<phase>deploy</phase>
<goals><goal>deploy</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
File UserServiceImpl.java
文件
UserServiceImpl.java
package com.myGWT.springbootapp.server;
import com.myGWT.springbootapp.client.UserService;
import com.myGWT.springbootapp.entities.User;
import com.myGWT.springbootapp.repositories.UserRepository;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends RemoteServiceServlet implements UserService {
AnnotationConfigWebApplicationContext();
@Autowired
private UserRepository repository ;
@Override
public List<User> list() {
return repository.findAll();
}
}
File UserRepository.java
文件
UserRepository.java
package com.myGWT.springbootapp.repositories;
import com.myGWT.springbootapp.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
File UserService.java
文件
UserService.java
package com.myGWT.springbootapp.client;
import com.myGWT.springbootapp.entities.User;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import java.util.List;
@RemoteServiceRelativePath("service")
public interface UserService extends RemoteService {
List<User> list();
}
File GWTApp.java
文件
GWTApp.java
package com.myGWT.springbootapp.client;
import com.myGWT.springbootapp.entities.User;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.view.client.ListDataProvider;
import java.util.List;
public class GWTApp implements EntryPoint {
private UserServiceAsync userService = GWT.create(UserService.class);
private ListDataProvider<User> createTable (CellTable<User> table){
TextColumn<User> idColumn =new TextColumn<User>() {
@Override
public String getValue(User object) {
return object.getId().toString();
}
};
TextColumn<User> loginColumn =new TextColumn<User>() {
@Override
public String getValue(User object) {
return object.getLogin();
}
};
table.addColumn(idColumn, "Id");
table.addColumn(loginColumn, "Login");
final ListDataProvider<User> dataProvider = new ListDataProvider<>();
dataProvider.addDataDisplay(table);
this.userService.list(new AsyncCallback<List<User>>() {
@Override
public void onFailure(Throwable caught) {
Window.alert("Error: " + caught.getMessage());
}
@Override
public void onSuccess(List<User> result) {
dataProvider.getList().addAll(result);
}
});
return dataProvider;
}
public void onModuleLoad() {
CellTable<User> table = new CellTable<>();
ListDataProvider<User> dataProvider = createTable(table);
RootPanel.get().add(table);
}
}
Directory structure of the project项目目录结构
The short answer is: Spring didn't instantiate your GWT service;简短的回答是:Spring 没有实例化您的 GWT 服务; therefore it can't autowire anything into it.
因此它不能自动连接任何东西。
The Jetty container is actually responsible for creating and mapping an instance of UserServiceImpl
. Jetty 容器实际上负责创建和映射
UserServiceImpl
的实例。 That's what your web.xml
is describing.这就是你的
web.xml
所描述的。
Your @Service
annotation is indeed creating a Servlet instance within the Spring context as you would expect, but it's not known to Jetty.您的
@Service
注释确实如您所料在 Spring 上下文中创建了一个 Servlet 实例,但 Jetty 不知道它。 Historically, I have removed the @Service annotation from my RemoteServiceServlet
-based services and added the following method to provide @Autowire
support:从历史上看,我已经从基于
RemoteServiceServlet
的服务中删除了 @Service 注释,并添加了以下方法来提供@Autowire
支持:
public class UserServiceImpl extends RemoteServiceServlet implements UserService {
...
@Override
public void init() throws ServletException {
super.init();
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());
}
...
}
From the SpringBeanAutowiringSupport
javadoc :从
SpringBeanAutowiringSupport
javadoc :
Process @Autowired injection for the given target object, based on the current root web application context as stored in the ServletContext.
根据存储在 ServletContext 中的当前根 Web 应用程序上下文,处理给定目标对象的 @Autowired 注入。
Jetty will call init()
during Servlet creation and boom, you're beans come together. Jetty 将在 Servlet 创建和繁荣期间调用
init()
,您就是 bean。 This is on the hacky side of things because it bridges two unrelated processes, but it is working for me in production currently.这是在hacky的一面,因为它连接了两个不相关的过程,但它目前在生产中对我有用。
Using a Servlet 3.0+ compliant container you can probably find a way to use WebApplicationInitializer
( javadoc ) to fire up your Spring context via AnnotationConfigWebApplicationContext
( javadoc ) prior to mapping your servlets which would allow you to use the instances from there (this replaces your web.xml
).使用 Servlet 3.0+ 兼容容器,您可能会找到一种方法,在映射您的 servlet 之前,使用
WebApplicationInitializer
( javadoc ) 通过AnnotationConfigWebApplicationContext
( javadoc ) 启动您的 Spring 上下文,这将允许您从那里使用实例(这将取代您的web.xml
)。
Edit:编辑:
And since you're using Spring Boot you can take a peek at this thread which shows how to map servlets via ServletRegistrationBean
: How can I register a secondary servlet with Spring Boot?并且由于您使用的是 Spring Boot,因此您可以查看此线程,该线程显示了如何通过
ServletRegistrationBean
映射 servlet: How can I register a secondary servlet with Spring Boot? (see checketts's answer) (见checketts的回答)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.