如何注册
1.注解+启动类扫描
@ServletComponentScan
@SpringBootApplication
public class SpringbootUploadApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootUploadApplication.class, args);
}
}
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.err.println("MyServlet doGet");
resp.getWriter().write("my");
}
}
@WebFilter(urlPatterns = "/my")
public class MyFilter extends HttpFilter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
System.err.println("MyFilter doFilter");
chain.doFilter(request,response);
}
}
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.err.println("MyListener contextInitialized"+sce.getServletContext().getServerInfo());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
2.注册ServletRegistrationBean
还是这三个组件,不过把注解@WebServlet/@WebFilter/@WebListener去掉,自动扫描就失效了
取而代之配置类去注册
@Configuration
public class ServletConfig {
@Bean
public ServletRegistrationBean myServlet(){
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
MyListener mySwervletContextListener = new MyListener();
return new ServletListenerRegistrationBean(mySwervletContextListener);
}
}
源码
先看看注册Bean的类图
感觉用不上,不想看源码 蛋疼,硬着头皮早上写!干饭
- SpringApplication#refreshContext
- AnnotationConfigServletWebServerApplicationContext#refresh #onRefresh
- TomcatServletWebServerFactory 创建tomcat服务器并start
下面就是tomcat流程
接下来就是异步任务
子类调用父类
public class StandardEngine extends ContainerBase implements Engine {
@Override
protected synchronized void startInternal() throws LifecycleException {
// Log our server identification information
if (log.isInfoEnabled()) {
log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo()));
}
// Standard container startup
super.startInternal();
}
}
父类方法逻辑
public abstract class ContainerBase extends LifecycleMBeanBase implements Container {
@Override
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
logger = null;
getLogger();
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (Container child : children) {
results.add(startStopExecutor.submit(new StartChild(child)));
}
MultiThrowable multiThrowable = null;
for (Future<Void> result : results) {
try {
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
multiThrowable.add(e);
}
}
if (multiThrowable != null) {
throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
multiThrowable.getThrowable());
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
setState(LifecycleState.STARTING);
// Start our thread
if (backgroundProcessorDelay > 0) {
monitorFuture = Container.getService(ContainerBase.this).getServer()
.getUtilityExecutor().scheduleWithFixedDelay(
new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS);
}
}
}
然后其中一个异步任务就会执行以下逻辑,具体跟不到是哪里
StandardHost->异步->TomcatEmbeddedContext#start->#startInternal->
部分逻辑
public class StandardContext extends ContainerBase implements Context, NotificationEmitter {
@Override
protected synchronized void startInternal() throws LifecycleException {
// Call ServletContainerInitializers
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(),
getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
}
}
class TomcatStarter implements ServletContainerInitializer {
//有三个,见下图
private final ServletContextInitializer[] initializers;
@Override
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
try {
for (ServletContextInitializer initializer : this.initializers) {
initializer.onStartup(servletContext);
}
}
catch (Exception ex) {
this.startUpException = ex;
// Prevent Tomcat from logging and re-throwing when we know we can
// deal with it in the main thread, but log for information here.
if (logger.isErrorEnabled()) {
logger.error("Error starting Tomcat context. Exception: " + ex.getClass().getName() + ". Message: "
+ ex.getMessage());
}
}
}
}
好像起作用的是第一个噢!只不过是一个接口函数声明,看不到是啥样的
public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext {
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
return new ServletContextInitializerBeans(getBeanFactory());
}
}
调用关系图
public class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> {
@SafeVarargs
@SuppressWarnings("varargs")
public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
Class<? extends ServletContextInitializer>... initializerTypes) {
this.initializers = new LinkedMultiValueMap<>();
this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
: Collections.singletonList(ServletContextInitializer.class);
//1添加初始化Bean
addServletContextInitializerBeans(beanFactory);
//2添加适配Bean
addAdaptableBeans(beanFactory);
//3排序
List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
.collect(Collectors.toList());
this.sortedList = Collections.unmodifiableList(sortedInitializers);
logMappings(this.initializers);
}
//1添加初始化Bean
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,initializerType)) {
addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
}
}
}
//通用获取接口
private <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type) {
return getOrderedBeansOfType(beanFactory, type, Collections.emptySet());
}
//这里的type就是上级接口ServletContextInitializer,返回的就是我们自定的三个ServletRegistrationBean/FilterRegistrationBean/ServletListenerRegistrationBean,详见ServletContextInitializer继承图
//至于这几个是什么时候注册好的,请看下回分解
private <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type,
Set<?> excludes) {
String[] names = beanFactory.getBeanNamesForType(type, true, false);
Map<String, T> map = new LinkedHashMap<>();
for (String name : names) {
if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
T bean = beanFactory.getBean(name, type);
if (!excludes.contains(bean)) {
map.put(name, bean);
}
}
}
List<Entry<String, T>> beans = new ArrayList<>(map.entrySet());
beans.sort((o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), o2.getValue()));
return beans;
}
//2添加适配Bean
protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {//6种监听器,见下图
addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,
new ServletListenerRegistrationBeanAdapter());
}
}
}
大致就在这里了,没有细看,缺的没有看这几个Bean是怎么注册到Spring中
接下来走到
public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext {
private void selfInitialize(ServletContext servletContext) throws ServletException {
prepareWebApplicationContext(servletContext);
registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
//这一步走完了,得到了啥 见下图
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
//现在到这里了
beans.onStartup(servletContext);
}
}
}
都是熟悉的面孔
上面这些组件startUp顺序执行,逻辑都差不多
其实是ServletRegistrationBean
public abstract class RegistrationBean implements ServletContextInitializer, Ordered {
@Override
public final void onStartup(ServletContext servletContext) throws ServletException {
String description = getDescription();
if (!isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
return;
}
register(description, servletContext);
}
@Override
protected final void register(String description, ServletContext servletContext) {
D registration = addRegistration(description, servletContext);
if (registration == null) {
logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
return;
}
configure(registration);
}
@Override
protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
String name = getServletName();
return servletContext.addServlet(name, this.servlet);
}
@Override
protected void configure(ServletRegistration.Dynamic registration) {
super.configure(registration);
String[] urlMapping = StringUtils.toStringArray(this.urlMappings);
if (urlMapping.length == 0 && this.alwaysMapUrl) {
urlMapping = DEFAULT_MAPPINGS;
}
if (!ObjectUtils.isEmpty(urlMapping)) {
registration.addMapping(urlMapping);
}
registration.setLoadOnStartup(this.loadOnStartup);
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
}
}
然后就完毕了