GVKun编程网logo

java – Spring Boot对返回CompletionStage的请求运行两次过滤器(springboot过滤器返回信息)

10

在本文中,我们将为您详细介绍java–SpringBoot对返回CompletionStage的请求运行两次过滤器的相关知识,并且为您解答关于springboot过滤器返回信息的疑问,此外,我们还会提

在本文中,我们将为您详细介绍java – Spring Boot对返回CompletionStage的请求运行两次过滤器的相关知识,并且为您解答关于springboot过滤器返回信息的疑问,此外,我们还会提供一些关于Distributed transactions with multiple databases, Spring Boot, Spring Data JPA and Atomikos、eclipse 中springboot2.0整合jsp 出现No Java compiler available for configuration options compilerClassName、Java Spring Boot Restcontroller RequestMapping执行两次、java – CompletableFuture vs Spring Transactions的有用信息。

本文目录一览:

java – Spring Boot对返回CompletionStage的请求运行两次过滤器(springboot过滤器返回信息)

java – Spring Boot对返回CompletionStage的请求运行两次过滤器(springboot过滤器返回信息)

当方法返回CompletionStage时,我遇到了一个问题,即我的过滤器运行了两次.从RequestMapping(here)上的文档中,它是受支持的返回值.

A CompletionStage (implemented by CompletableFuture for example) which the application uses to produce a return value in a separate thread of its own choosing,as an alternative to returning a Callable.

由于项目非常复杂,并且有很多并发代码,因此我创建了一个新的简单的spring-boot项目.这是(唯一的)控制器:

@Controller
public class BaseController {
    @RequestMapping("/hello")
    @ResponseBody
    public CompletionStageCompletableFuture.supplyAsync(() -> "Hello World");
    }
}

还有一个过滤器:

@WebFilter
@Component
public class GenericLoggingFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,servletexception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;

        System.out.println(httpServletRequest.getmethod() + " " +
                           httpServletRequest.getRequestURI());

        chain.doFilter(request,response);
    }
}

当我打电话curl http:// localhost:8080 / hello时,它会在控制台上打印两次GET / hello.当我更改控制器方法以返回String时:

@RequestMapping("/hello")
@ResponseBody
public String world() {
    return "Hello World";
}

它只打印一次.即使我将其更改为Callable也会出现此行为,Callable没有真正的并发意义(当然,spring本身可能会将此视为异步请求).

因此,如果spring再次运行整个Web堆栈以获得请求上下文,那么即使这样也没有意义,因为以下内容:

@RequestMapping("/hello")
@ResponseBody
public CompletionStageCompletableFuture.supplyAsync(() -> {
        System.out.println(RequestContextHolder.currentRequestAttributes());
        return "Hello World";
    });
}

抛出异常:IllegalStateException:找不到线程绑定请求…

令人惊讶的是,以下工作:

@RequestMapping("/hello")
@ResponseBody
public Callablestem.out.println(RequestContextHolder.currentRequestAttributes());
        return "Hello World";
    };
}

所以,我不确定相当多的事情.

>似乎Callable和CompletionStage在执行哪个线程的上下文中被区别对待.
>如果是这种情况,为什么我的过滤器在每种情况下运行两次?如果过滤器的工作是设置某个特定于请求的上下文,那么如果无法访问CompletionStage,则再次运行它是没有意义的.
>为什么过滤器运行两次到底是哪种方式?

最佳答案
请用OncePerRequestFilter替换GenericFilterBean.

Distributed transactions with multiple databases, Spring Boot, Spring Data JPA and Atomikos

Distributed transactions with multiple databases, Spring Boot, Spring Data JPA and Atomikos

A couple of weeks ago I was evaluating the possibility to use Spring Boot, Spring Data JPA and Atomikos for distributed transactions involving multiple databases. After looking at the Spring blog article (which involves one database and ActiveMQ) and having done some attempts, I could not get it to work with two databases. The configuration seemed fine, but the Entity Manager did not get notified when persisting my entities. So I wrote this question on StackOverflow, which has been answered directly by Dave Syer and Oliver Gierke. This post is to share and discuss the solution.

Description of the case and entities model

We want to be able to save two entities at the same time into two different databases; the operation must be transactional. So, in this example, we have a Customer entity, which is persisted in the first database, and an Order entity which is persisted in the second database. The two entities are very simple, as they serve only as a demonstration.

The resulting implementation is the following. It''s worth noting that they belong to two different packages, for two main reasons:

  1. it''s a logical separation that gives order to the project
  2. each repository will scan packages containing only entities that it will be going to manage
package com.at.mul.domain.customer;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Entity
@Table(name = "customer")
@Data
@EqualsAndHashCode(exclude = { "id" })
public class Customer {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;

	@Column(name = "name", nullable = false)
	private String name;

	@Column(name = "age", nullable = false)
	private Integer age;

}
package com.at.mul.domain.order;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Entity
@Table(name = "orders")
@Data
@EqualsAndHashCode(exclude = { "id" })
public class Order {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;

	@Column(name = "code", nullable = false)
	private Integer code;

	@Column(name = "quantity", nullable = false)
	private Integer quantity;

}
See Lombok for annotations like @Data and @EqualsAndHashCode

Write repositories interfaces

Also in this case it''s standard, the only thing to notice is that I put the two interfaces in two different packages. The reason is explained in the next step.

package com.at.mul.repository.customer;

import org.springframework.data.jpa.repository.JpaRepository;

import com.at.mul.domain.customer.Customer;

public interface CustomerRepository extends JpaRepository<Customer, Integer> {

}
package com.at.mul.repository.order;

import org.springframework.data.jpa.repository.JpaRepository;

import com.at.mul.domain.order.Order;

public interface OrderRepository extends JpaRepository<Order, Integer> {

}

Write configuration classes

This is where it becomes interesting. The @DependsOn("transactionManager") annotation is not mandatory, but I needed this to get rid of several warnings at tests (or application) startup, like WARNING: transaction manager not running? in the logs. The next annotation @EnableJpaRepositories is more important:
  • it specifies which are the packages to scan for annotated components (repository interfaces), and in my case I wanted only repositories related to the customer (and conversely to the order).
  • it specifies which is the entity manager to be used to manage entities, in my case the customerEntityManager for customer related operations and orderEntityManager for order related operations
  • it specifies the transaction manager to be used, in my case the transactionManager defined in the MainConfig class. This needs to be the same for every @EnableJpaRepositories to get distributed transactions working
package com.at.mul;

import java.util.HashMap;

import javax.sql.DataSource;

import org.h2.jdbcx.JdbcDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import com.at.mul.repository.customer.CustomerDatasourceProperties;
import com.atomikos.jdbc.AtomikosDataSourceBean;

@Configuration
@DependsOn("transactionManager")
@EnableJpaRepositories(basePackages = "com.at.mul.repository.customer", entityManagerFactoryRef = "customerEntityManager", transactionManagerRef = "transactionManager")
@EnableConfigurationProperties(CustomerDatasourceProperties.class)
public class CustomerConfig {

	@Autowired
	private JpaVendorAdapter jpaVendorAdapter;

	@Autowired
	private CustomerDatasourceProperties customerDatasourceProperties;

	@Bean(name = "customerDataSource", initMethod = "init", destroyMethod = "close")
	public DataSource customerDataSource() {
		JdbcDataSource h2XaDataSource = new JdbcDataSource();
		h2XaDataSource.setURL(customerDatasourceProperties.getUrl());

		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(h2XaDataSource);
		xaDataSource.setUniqueResourceName("xads1");
		return xaDataSource;
	}

	@Bean(name = "customerEntityManager")
	@DependsOn("transactionManager")
	public LocalContainerEntityManagerFactoryBean customerEntityManager() throws Throwable {

		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
		properties.put("javax.persistence.transactionType", "JTA");

		LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
		entityManager.setJtaDataSource(customerDataSource());
		entityManager.setJpaVendorAdapter(jpaVendorAdapter);
		entityManager.setPackagesToScan("com.at.mul.domain.customer");
		entityManager.setPersistenceUnitName("customerPersistenceUnit");
		entityManager.setJpaPropertyMap(properties);
		return entityManager;
	}

}
package com.at.mul;

import java.util.HashMap;

import javax.sql.DataSource;

import org.h2.jdbcx.JdbcDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import com.at.mul.repository.order.OrderDatasourceProperties;
import com.atomikos.jdbc.AtomikosDataSourceBean;

@Configuration
@DependsOn("transactionManager")
@EnableJpaRepositories(basePackages = "com.at.mul.repository.order", entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager")
@EnableConfigurationProperties(OrderDatasourceProperties.class)
public class OrderConfig {

	@Autowired
	private JpaVendorAdapter jpaVendorAdapter;

	@Autowired
	private OrderDatasourceProperties orderDatasourceProperties;

	@Bean(name = "orderDataSource", initMethod = "init", destroyMethod = "close")
	public DataSource orderDataSource() {
		JdbcDataSource h2XaDataSource = new JdbcDataSource();
		h2XaDataSource.setURL(orderDatasourceProperties.getUrl());

		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(h2XaDataSource);
		xaDataSource.setUniqueResourceName("xads2");
		return xaDataSource;
	}

	@Bean(name = "orderEntityManager")
	public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable {

		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
		properties.put("javax.persistence.transactionType", "JTA");

		LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
		entityManager.setJtaDataSource(orderDataSource());
		entityManager.setJpaVendorAdapter(jpaVendorAdapter);
		entityManager.setPackagesToScan("com.at.mul.domain.order");
		entityManager.setPersistenceUnitName("orderPersistenceUnit");
		entityManager.setJpaPropertyMap(properties);
		return entityManager;
	}

}

Another important thing here is the definition of the LocalContainerEntityManagerFactoryBean.

  • the @Bean annotation has a given name, that is the one specified in the @EnableJpaRepositories annotation.
  • you need to set some properties to the JpaPropertyMap, in particular you need to say that the transaction type is JTA and that the jta platform is AtomikosJtaPlatform.class.getName()
Not setting the second property was the reason why I could not get it work. As Dave Syer wrote "It seems Hibernate4 doesn''t work with Atomikos out of the box", so you need to implement the class to be set as hibernate.transaction.jta.platform property by yourself. In my opinion this is not very well documented, but fortunately Oliver Gierke found another StackOverflow discussion about this topic. If you are using another JTA provider, you may find this useful.

Write the AbstractJtaPlatform implementation

As said, this is the most important step, as we need to write the implementation of that class by ourselves since Hibernate does not provide it. Here is the resulting code:

package com.at.mul;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;

public class AtomikosJtaPlatform extends AbstractJtaPlatform {

	private static final long serialVersionUID = 1L;

	static TransactionManager transactionManager;
	static UserTransaction transaction;

	@Override
	protected TransactionManager locateTransactionManager() {
		return transactionManager;
	}

	@Override
	protected UserTransaction locateUserTransaction() {
		return transaction;
	}

}

Write the main configuration class

Also in this case it''s a pretty standard class, with @EnableTransactionManagement annotation and Atomikos bean definitions. The only very important thing to notice is that we need to set AtomikosJtaPlatform.transactionManager and AtomikosJtaPlatform.transaction attributes.

package com.at.mul;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;

import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;

@Configuration
@ComponentScan
@EnableTransactionManagement
public class MainConfig {

	@Bean
	public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}
	
	@Bean
	public JpaVendorAdapter jpaVendorAdapter() {
		HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
		hibernateJpaVendorAdapter.setShowSql(true);
		hibernateJpaVendorAdapter.setGenerateDdl(true);
		hibernateJpaVendorAdapter.setDatabase(Database.H2);
		return hibernateJpaVendorAdapter;
	}

	@Bean(name = "userTransaction")
	public UserTransaction userTransaction() throws Throwable {
		UserTransactionImp userTransactionImp = new UserTransactionImp();
		userTransactionImp.setTransactionTimeout(10000);
		return userTransactionImp;
	}

	@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
	public TransactionManager atomikosTransactionManager() throws Throwable {
		UserTransactionManager userTransactionManager = new UserTransactionManager();
		userTransactionManager.setForceShutdown(false);

		AtomikosJtaPlatform.transactionManager = userTransactionManager;

		return userTransactionManager;
	}

	@Bean(name = "transactionManager")
	@DependsOn({ "userTransaction", "atomikosTransactionManager" })
	public PlatformTransactionManager transactionManager() throws Throwable {
		UserTransaction userTransaction = userTransaction();

		AtomikosJtaPlatform.transaction = userTransaction;

		TransactionManager atomikosTransactionManager = atomikosTransactionManager();
		return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
	}

}

Resources

Here is the resulting structure of the project:

You can see the full source code here: https://github.com/fabiomaffioletti/mul-at, The master branch uses in memory database. Checkout branch named mysql-db to use real databases (see application.properties to tweak your database connection data).

eclipse 中springboot2.0整合jsp 出现No Java compiler available for configuration options compilerClassName

eclipse 中springboot2.0整合jsp 出现No Java compiler available for configuration options compilerClassName

今天使用eclipse创建springboot整合jsp出现一个问题,在idea中并没有遇到这个问题。最后发现是需要在eclipse中添加一个eclipse依赖,依赖如下:

<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.6.1</version>
<scope>provided</scope>
</dependency>
添加该依赖后问题解决。
错误提示如下:

java.lang.IllegalStateException: No Java compiler available for configuration options compilerClassName: [null] and compiler: [null]
at org.apache.jasper.JspCompilationContext.createCompiler(JspCompilationContext.java:235) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:587) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:368) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:386) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:330) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:728) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:470) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:395) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:316) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:170) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:314) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1325) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1069) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1008) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.29.jar:8.5.29]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_181]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.29.jar:8.5.29]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_181]

2018-11-03 21:45:46.570 ERROR 4316 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No Java compiler available for configuration options compilerClassName: [null] and compiler: [null]] with root cause

java.lang.IllegalStateException: No Java compiler available for configuration options compilerClassName: [null] and compiler: [null]
at org.apache.jasper.JspCompilationContext.createCompiler(JspCompilationContext.java:235) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:587) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:368) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:386) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:330) ~[tomcat-embed-jasper-8.5.29.jar:8.5.29]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:728) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:470) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:395) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:316) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:170) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:314) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1325) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1069) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1008) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.29.jar:8.5.29]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.29.jar:8.5.29]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_181]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.29.jar:8.5.29]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_181]

 

Java Spring Boot Restcontroller RequestMapping执行两次

Java Spring Boot Restcontroller RequestMapping执行两次

我有一个带有RestController的Spring Boot应用程序和一个将下载并传递图像的方法:

@RestController
public class PictureController {

    @RequestMapping("/picture/{id}")
    public HttpEntity<byte[]> getImage(@PathVariable String id)  {

        logger.info("Requested picture : >> " + id + " <<");

        // !! Execute code for downloading  !!

        // Create Headers...

        // return HttpEntity<byte[]>
    }
}

在日志文件中,我可以看到该方法执行了 两次 ,但我不知道为什么。

如果我删除了下载代码,它将按预期执行 一次

是因为下载需要一秒钟吗?

下载代码是…

        byte[] response;

        try {
            URL url = new URL(....);

            InputStream in = new BufferedInputStream(url.openStream());
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int n = 0;
            while (-1 != (n = in.read(buf))) {
                out.write(buf,n);
            }
            out.close();
            in.close();
            response = out.toByteArray();

我还尝试了几种解决方案,例如…

@RequestMapping(value = "/picture2/{id}",headers = "Accept=image/jpeg,image/jpg,image/png,image/gif") 
public @ResponseBody byte[] getArticleImage2(@PathVariable String id) {

我以为HttpEntity可能有问题,但这是相同的行为。无需下载代码即可按预期工作,但下载映像后,它将执行 两次

这是我应用程序的严重性能问题… :(

这里有什么问题?

java – CompletableFuture vs Spring Transactions

java – CompletableFuture vs Spring Transactions

理念

我有一个处理方法,它接收项目列表并使用外部Web服务异步处理它们.处理步骤还会在处理时保留数据.在整个过程结束时,我希望将整个过程与每个处理结果一起保持.

问题

我将列表中的每个项目转换为CompletableFuture并对它们运行处理任务,并将它们放回到期货数组中.现在使用其.ofAll方法(按顺序方法)完成所有提交的任务完成后的未来,并返回另一个包含结果的CompletableFuture.

当我想得到那个结果时,我调用.whenComplete(..),并希望将返回的结果作为数据设置到我的实体中,然后保存到数据库,但是存储库保存调用什么也不做,只继续线程继续运行,它不会超过存储库保存调用.

@Transactional
 public void process(List<Item> items) {
   List<Item> savedItems = itemRepository.save(items);

   final Process process = createNewProcess();

   final List<CompletableFuture<ProcessData>> futures = savedItems.stream()
     .map(item -> CompletableFuture.supplyAsync(() -> doProcess(item,process),executor))
     .collect(Collectors.toList());

   sequence(futures).whenComplete((data,throwable) -> {
     process.setData(data);
     processRepository.save(process); // <-- transaction lost?
     log.debug("Process DONE"); // <-- never reached
   });
  }

序列方法

private static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
    CompletableFuture<Void> allDoneFuture =
      CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
    return allDoneFuture.thenApply(v ->
      futures.stream().map(CompletableFuture::join).collect(Collectors.toList())
    );
  }

怎么了?为什么持续的呼叫没有通过.启动事务的线程是否无法提交事务或丢失的位置?所有处理过的数据都很好,并且都很好.我尝试过不同的交易策略,但如果是这样的话,如何控制哪个线程完成交易呢?

有什么建议?

解决方法

如上所述,您的问题的原因是交易结束
当达到方法进程(..)的返回时.

您可以做的是手动创建交易,为您提供全面的交易
控制它何时开始和结束.

删除@Transactional

然后在进程(..)中自动装配TransactionManager:

TransactionDeFinition txDef = new DefaultTransactionDeFinition();
    TransactionStatus txStatus = transactionManager.getTransaction(txDef);
    try {
    //do your stuff here like
        doWhateverAsync().then(transactionManager.commit(txStatus);)
    } catch (Exception e) {
        transactionManager.rollback(txStatus);
        throw e;
    }

我们今天的关于java – Spring Boot对返回CompletionStage的请求运行两次过滤器springboot过滤器返回信息的分享就到这里,谢谢您的阅读,如果想了解更多关于Distributed transactions with multiple databases, Spring Boot, Spring Data JPA and Atomikos、eclipse 中springboot2.0整合jsp 出现No Java compiler available for configuration options compilerClassName、Java Spring Boot Restcontroller RequestMapping执行两次、java – CompletableFuture vs Spring Transactions的相关信息,可以在本站进行搜索。

本文标签: