001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.handler; 018 019import java.util.Collections; 020import java.util.Enumeration; 021 022import javax.servlet.Servlet; 023import javax.servlet.ServletConfig; 024import javax.servlet.ServletContext; 025import javax.servlet.ServletException; 026 027import org.springframework.beans.BeansException; 028import org.springframework.beans.factory.BeanInitializationException; 029import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; 030import org.springframework.lang.Nullable; 031import org.springframework.web.context.ServletConfigAware; 032import org.springframework.web.context.ServletContextAware; 033 034/** 035 * {@link org.springframework.beans.factory.config.BeanPostProcessor} 036 * that applies initialization and destruction callbacks to beans that 037 * implement the {@link javax.servlet.Servlet} interface. 038 * 039 * <p>After initialization of the bean instance, the Servlet {@code init} 040 * method will be called with a ServletConfig that contains the bean name 041 * of the Servlet and the ServletContext that it is running in. 042 * 043 * <p>Before destruction of the bean instance, the Servlet {@code destroy} 044 * will be called. 045 * 046 * <p><b>Note that this post-processor does not support Servlet initialization 047 * parameters.</b> Bean instances that implement the Servlet interface are 048 * supposed to be configured like any other Spring bean, that is, through 049 * constructor arguments or bean properties. 050 * 051 * <p>For reuse of a Servlet implementation in a plain Servlet container 052 * and as a bean in a Spring context, consider deriving from Spring's 053 * {@link org.springframework.web.servlet.HttpServletBean} base class that 054 * applies Servlet initialization parameters as bean properties, supporting 055 * both the standard Servlet and the Spring bean initialization style. 056 * 057 * <p><b>Alternatively, consider wrapping a Servlet with Spring's 058 * {@link org.springframework.web.servlet.mvc.ServletWrappingController}.</b> 059 * This is particularly appropriate for existing Servlet classes, 060 * allowing to specify Servlet initialization parameters etc. 061 * 062 * @author Juergen Hoeller 063 * @since 1.1.5 064 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) 065 * @see javax.servlet.Servlet#destroy() 066 * @see SimpleServletHandlerAdapter 067 */ 068public class SimpleServletPostProcessor implements 069 DestructionAwareBeanPostProcessor, ServletContextAware, ServletConfigAware { 070 071 private boolean useSharedServletConfig = true; 072 073 @Nullable 074 private ServletContext servletContext; 075 076 @Nullable 077 private ServletConfig servletConfig; 078 079 080 /** 081 * Set whether to use the shared ServletConfig object passed in 082 * through {@code setServletConfig}, if available. 083 * <p>Default is "true". Turn this setting to "false" to pass in 084 * a mock ServletConfig object with the bean name as servlet name, 085 * holding the current ServletContext. 086 * @see #setServletConfig 087 */ 088 public void setUseSharedServletConfig(boolean useSharedServletConfig) { 089 this.useSharedServletConfig = useSharedServletConfig; 090 } 091 092 @Override 093 public void setServletContext(ServletContext servletContext) { 094 this.servletContext = servletContext; 095 } 096 097 @Override 098 public void setServletConfig(ServletConfig servletConfig) { 099 this.servletConfig = servletConfig; 100 } 101 102 103 @Override 104 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 105 return bean; 106 } 107 108 @Override 109 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 110 if (bean instanceof Servlet) { 111 ServletConfig config = this.servletConfig; 112 if (config == null || !this.useSharedServletConfig) { 113 config = new DelegatingServletConfig(beanName, this.servletContext); 114 } 115 try { 116 ((Servlet) bean).init(config); 117 } 118 catch (ServletException ex) { 119 throw new BeanInitializationException("Servlet.init threw exception", ex); 120 } 121 } 122 return bean; 123 } 124 125 @Override 126 public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { 127 if (bean instanceof Servlet) { 128 ((Servlet) bean).destroy(); 129 } 130 } 131 132 @Override 133 public boolean requiresDestruction(Object bean) { 134 return (bean instanceof Servlet); 135 } 136 137 138 /** 139 * Internal implementation of the {@link ServletConfig} interface, 140 * to be passed to the wrapped servlet. 141 */ 142 private static class DelegatingServletConfig implements ServletConfig { 143 144 private final String servletName; 145 146 @Nullable 147 private final ServletContext servletContext; 148 149 public DelegatingServletConfig(String servletName, @Nullable ServletContext servletContext) { 150 this.servletName = servletName; 151 this.servletContext = servletContext; 152 } 153 154 @Override 155 public String getServletName() { 156 return this.servletName; 157 } 158 159 @Override 160 @Nullable 161 public ServletContext getServletContext() { 162 return this.servletContext; 163 } 164 165 @Override 166 @Nullable 167 public String getInitParameter(String paramName) { 168 return null; 169 } 170 171 @Override 172 public Enumeration<String> getInitParameterNames() { 173 return Collections.enumeration(Collections.emptySet()); 174 } 175 } 176 177}