在本文中,我们将给您介绍关于了解servlet容器的详细内容,并且为您解答servlet容器的概念和作用的相关问题,此外,我们还将为您提供关于18、配置嵌入式servlet容器(2)、19、配置嵌入式
在本文中,我们将给您介绍关于了解servlet容器的详细内容,并且为您解答servlet容器的概念和作用的相关问题,此外,我们还将为您提供关于18、配置嵌入式servlet容器(2)、19、配置嵌入式servlet容器(下)、8、Servlet容器启动解析、cxf webservice部署servlet容器报错的知识。
本文目录一览:- 了解servlet容器(servlet容器的概念和作用)
- 18、配置嵌入式servlet容器(2)
- 19、配置嵌入式servlet容器(下)
- 8、Servlet容器启动解析
- cxf webservice部署servlet容器报错
了解servlet容器(servlet容器的概念和作用)
作为一个UI开发人员以及对Java知识非常了解的人,我如何简单地理解servlet容器到底是什么?
我听说过Weblogic,JBoss等是servlet容器,但是不确定这到底意味着什么。这是否意味着任何中间件技术?
请你帮助我好吗。
答案1
小编典典Servlet容器是实现Java Servlet规范的某些版本的应用程序服务器。
简而言之,servlet规范定义了一种编程模型,该模型允许开发人员编写处理请求(几乎总是HTTP请求)的组件,例如servlet。然后可以将这些组件声明到容器中,并处理与连接和管理这些组件相关的许多繁琐任务,以便它们可以处理这些请求。
18、配置嵌入式servlet容器(2)
使用其他Servlet容器
替换为其他嵌入式Servlet容器
Jetty:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入其他的Servlet -->
<dependency>
<artifactId>spring‐boot‐starter‐jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
Undertow:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--引入其他的Servlet -->
<dependency>
<artifactId>spring‐boot‐starter‐undertow<</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
右键排除依赖
嵌入式Servlet配置原理:
Servelt容器的自动配置类
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties({ServerProperties.class})
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
public EmbeddedWebServerFactoryCustomizerAutoConfiguration() {
}
@Configuration
@ConditionalOnClass({HttpServer.class})
public static class NettyWebServerFactoryCustomizerConfiguration {
public NettyWebServerFactoryCustomizerConfiguration() {
}
@Bean
public NettyWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
return new NettyWebServerFactoryCustomizer(environment, serverProperties);
}
}
@Configuration
@ConditionalOnClass({Undertow.class, SslClientAuthMode.class})
public static class UndertowWebServerFactoryCustomizerConfiguration {
public UndertowWebServerFactoryCustomizerConfiguration() {
}
@Bean
public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
}
}
@Configuration
@ConditionalOnClass({Server.class, Loader.class, WebAppContext.class})
public static class JettyWebServerFactoryCustomizerConfiguration {
public JettyWebServerFactoryCustomizerConfiguration() {
}
@Bean
public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties);
}
}
@Configuration
@ConditionalOnClass({Tomcat.class, UpgradeProtocol.class})
public static class TomcatWebServerFactoryCustomizerConfiguration {
public TomcatWebServerFactoryCustomizerConfiguration() {
}
@Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
}
}
}
TomcatWebServerFactoryCustomizer.java
public class TomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {
private final Environment environment;
private final ServerProperties serverProperties;
public TomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
this.environment = environment;
this.serverProperties = serverProperties;
}
public int getOrder() {
return 0;
}
public void customize(ConfigurableTomcatWebServerFactory factory) {
ServerProperties properties = this.serverProperties;
Tomcat tomcatProperties = properties.getTomcat();
PropertyMapper propertyMapper = PropertyMapper.get();
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getBasedir).whenNonNull().to(factory::setBaseDirectory);
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull().as(Duration::getSeconds).as(Long::intValue).to(factory::setBackgroundProcessorDelay);
this.customizeRemoteIpValve(factory);
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive).to((maxThreads) -> {
this.customizeMaxThreads(factory, tomcatProperties.getMaxThreads());
});
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive).to((minSpareThreads) -> {
this.customizeMinThreads(factory, minSpareThreads);
});
propertyMapper.from(this::determineMaxHttpHeaderSize).whenNonNull().asInt(DataSize::toBytes).when(this::isPositive).to((maxHttpHeaderSize) -> {
this.customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize);
});
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull().asInt(DataSize::toBytes).to((maxSwallowSize) -> {
this.customizeMaxSwallowSize(factory, maxSwallowSize);
});
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getMaxHttpPostSize).asInt(DataSize::toBytes).when((maxHttpPostSize) -> {
return maxHttpPostSize != 0;
}).to((maxHttpPostSize) -> {
this.customizeMaxHttpPostSize(factory, maxHttpPostSize);
});
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getAccesslog).when(Accesslog::isEnabled).to((enabled) -> {
this.customizeAccessLog(factory);
});
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding);
properties.getClass();
propertyMapper.from(properties::getConnectionTimeout).whenNonNull().to((connectionTimeout) -> {
this.customizeConnectionTimeout(factory, connectionTimeout);
});
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive).to((maxConnections) -> {
this.customizeMaxConnections(factory, maxConnections);
});
tomcatProperties.getClass();
propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive).to((acceptCount) -> {
this.customizeAcceptCount(factory, acceptCount);
});
this.customizeStaticResources(factory);
this.customizeErrorReportValve(properties.getError(), factory);
}
.......
}
嵌入式Servlet容器启动原理;
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
;
}
}
}
19、配置嵌入式servlet容器(下)
使用外置的Servlet
添加xml配置文件
完成hello.jsp页面的跳转
hello.jsp
test.jsp
test.java
测试:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
3)、必须编写一个SpringBootServletInitializer的子类,并调用configure方法
4)、启动服务器就可以使用
原理:
流程:
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public SpringServletContainerInitializer() {
}
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
if (webAppInitializerClasses != null) {
var4 = webAppInitializerClasses.iterator();
while(var4.hasNext()) {
Class<?> waiClass = (Class)var4.next();
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
} catch (Throwable var7) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
} else {
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
var4 = initializers.iterator();
while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
initializer.onStartup(servletContext);
}}}}
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebJspApplication.class);
}
}
SpringBootServletInitializer.java
public void onStartup(ServletContext servletContext) throws ServletException {
this.logger = LogFactory.getLog(this.getClass());
WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
if (rootAppContext != null) {
servletContext.addListener(new ContextLoaderListener(rootAppContext) {
public void contextInitialized(ServletContextEvent event) {
}
});
} else {
this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
}
}
.....
protected WebApplicationContext createRootApplicationContext(
ServletContext servletContext) {
//1、创建SpringApplicationBuilder
SpringApplicationBuilder builder = createSpringApplicationBuilder();
StandardServletEnvironment environment = new StandardServletEnvironment();
environment.initPropertySources(servletContext, null);
builder.environment(environment);
builder.main(getClass());
ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
if (parent != null) {
this.logger.info("Root context already created (using as parent).");
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
builder.initializers(new ParentContextApplicationContextInitializer(parent));
}
builder.initializers(
new ServletContextApplicationContextInitializer(servletContext));
builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
//调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来
builder = configure(builder);
//使用builder创建一个Spring应用
SpringApplication application = builder.build();
if (application.getSources().isEmpty() && AnnotationUtils
.findAnnotation(getClass(), Configuration.class) != null) {
application.getSources().add(getClass());
}
Assert.state(!application.getSources().isEmpty(),
"No SpringApplication sources have been defined. Either override the "
+ "configure method or add an @Configuration annotation");
// Ensure error pages are registered
if (this.registerErrorPageFilter) {
application.getSources().add(ErrorPageFilterConfiguration.class);
}
//启动Spring应用
return run(application);
}
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新容器的初始化
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
8、Servlet容器启动解析
1.1、简介
SpringBoot1.x只区分web环境和非web环境,而在2.x版本中引入了Reactive环境,即响应式环境.那么现在SpringBoot支持三种环境:
Servlet的web环境、Reactive的web环境以及非web环境.90%以上的公司使用的是Servlet的web环境,而该环境默认使用的是tomcat容器,
本章内容主要是介绍Servlet容器启动流程.
1.2、全局流程解析
// 容器刷新的核心流程,之前已经分析过了
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 走到这里,这里会启动web服务器
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
}
}
// 走到这里,这里会启动web服务器
onRefresh();
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
}
private void createWebServer() {
// 刚开始这两个属性都为null
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 走到这步获取factory
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
}
initPropertySources();
}
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don''t consider the hierarchy
// 默认返回只有一个,tomcatServletWebServerFactory,下面第三节会分析这个bean定义什么时候被加载到容器中
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
// 抛异常
}
if (beanNames.length > 1) {
// 抛异常
}
// 调用getBean创建工厂类实例
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
// this.webServer = factory.getWebServer(getSelfInitializer())
// 调用这个创建webServer
public WebServer getWebServer(ServletContextInitializer... initializers) {
// 创建一个tomcat
Tomcat tomcat = new Tomcat();
// 设置基础目录等属性
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
// 这步就创建一个TomcatWebServer,里面还会做一些事情,以后分析
return new TomcatWebServer(tomcat, getPort() >= 0);
}
initPropertySources();
protected void initPropertySources() {
ConfigurableEnvironment env = getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
}
}
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
public static void initServletPropertySources(MutablePropertySources sources,
@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
// servletContextInitParams
String name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;
// 判断servletContext不为null且包含这个servletContextInitParams属性集
if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
// 封装一个ServletContextPropertySource属性集替换原有的
sources.replace(name, new ServletContextPropertySource(name, servletContext));
}
name = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;
// servletConfig默认为null
if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
}
}
// onRefresh方法结束后,我们看finishRefresh方法
// Last step: publish corresponding event.
finishRefresh();
protected void finishRefresh() {
super.finishRefresh();
WebServer webServer = startWebServer();
if (webServer != null) {
// 发布Server初始完毕事件
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
}
private WebServer startWebServer() {
WebServer webServer = this.webServer;
if (webServer != null) {
webServer.start();
}
return webServer;
}
1.3、web容器工厂类加载解析
// 默认返回只有一个,tomcatServletWebServerFactory,那么这个bean定义什么时候被加载到容器中
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
// 它是通过@Import注解导入到容器中的
public void parse(Set<beandefinitionholder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
}
// 这边会处理@Import注解导入的配置类
this.deferredImportSelectorHandler.process();
}
public void process() {
List<deferredimportselectorholder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 排序并依此遍历调用register方法
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
public void register(DeferredImportSelectorHolder deferredImport) {
// 这个返回的Selector就是AutoConfigurationImportSelector,这也是@SpringBootApplication上通过@Import注解
// 导入的Selector. getImportGroup返回的是AutoConfigurationGroup.class
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
// computeIfAbsent就是不存在就创建,这边也是创建一个grouping
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
// this.deferredImports.add(deferredImport);
// 加入到了deferredImports中,List<deferredimportselectorholder> deferredImports = new ArrayList<>()
grouping.add(deferredImport);
// 放入到configurationClasses中
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
// 这边主要是构造了一个grouping,在下一步进行处理
deferredImports.forEach(handler::register);
handler.processGroupImports();
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 下面先分析这个getImports方法
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
}
});
}
}
public Iterable<group.entry> getImports() {
// 这边的deferredImports是通过grouping.add(deferredImport)添加进去的
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
// 两个参数如下图所示,annotationMetadata是主配置类上面的注解
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
// 下面先分析下这个getAutoConfigurationEntry方法
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
// 加入到这个autoConfigurationEntries中
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
// 接着依次遍历放入到这个map中,Map<string, annotationmetadata> entries = new LinkedHashMap<>()
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
// 这边就到了AutoConfigurationImportSelector类的方法中
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
// 判断是否支持自动配置
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 这个attributes属性就是上图中显示的,用来过滤自动配置类的
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 下面分析这个方法,这个就是加载容器中的自动配置类
List<string> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去除重复的,方法就是放入set再放入list中
configurations = removeDuplicates(configurations);
// 去除掉应该被排除的
Set<string> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 通过filter过滤,下面分析,过滤完发现只有22个了
configurations = filter(configurations, autoConfigurationMetadata);
// 发布一个事件,好像没有做啥关键的
fireAutoConfigurationImportEvents(configurations, exclusions);
// 将configurations封装成AutoConfigurationEntry返回
return new AutoConfigurationEntry(configurations, exclusions);
}
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
// 判断有没有配置这个属性,没有的话默认为true,
// String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
protected List<string> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// getSpringFactoriesLoaderFactoryClass()返回EnableAutoConfiguration.class,那么这边就是获取容器中所有的字段配置类
// 见下图,默认总共有118个
List<string> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
return configurations;
}
private List<string> filter(List<string> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List<string> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
return new ArrayList<>(result);
}
protected List<autoconfigurationimportfilter> getAutoConfigurationImportFilters() {
// 看一下这个过滤的逻辑,看下图它的实现类大概就知道它是怎样过滤了
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
// 下面解释下1.3节提出的问题,tomcatServletWebServerFactory,这个bean定义什么时候被加载到容器中
// filter之后的中有一个是org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
// 会Import一个这个
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
@Configuration
class ServletWebServerFactoryConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
// 这边就会创建一个TomcatServletWebServerFactory
return new TomcatServletWebServerFactory();
}
}}
// 到此为止grouping.getImports方法分析完了,它是返回之前加载的22个自动配置类
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 下面先分析这个getImports方法
grouping.getImports().forEach(entry -> {
// 这边这个configurationClass获取的还是主配置类SpringbootApplication
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
// 调用processImports方法处理,这个方法之前已经分析过了
processImports(configurationClass, asSourceClass(configurationClass),
asSourceClasses(entry.getImportClassName()), false);
}
});
}
}
1.4、Web容器个性化配置解析
// 入口,onRefresh方法中会创建webServer,走到这里
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don''t consider the hierarchy
// 默认返回只有一个,tomcatServletWebServerFactory,下面第三节会分析这个bean定义什么时候被加载到容器中
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
// 抛异常
}
if (beanNames.length > 1) {
// 抛异常
}
// 调用getBean创建工厂类实例,这边会调用getBean开始创建bean实例对象,这个步骤之前已经分析过了
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 当中有一个WebServerFactoryCustomizerBeanPostProcessor
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
// 走到这里,WebServerFactoryCustomizerBeanPostProcessor
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebServerFactory) {
postProcessBeforeInitialization((WebServerFactory) bean);
}
return bean;
}
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
// 先看下getCustomizers方法
// 这边lamda表达式的意思就是遍历getCustomizers方法,通过invoke调用每个customizer.cutomize方法定制修改web容器
LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
.invoke((customizer) -> customizer.customize(webServerFactory));
}
private Collection<webserverfactorycustomizer<?>> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
// 获取容器中的所有WebServerFactoryCustomizer,待会我们分析下第二个Customizer
this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
private Collection<webserverfactorycustomizer<?>> getWebServerFactoryCustomizerBeans() {
return (Collection) this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
}
// 我们先来看下上图中第二个定制器,ServletWebServerFactoryCustomizer
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
// 它是怎么引入到容器中的呢?它是通过ServletWebServerFactoryAutoConfiguration的bean方法引入到的,
// 并且赋值serverProperties
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
}
// 这就是我们在application.properties中修改port,会被赋值到这里,然后定制器就可以取到
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
private Integer port;
private InetAddress address;
// 省略一些
}
// 然后我们再来看invoke((customizer) -> customizer.customize(webServerFactory))这个步骤,这会调用每个定制器的定制方法
// 具体我们看下ServletWebServerFactoryCustomizer的cutomize方法
public class ServletWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<configurableservletwebserverfactory>, Ordered {
private final ServerProperties serverProperties;
public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
this.serverProperties = serverProperties;
}
@Override
public int getOrder() {
return 0;
}
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
// 这边是lamda表达式,调用factory.setPort进行赋值
map.from(this.serverProperties::getPort).to(factory::setPort);
map.from(this.serverProperties::getAddress).to(factory::setAddress);
map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);
map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);
map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
map.from(this.serverProperties::getSsl).to(factory::setSsl);
map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
map.from(this.serverProperties::getCompression).to(factory::setCompression);
map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
}
}
cxf webservice部署servlet容器报错
异常信息如下:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ''helloWorld'': Invocation of init method Failed; nested exception is java.lang.NoSuchMethodError: javax.wsdl.xml.WSDLReader.readWSDL(Ljavax/wsdl/xml/WSDLLocator;Lorg/w3c/dom/Element;)Ljavax/wsdl/DeFinition;
at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.initializeBean(AbstractAutowireCapablebeanfactory.java:1422)
at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.doCreateBean(AbstractAutowireCapablebeanfactory.java:518)
at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.createBean(AbstractAutowireCapablebeanfactory.java:455)
at org.springframework.beans.factory.support.Abstractbeanfactory$1.getobject(Abstractbeanfactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.Abstractbeanfactory.doGetBean(Abstractbeanfactory.java:290)
at org.springframework.beans.factory.support.Abstractbeanfactory.getBean(Abstractbeanfactory.java:192)
at org.springframework.beans.factory.support.DefaultListablebeanfactory.preInstantiateSingletons(DefaultListablebeanfactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishbeanfactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.apache.cxf.transport.servlet.CXFServlet.createSpringContext(CXFServlet.java:160)
at org.apache.cxf.transport.servlet.CXFServlet.loadBus(CXFServlet.java:74)
at org.apache.cxf.transport.servlet.CXFNonspringServlet.init(CXFNonspringServlet.java:71)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4420)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4733)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:601)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:675)
at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:601)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1315)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1061)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: java.lang.NoSuchMethodError: javax.wsdl.xml.WSDLReader.readWSDL(Ljavax/wsdl/xml/WSDLLocator;Lorg/w3c/dom/Element;)Ljavax/wsdl/DeFinition;
at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDeFinition(WSDLManagerImpl.java:260)
at org.apache.cxf.wsdl11.WSDLManagerImpl.getDeFinition(WSDLManagerImpl.java:205)
at org.apache.cxf.service.factory.ReflectionServicefactorybean.isEmptywsdl(ReflectionServicefactorybean.java:2590)
at org.apache.cxf.service.factory.ReflectionServicefactorybean.isFromWsdl(ReflectionServicefactorybean.java:531)
at org.apache.cxf.service.factory.ReflectionServicefactorybean.initializeServiceModel(ReflectionServicefactorybean.java:537)
at org.apache.cxf.service.factory.ReflectionServicefactorybean.create(ReflectionServicefactorybean.java:252)
at org.apache.cxf.jaxws.support.JaxWsServicefactorybean.create(JaxWsServicefactorybean.java:205)
at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:101)
at org.apache.cxf.frontend.Serverfactorybean.create(Serverfactorybean.java:159)
at org.apache.cxf.jaxws.JaxWsServerfactorybean.create(JaxWsServerfactorybean.java:211)
at org.apache.cxf.jaxws.EndpointImpl.getServer(EndpointImpl.java:454)
at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:334)
at org.apache.cxf.jaxws.EndpointImpl.publish(EndpointImpl.java:251)
at org.apache.cxf.ws.discovery.internal.WSdiscoveryServiceImpl.startup(WSdiscoveryServiceImpl.java:197)
at org.apache.cxf.ws.discovery.internal.WSdiscoveryServiceImpl.serverStarted(WSdiscoveryServiceImpl.java:122)
at org.apache.cxf.ws.discovery.listeners.WSdiscoveryServerListener.startServer(WSdiscoveryServerListener.java:72)
at org.apache.cxf.bus.managers.ServerLifeCycleManagerImpl.startServer(ServerLifeCycleManagerImpl.java:61)
at org.apache.cxf.endpoint.ServerImpl.start(ServerImpl.java:146)
at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:360)
at org.apache.cxf.jaxws.EndpointImpl.publish(EndpointImpl.java:251)
at org.apache.cxf.jaxws.EndpointImpl.publish(EndpointImpl.java:537)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.invokeCustomInitMethod(AbstractAutowireCapablebeanfactory.java:1546)
at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.invokeInitMethods(AbstractAutowireCapablebeanfactory.java:1487)
at org.springframework.beans.factory.support.AbstractAutowireCapablebeanfactory.initializeBean(AbstractAutowireCapablebeanfactory.java:1419)
... 38 more
原因是你的容器中有多个wsdl4j-*.jar包。cxf 正确的包是wsdl4j-1.6.2.jar.
解决的办法就是只保留wsdl4j-1.6.2.jar 。删除掉其他的wsdl4j-*.jar.
关于了解servlet容器和servlet容器的概念和作用的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于18、配置嵌入式servlet容器(2)、19、配置嵌入式servlet容器(下)、8、Servlet容器启动解析、cxf webservice部署servlet容器报错等相关内容,可以在本站寻找。
本文标签: