mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
More ordering issues in service apps
* The TraceAutoConfiguration in the service project was loading too early because it contains a BPP * It also had a Spring Security dependency without any @Conditional* configuration * Fixed by nesting the BPP in a class with @Conditional*
This commit is contained in:
parent
0a58e560b3
commit
ec0e9b17ad
|
@ -99,11 +99,13 @@ public class CleanCommand extends OptionParsingCommand {
|
|||
if (file.exists()) {
|
||||
if (options.has(this.allOption)
|
||||
|| group.equals("org.springframework.bootstrap")) {
|
||||
System.out.println("Deleting: " + file);
|
||||
FileUtil.forceDelete(file);
|
||||
} else {
|
||||
for (Object obj : FileUtil.listAll(file, Collections.emptyList())) {
|
||||
File candidate = (File) obj;
|
||||
if (candidate.getName().contains("SNAPSHOT")) {
|
||||
System.out.println("Deleting: " + candidate);
|
||||
FileUtil.forceDelete(candidate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash -x
|
||||
#!/bin/bash
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false;
|
||||
|
@ -48,8 +48,14 @@ fi
|
|||
|
||||
if [ "$SPRING_HOME" == "" ]; then
|
||||
SPRING_HOME=`cd "$(dirname $0)"/.. && pwd`
|
||||
else
|
||||
if [ ! -d "${SPRING_HOME}" ]; then
|
||||
echo "Not a directory: SPRING_HOME=${SPRING_HOME}"
|
||||
echo "Please rectify and restart."
|
||||
exit 2
|
||||
fi
|
||||
SPRING_HOME=`cd "${SPRING_HOME}" && pwd`
|
||||
fi
|
||||
SPRING_HOME=`cd "${SPRING_HOME}" && pwd`
|
||||
SPRING_BIN=$(dirname $0)
|
||||
|
||||
TARGETDIR=target/classes
|
||||
|
@ -60,15 +66,7 @@ mkdir -p "${TARGETDIR%/}"
|
|||
|
||||
CLASSPATH="${CLASSPATH}":"${SPRING_BIN}":"${TARGETDIR}"
|
||||
|
||||
if [ ! "${SPRING_BIN}" == "${SPRING_HOME}" ]; then
|
||||
CLASSPATH="${CLASSPATH}":"${SPRING_HOME}"/classes
|
||||
fi
|
||||
|
||||
for f in "${SPRING_HOME}"/lib/*.jar; do
|
||||
[ -f $f ] && CLASSPATH="${CLASSPATH}":$f
|
||||
done
|
||||
|
||||
for f in "${SPRING_HOME}"/*.jar; do
|
||||
for f in "${SPRING_HOME}"/*.jar "${SPRING_HOME}"/lib/*.jar "${SPRING_HOME}"/classes; do
|
||||
[ -f $f ] && CLASSPATH="${CLASSPATH}":$f
|
||||
done
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package org.springframework.bootstrap.sample.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.bootstrap.SpringApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.InterceptingClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Integration tests for separate management and main service ports.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ShutdownServiceBootstrapApplicationTests {
|
||||
|
||||
private static ConfigurableApplicationContext context;
|
||||
|
||||
@BeforeClass
|
||||
public static void start() throws Exception {
|
||||
Future<ConfigurableApplicationContext> future = Executors
|
||||
.newSingleThreadExecutor().submit(
|
||||
new Callable<ConfigurableApplicationContext>() {
|
||||
@Override
|
||||
public ConfigurableApplicationContext call() throws Exception {
|
||||
return (ConfigurableApplicationContext) SpringApplication
|
||||
.run(ServiceBootstrapApplication.class);
|
||||
}
|
||||
});
|
||||
context = future.get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stop() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHome() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = getRestTemplate("user", "password").getForEntity(
|
||||
"http://localhost:8080", Map.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertEquals("Hello Phil", body.get("message"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShutdown() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = getRestTemplate("user", "password").postForEntity(
|
||||
"http://localhost:8080/shutdown", null, Map.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertTrue("Wrong body: " + body,
|
||||
((String) body.get("message")).contains("Shutting down"));
|
||||
}
|
||||
|
||||
private RestTemplate getRestTemplate(final String username, final String password) {
|
||||
|
||||
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
|
||||
|
||||
if (username != null) {
|
||||
|
||||
interceptors.add(new ClientHttpRequestInterceptor() {
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
request.getHeaders().add(
|
||||
"Authorization",
|
||||
"Basic "
|
||||
+ new String(Base64
|
||||
.encode((username + ":" + password)
|
||||
.getBytes())));
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(
|
||||
new InterceptingClientHttpRequestFactory(
|
||||
new SimpleClientHttpRequestFactory(), interceptors));
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
}
|
||||
});
|
||||
return restTemplate;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -65,6 +65,7 @@
|
|||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<optional>true</optional>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.springframework.bootstrap.service.properties.ContainerProperties;
|
|||
import org.springframework.bootstrap.service.properties.ContainerProperties.Tomcat;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -48,6 +49,7 @@ import org.springframework.util.StringUtils;
|
|||
// the right order
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class })
|
||||
@Order(Integer.MIN_VALUE)
|
||||
public class ContainerConfiguration implements BeanPostProcessor, BeanFactoryAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
|
|
@ -18,17 +18,19 @@ package org.springframework.bootstrap.autoconfigure.service;
|
|||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||
import org.springframework.bootstrap.service.properties.ContainerProperties;
|
||||
import org.springframework.bootstrap.service.trace.InMemoryTraceRepository;
|
||||
import org.springframework.bootstrap.service.trace.SecurityFilterPostProcessor;
|
||||
import org.springframework.bootstrap.service.trace.TraceEndpoint;
|
||||
import org.springframework.bootstrap.service.trace.TraceRepository;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
|
@ -41,24 +43,34 @@ import org.springframework.web.servlet.DispatcherServlet;
|
|||
@ConditionalOnMissingBean({ TraceEndpoint.class })
|
||||
public class TraceAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ContainerProperties configuration = new ContainerProperties();
|
||||
|
||||
@Autowired(required = false)
|
||||
private TraceRepository traceRepository = new InMemoryTraceRepository();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({ TraceRepository.class })
|
||||
@ConditionalOnMissingBean(TraceRepository.class)
|
||||
protected TraceRepository traceRepository() {
|
||||
return this.traceRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterPostProcessor securityFilterPostProcessor() {
|
||||
SecurityFilterPostProcessor processor = new SecurityFilterPostProcessor(
|
||||
traceRepository());
|
||||
processor.setDumpRequests(this.configuration.isDumpRequests());
|
||||
return processor;
|
||||
@Configuration
|
||||
@ConditionalOnClass(SecurityFilterChain.class)
|
||||
public static class SecurityFilterPostProcessorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private TraceRepository traceRepository;
|
||||
|
||||
@Value("${container.dump_requests:false}")
|
||||
private boolean dumpRequests;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterPostProcessor securityFilterPostProcessor(
|
||||
BeanFactory beanFactory) {
|
||||
SecurityFilterPostProcessor processor = new SecurityFilterPostProcessor(
|
||||
this.traceRepository);
|
||||
processor.setDumpRequests(this.dumpRequests);
|
||||
return processor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.util.Assert;
|
||||
|
@ -51,7 +52,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SecurityFilterPostProcessor implements BeanPostProcessor {
|
||||
public class SecurityFilterPostProcessor implements BeanPostProcessor, Ordered {
|
||||
|
||||
private final static Log logger = LogFactory
|
||||
.getLog(SecurityFilterPostProcessor.class);
|
||||
|
@ -60,6 +61,20 @@ public class SecurityFilterPostProcessor implements BeanPostProcessor {
|
|||
|
||||
private TraceRepository traceRepository = new InMemoryTraceRepository();
|
||||
|
||||
private int order = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* @param order the order to set
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param traceRepository
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
Block a user