/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.citrus.springext.support.context;
import static com.alibaba.citrus.test.TestEnvStatic.*;
import static com.alibaba.citrus.test.TestUtil.*;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.io.File;
import java.lang.reflect.Proxy;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.citrus.springext.util.ProxyTargetFactory;
import com.meterware.servletunit.ServletRunner;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.io.ResourceLoader;
/**
* 确保singleton proxy可以工作。设计以下情形:
* <ul>
* <li>parent context中被置入了resolvableDependencies。</li>
* <li>this context中被置入了同名的dependencies。</li>
* <li>利用autowire注入对象,应该被注入parent中的对象。</li>
* </ul>
*
* @author Michael Zhou
*/
public class InheritableBeanFactoryTests {
private XmlWebApplicationContext parentContext;
private XmlWebApplicationContext thisContext;
private void initContext(boolean withMockRequest) throws Exception {
ServletContext servletContext = new ServletRunner(new File(srcdir, "WEB-INF/web.xml"), "").newClient()
.newInvocation("http://localhost/servlet").getServlet().getServletConfig().getServletContext();
// parent context,如果withMockRequest,则注册并覆盖原有的request
parentContext = new XmlWebApplicationContext();
parentContext.setConfigLocation(withMockRequest ? "beans-autowire-parent.xml" : "beans.xml");
parentContext.setServletContext(servletContext);
parentContext.refresh();
// this context将会重新注册request,但是由于parent中已经注册了,不会被覆盖
thisContext = new XmlWebApplicationContext();
thisContext.setConfigLocation("beans-autowire.xml");
thisContext.setServletContext(servletContext);
thisContext.setParent(parentContext);
thisContext.refresh();
}
/** 如果parent context中被置入mock request,那么取得并注入到autowire对象中。 */
@Test
public void request1() throws Exception {
initContext(true);
MyObject obj = (MyObject) thisContext.getBean("autowiredObject");
assertEquals("mock_uri", obj.request.getRequestURI());
assertSame(thisContext, obj.resourceLoader); // 确保非ProxyTargetFactory接口的对象不受影响
}
/** 如果parent context中没有置入mock request,那么autowire试图取得request失败。 */
@Test
public void request2() throws Exception {
try {
// 对于spring2,这一步就会抛出IllegalStateException: no thread-bound request found.
initContext(false);
// 对于spring3,会将request访问推迟到执行request方法时,才会抛出IllegalStateException: no thread-bound request found.
// 这一点和request context的手法相同,但是由于request context采用了cglib,所以性能上更好一点。
MyObject obj = (MyObject) thisContext.getBean("autowiredObject");
assertTrue(Proxy.isProxyClass(obj.request.getClass()));
assertSame(thisContext, obj.resourceLoader); // 确保非ProxyTargetFactory接口的对象不受影响
obj.request.getRequestURI();
fail();
} catch (Exception e) {
assertThat(e, exception(IllegalStateException.class, "No thread-bound request found"));
}
}
public static class RequestPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
HttpServletRequest mockRequest = createMock(RequestProxy.class);
expect(mockRequest.getRequestURI()).andReturn("mock_uri").anyTimes();
replay(mockRequest);
beanFactory.registerResolvableDependency(ServletRequest.class, mockRequest);
}
}
public static interface RequestProxy extends HttpServletRequest, ProxyTargetFactory {
}
public static class MyObject {
@Autowired(required = false)
private HttpServletRequest request;
@Autowired
private ResourceLoader resourceLoader;
}
}