001/* 002 * Copyright 2012-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 * http://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.boot.autoconfigure.web; 018 019import javax.servlet.Servlet; 020 021import io.undertow.Undertow; 022import org.apache.catalina.startup.Tomcat; 023import org.eclipse.jetty.server.Server; 024import org.eclipse.jetty.util.Loader; 025import org.eclipse.jetty.webapp.WebAppContext; 026import org.xnio.SslClientAuthMode; 027 028import org.springframework.beans.BeansException; 029import org.springframework.beans.factory.BeanFactory; 030import org.springframework.beans.factory.BeanFactoryAware; 031import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 032import org.springframework.beans.factory.support.BeanDefinitionRegistry; 033import org.springframework.beans.factory.support.RootBeanDefinition; 034import org.springframework.boot.autoconfigure.AutoConfigureOrder; 035import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 036import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 037import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 038import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 039import org.springframework.boot.autoconfigure.condition.SearchStrategy; 040import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration.BeanPostProcessorsRegistrar; 041import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; 042import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; 043import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory; 044import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; 045import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory; 046import org.springframework.boot.web.servlet.ErrorPageRegistrarBeanPostProcessor; 047import org.springframework.context.annotation.Bean; 048import org.springframework.context.annotation.Configuration; 049import org.springframework.context.annotation.Import; 050import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; 051import org.springframework.core.Ordered; 052import org.springframework.core.type.AnnotationMetadata; 053import org.springframework.util.ObjectUtils; 054 055/** 056 * {@link EnableAutoConfiguration Auto-configuration} for an embedded servlet containers. 057 * 058 * @author Phillip Webb 059 * @author Dave Syer 060 * @author Ivan Sopov 061 * @author Stephane Nicoll 062 */ 063@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) 064@Configuration 065@ConditionalOnWebApplication 066@Import(BeanPostProcessorsRegistrar.class) 067public class EmbeddedServletContainerAutoConfiguration { 068 069 /** 070 * Nested configuration if Tomcat is being used. 071 */ 072 @Configuration 073 @ConditionalOnClass({ Servlet.class, Tomcat.class }) 074 @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) 075 public static class EmbeddedTomcat { 076 077 @Bean 078 public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { 079 return new TomcatEmbeddedServletContainerFactory(); 080 } 081 082 } 083 084 /** 085 * Nested configuration if Jetty is being used. 086 */ 087 @Configuration 088 @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, 089 WebAppContext.class }) 090 @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) 091 public static class EmbeddedJetty { 092 093 @Bean 094 public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() { 095 return new JettyEmbeddedServletContainerFactory(); 096 } 097 098 } 099 100 /** 101 * Nested configuration if Undertow is being used. 102 */ 103 @Configuration 104 @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class }) 105 @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) 106 public static class EmbeddedUndertow { 107 108 @Bean 109 public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() { 110 return new UndertowEmbeddedServletContainerFactory(); 111 } 112 113 } 114 115 /** 116 * Registers a {@link EmbeddedServletContainerCustomizerBeanPostProcessor}. Registered 117 * via {@link ImportBeanDefinitionRegistrar} for early registration. 118 */ 119 public static class BeanPostProcessorsRegistrar 120 implements ImportBeanDefinitionRegistrar, BeanFactoryAware { 121 122 private ConfigurableListableBeanFactory beanFactory; 123 124 @Override 125 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 126 if (beanFactory instanceof ConfigurableListableBeanFactory) { 127 this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; 128 } 129 } 130 131 @Override 132 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, 133 BeanDefinitionRegistry registry) { 134 if (this.beanFactory == null) { 135 return; 136 } 137 registerSyntheticBeanIfMissing(registry, 138 "embeddedServletContainerCustomizerBeanPostProcessor", 139 EmbeddedServletContainerCustomizerBeanPostProcessor.class); 140 registerSyntheticBeanIfMissing(registry, 141 "errorPageRegistrarBeanPostProcessor", 142 ErrorPageRegistrarBeanPostProcessor.class); 143 } 144 145 private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, 146 String name, Class<?> beanClass) { 147 if (ObjectUtils.isEmpty( 148 this.beanFactory.getBeanNamesForType(beanClass, true, false))) { 149 RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); 150 beanDefinition.setSynthetic(true); 151 registry.registerBeanDefinition(name, beanDefinition); 152 } 153 } 154 155 } 156 157}