Polishing
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,11 +24,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import org.springframework.aop.scope.ScopedObject;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
@@ -40,6 +37,10 @@ import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests that scopes are properly supported by using a custom Scope implementations
|
||||
@@ -58,10 +59,11 @@ public class ScopingTests {
|
||||
|
||||
private GenericApplicationContext ctx;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
customScope = new CustomScope();
|
||||
ctx = createContext(customScope, ScopedConfigurationClass.class);
|
||||
ctx = createContext(ScopedConfigurationClass.class);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -69,11 +71,9 @@ public class ScopingTests {
|
||||
if (ctx != null) {
|
||||
ctx.close();
|
||||
}
|
||||
ctx = null;
|
||||
customScope = null;
|
||||
}
|
||||
|
||||
private GenericApplicationContext createContext(org.springframework.beans.factory.config.Scope customScope, Class<?> configClass) {
|
||||
private GenericApplicationContext createContext(Class<?> configClass) {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
if (customScope != null) {
|
||||
beanFactory.registerScope(SCOPE, customScope);
|
||||
@@ -85,6 +85,7 @@ public class ScopingTests {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testScopeOnClasses() throws Exception {
|
||||
genericTestScope("scopedClass");
|
||||
@@ -95,6 +96,40 @@ public class ScopingTests {
|
||||
genericTestScope("scopedInterface");
|
||||
}
|
||||
|
||||
private void genericTestScope(String beanName) throws Exception {
|
||||
String message = "scope is ignored";
|
||||
Object bean1 = ctx.getBean(beanName);
|
||||
Object bean2 = ctx.getBean(beanName);
|
||||
|
||||
assertSame(message, bean1, bean2);
|
||||
|
||||
Object bean3 = ctx.getBean(beanName);
|
||||
|
||||
assertSame(message, bean1, bean3);
|
||||
|
||||
// make the scope create a new object
|
||||
customScope.createNewScope = true;
|
||||
|
||||
Object newBean1 = ctx.getBean(beanName);
|
||||
assertNotSame(message, bean1, newBean1);
|
||||
|
||||
Object sameBean1 = ctx.getBean(beanName);
|
||||
|
||||
assertSame(message, newBean1, sameBean1);
|
||||
|
||||
// make the scope create a new object
|
||||
customScope.createNewScope = true;
|
||||
|
||||
Object newBean2 = ctx.getBean(beanName);
|
||||
assertNotSame(message, newBean1, newBean2);
|
||||
|
||||
// make the scope create a new object .. again
|
||||
customScope.createNewScope = true;
|
||||
|
||||
Object newBean3 = ctx.getBean(beanName);
|
||||
assertNotSame(message, newBean2, newBean3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameScopeOnDifferentBeans() throws Exception {
|
||||
Object beanAInScope = ctx.getBean("scopedClass");
|
||||
@@ -154,10 +189,8 @@ public class ScopingTests {
|
||||
assertSame(spouse.getName(), spouseFromBF.getName());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testScopedProxyConfigurationWithClasses() throws Exception {
|
||||
|
||||
TestBean singleton = (TestBean) ctx.getBean("singletonWithScopedClassDep");
|
||||
ITestBean spouse = singleton.getSpouse();
|
||||
assertTrue("scoped bean is not wrapped by the scoped-proxy", spouse instanceof ScopedObject);
|
||||
@@ -189,7 +222,6 @@ public class ScopingTests {
|
||||
assertSame(spouse.getName(), spouseFromBF.getName());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testScopedConfigurationBeanDefinitionCount() throws Exception {
|
||||
// count the beans
|
||||
@@ -197,112 +229,41 @@ public class ScopingTests {
|
||||
assertEquals(11, ctx.getBeanDefinitionCount());
|
||||
}
|
||||
|
||||
// /**
|
||||
// * SJC-254 caught a regression in handling scoped proxies starting in 1.0 m4.
|
||||
// * The ScopedProxyFactoryBean object was having its scope set to that of its delegate
|
||||
// * whereas it should have remained singleton.
|
||||
// */
|
||||
// @Test
|
||||
// public void sjc254() {
|
||||
// JavaConfigWebApplicationContext ctx = new JavaConfigWebApplicationContext();
|
||||
// ctx.setConfigLocations(new String[] { ScopeTestConfiguration.class.getName() });
|
||||
// ctx.refresh();
|
||||
//
|
||||
// // should be fine
|
||||
// ctx.getBean(Bar.class);
|
||||
//
|
||||
// boolean threw = false;
|
||||
// try {
|
||||
// ctx.getBean(Foo.class);
|
||||
// } catch (BeanCreationException ex) {
|
||||
// if(ex.getCause() instanceof IllegalStateException) {
|
||||
// threw = true;
|
||||
// }
|
||||
// }
|
||||
// assertTrue(threw);
|
||||
// }
|
||||
|
||||
@Configuration
|
||||
static class ScopeTestConfiguration {
|
||||
|
||||
@Bean
|
||||
@Scope(value="session", proxyMode=ScopedProxyMode.INTERFACES)
|
||||
public Foo foo() {
|
||||
return new Foo();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Bar bar() {
|
||||
return new Bar(foo());
|
||||
}
|
||||
}
|
||||
|
||||
static class Foo {
|
||||
|
||||
public Foo() {
|
||||
//System.out.println("created foo: " + this.getClass().getName());
|
||||
}
|
||||
|
||||
public void doSomething() {
|
||||
//System.out.println("interesting: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Bar {
|
||||
|
||||
private final Foo foo;
|
||||
|
||||
public Bar(Foo foo) {
|
||||
this.foo = foo;
|
||||
//System.out.println("created bar: " + this);
|
||||
}
|
||||
|
||||
public Foo getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void genericTestScope(String beanName) throws Exception {
|
||||
String message = "scope is ignored";
|
||||
Object bean1 = ctx.getBean(beanName);
|
||||
Object bean2 = ctx.getBean(beanName);
|
||||
|
||||
assertSame(message, bean1, bean2);
|
||||
|
||||
Object bean3 = ctx.getBean(beanName);
|
||||
|
||||
assertSame(message, bean1, bean3);
|
||||
|
||||
// make the scope create a new object
|
||||
customScope.createNewScope = true;
|
||||
|
||||
Object newBean1 = ctx.getBean(beanName);
|
||||
assertNotSame(message, bean1, newBean1);
|
||||
|
||||
Object sameBean1 = ctx.getBean(beanName);
|
||||
|
||||
assertSame(message, newBean1, sameBean1);
|
||||
|
||||
// make the scope create a new object
|
||||
customScope.createNewScope = true;
|
||||
|
||||
Object newBean2 = ctx.getBean(beanName);
|
||||
assertNotSame(message, newBean1, newBean2);
|
||||
|
||||
// make the scope create a new object .. again
|
||||
customScope.createNewScope = true;
|
||||
|
||||
Object newBean3 = ctx.getBean(beanName);
|
||||
assertNotSame(message, newBean2, newBean3);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class InvalidProxyOnPredefinedScopesConfiguration {
|
||||
|
||||
@Bean @Scope(proxyMode=ScopedProxyMode.INTERFACES)
|
||||
public Object invalidProxyOnPredefinedScopes() { return new Object(); }
|
||||
public Object invalidProxyOnPredefinedScopes() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
public static class ScopedConfigurationClass {
|
||||
|
||||
|
||||
@@ -17,7 +17,13 @@
|
||||
package org.springframework.messaging.simp.annotation.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -33,21 +39,25 @@ import org.springframework.messaging.converter.CompositeMessageConverter;
|
||||
import org.springframework.messaging.converter.MessageConverter;
|
||||
import org.springframework.messaging.converter.StringMessageConverter;
|
||||
import org.springframework.messaging.core.AbstractMessageSendingTemplate;
|
||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||
import org.springframework.messaging.handler.HandlerMethod;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.annotation.support.*;
|
||||
import org.springframework.messaging.handler.annotation.support.AnnotationExceptionHandlerMethodResolver;
|
||||
import org.springframework.messaging.handler.annotation.support.DestinationVariableMethodArgumentResolver;
|
||||
import org.springframework.messaging.handler.annotation.support.HeaderMethodArgumentResolver;
|
||||
import org.springframework.messaging.handler.annotation.support.HeadersMethodArgumentResolver;
|
||||
import org.springframework.messaging.handler.annotation.support.MessageMethodArgumentResolver;
|
||||
import org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver;
|
||||
import org.springframework.messaging.handler.invocation.AbstractExceptionHandlerMethodResolver;
|
||||
import org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler;
|
||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.messaging.simp.SimpMessageMappingInfo;
|
||||
import org.springframework.messaging.simp.SimpMessageSendingOperations;
|
||||
import org.springframework.messaging.simp.SimpMessageTypeMessageCondition;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
||||
import org.springframework.messaging.simp.SimpMessageMappingInfo;
|
||||
import org.springframework.messaging.simp.SimpMessageTypeMessageCondition;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
@@ -58,11 +68,10 @@ import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* A handler for messages delegating to
|
||||
* {@link org.springframework.messaging.simp.annotation.SubscribeMapping @SubscribeMapping} and
|
||||
* {@link MessageMapping @MessageMapping} annotated methods.
|
||||
* <p>
|
||||
* Supports Ant-style path patterns with template variables.
|
||||
* A handler for messages delegating to {@link MessageMapping @MessageMapping}
|
||||
* and {@link SubscribeMapping @SubscribeMapping} annotated methods.
|
||||
*
|
||||
* <p>Supports Ant-style path patterns with template variables.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
@@ -93,7 +102,6 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
/**
|
||||
* Create an instance of SimpAnnotationMethodMessageHandler with the given
|
||||
* message channels and broker messaging template.
|
||||
*
|
||||
* @param clientInboundChannel the channel for receiving messages from clients (e.g. WebSocket clients)
|
||||
* @param clientOutboundChannel the channel for messages to clients (e.g. WebSocket clients)
|
||||
* @param brokerTemplate a messaging template to send application messages to the broker
|
||||
@@ -185,6 +193,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return true;
|
||||
@@ -226,8 +235,8 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
}
|
||||
}
|
||||
|
||||
protected List<HandlerMethodArgumentResolver> initArgumentResolvers() {
|
||||
|
||||
protected List<HandlerMethodArgumentResolver> initArgumentResolvers() {
|
||||
ConfigurableBeanFactory beanFactory =
|
||||
(ClassUtils.isAssignableValue(ConfigurableApplicationContext.class, getApplicationContext())) ?
|
||||
((ConfigurableApplicationContext) getApplicationContext()).getBeanFactory() : null;
|
||||
@@ -245,14 +254,13 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
|
||||
resolvers.addAll(getCustomArgumentResolvers());
|
||||
resolvers.add(new PayloadArgumentResolver(this.messageConverter,
|
||||
this.validator != null ? this.validator : new NoopValidator()));
|
||||
(this.validator != null ? this.validator : new NoopValidator())));
|
||||
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends HandlerMethodReturnValueHandler> initReturnValueHandlers() {
|
||||
|
||||
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
|
||||
|
||||
// Annotation-based return value types
|
||||
@@ -276,7 +284,6 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
|
||||
@Override
|
||||
protected SimpMessageMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
|
||||
MessageMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, MessageMapping.class);
|
||||
MessageMapping messageAnnot = AnnotationUtils.findAnnotation(method, MessageMapping.class);
|
||||
if (messageAnnot != null) {
|
||||
@@ -312,9 +319,9 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
@Override
|
||||
protected Set<String> getDirectLookupDestinations(SimpMessageMappingInfo mapping) {
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
for (String s : mapping.getDestinationConditions().getPatterns()) {
|
||||
if (!this.pathMatcher.isPattern(s)) {
|
||||
result.add(s);
|
||||
for (String pattern : mapping.getDestinationConditions().getPatterns()) {
|
||||
if (!this.pathMatcher.isPattern(pattern)) {
|
||||
result.add(pattern);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -362,14 +369,17 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
return new AnnotationExceptionHandlerMethodResolver(beanType);
|
||||
}
|
||||
|
||||
|
||||
private static final class NoopValidator implements Validator {
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,12 +35,14 @@ import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* {@link javax.servlet.Filter} that generates an {@code ETag} value based on the content on the response.
|
||||
* This ETag is compared to the {@code If-None-Match} header of the request. If these headers are equal,
|
||||
* the response content is not sent, but rather a {@code 304 "Not Modified"} status instead.
|
||||
* {@link javax.servlet.Filter} that generates an {@code ETag} value based on the
|
||||
* content on the response. This ETag is compared to the {@code If-None-Match}
|
||||
* header of the request. If these headers are equal, the response content is
|
||||
* not sent, but rather a {@code 304 "Not Modified"} status instead.
|
||||
*
|
||||
* <p>Since the ETag is based on the response content, the response (or {@link org.springframework.web.servlet.View})
|
||||
* is still rendered. As such, this filter only saves bandwidth, not server performance.
|
||||
* <p>Since the ETag is based on the response content, the response
|
||||
* (e.g. a {@link org.springframework.web.servlet.View}) is still rendered.
|
||||
* As such, this filter only saves bandwidth, not server performance.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -82,12 +84,11 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
private void updateResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
|
||||
ShallowEtagResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ShallowEtagResponseWrapper.class);
|
||||
ShallowEtagResponseWrapper responseWrapper =
|
||||
WebUtils.getNativeResponse(response, ShallowEtagResponseWrapper.class);
|
||||
Assert.notNull(responseWrapper, "ShallowEtagResponseWrapper not found");
|
||||
|
||||
response = (HttpServletResponse) responseWrapper.getResponse();
|
||||
|
||||
byte[] body = responseWrapper.toByteArray();
|
||||
int statusCode = responseWrapper.getStatusCode();
|
||||
|
||||
@@ -131,9 +132,8 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
* <ul>
|
||||
* <li>response status codes in the {@code 2xx} series</li>
|
||||
* <li>request method is a GET</li>
|
||||
* <li>response Cache-Control header is null or does not contain a "no-store" directive</li>
|
||||
* <li>response Cache-Control header is not set or does not contain a "no-store" directive</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param request the HTTP request
|
||||
* @param response the HTTP response
|
||||
* @param responseStatusCode the HTTP response status code
|
||||
@@ -143,10 +143,14 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response,
|
||||
int responseStatusCode, byte[] responseBody) {
|
||||
|
||||
return (responseStatusCode >= 200 && responseStatusCode < 300)
|
||||
&& HttpMethod.GET.name().equals(request.getMethod())
|
||||
&& (response.getHeader(HEADER_CACHE_CONTROL) == null
|
||||
|| !response.getHeader(HEADER_CACHE_CONTROL).contains(DIRECTIVE_NO_STORE));
|
||||
if (responseStatusCode >= 200 && responseStatusCode < 300 &&
|
||||
HttpMethod.GET.name().equals(request.getMethod())) {
|
||||
String cacheControl = response.getHeader(HEADER_CACHE_CONTROL);
|
||||
if (cacheControl == null || !cacheControl.contains(DIRECTIVE_NO_STORE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +243,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
private int getStatusCode() {
|
||||
return statusCode;
|
||||
return this.statusCode;
|
||||
}
|
||||
|
||||
private byte[] toByteArray() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,7 +29,7 @@ import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.web.context.support.ServletContextResourcePatternResolver;
|
||||
|
||||
/**
|
||||
* Spring-specific subclass of the ServletTilesApplicationContext.
|
||||
* Spring-specific subclass of the Tiles ServletTilesApplicationContext.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0.1
|
||||
@@ -67,4 +67,5 @@ public class SpringWildcardServletTilesApplicationContext extends ServletTilesAp
|
||||
}
|
||||
return urlSet;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user