SpringBoot 借助 Servlet 3.1 新特性实现零配置的原理

简介

  • Servlet 3.1 搞了个类似开机自动运行的规则。(但是我貌似 3.0 也跑起来了,不知道是不是我搞错了什么)
  • 1、创建此类,类名随意别作死就行。实现接口 javax.servlet.ServletContainerInitializer
  • 2、将此类全路径名,放到这个文件中:【/项目/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer】
  • 3、Servlet容器跑起来后,自动调用当前类的 onStartup
  • 4、onStartup 的参数 Set<Class<?>> 就是当前项目所有实现了 @HandlesTypes(IJerryAppInitializer.class) 接口的类。
  • 5、通过反射,玩转 JerryAppInitializer ()
    在这里插入图片描述

放置 ServletContainerInitializer 实现类的全路径

servlet通过它来找到我们创建的类(实现了 ServletContainerInitializer 接口 ),并运行 JerryServletContainerInitializer#onStartup()
/demo/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer

com.jerry.demo.JerryServletContainerInitializer

设计想要被调用的类及其接口

接口

目的是让所有实现了该接口的类都被自动调用。
/demo/src/main/java/com/jerry/service/IJerryAppInitializer.java

package com.jerry.service;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;

public interface IJerryAppInitializer {
	// 这个名字自己取得
	void onJerryStartup(ServletContext servletContext) throws ServletException;
}

实现类

实现我们自定的接口,处理具体业务逻辑。比如注册 servlet 进行配置等。以实现编程式配置
/demo/src/main/java/com/jerry/service/impl/JerryAppInitializer.java

package com.jerry.service.impl;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import com.jerry.service.IJerryAppInitializer;

public class JerryAppInitializer implements IJerryAppInitializer{

	@Override
	public void onJerryStartup(ServletContext servletContext) throws ServletException {
		System.out.println("我是 com.jerry.service.impl.JerryApplicationInitializer,我是被 /demo/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer 折腾起来的。");
	}
}

Servlet 将调用此类

Servlet 将调用此类,此类再调用我上面定义的【想要被调用的类
在此类中,我们能获得所有IJerryAppInitializer的实现类的实例(系统通过 onStartup的参数Set<Class<?>> xxx 传给我们)。并通过反射调用其方法。
/demo/src/main/java/com/jerry/demo/JerryServletContainerInitializer.java

package com.jerry.demo;

import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

import com.jerry.service.IJerryAppInitializer;

/**
 * Servlet 3.1 搞了个类似开机自动运行的规则。
 * 1、创建此类,类名随意别作死就行。实现接口 javax.servlet.ServletContainerInitializer
 * 2、将此类全路径名,放到这个文件中:【/项目/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer】
 * 3、Servlet容器跑起来后,自动调用当前类的 onStartup
 * 4、onStartup 的参数 Set<Class<?>> 就是当前项目所有实现了  @HandlesTypes(IJerryAppInitializer.class) 接口的类。
 * 5、通过反射,玩转 JerryAppInitializer ()
 * @author jerryjin
 */
@HandlesTypes(IJerryAppInitializer.class)
public class JerryServletContainerInitializer implements ServletContainerInitializer {

	@Override
	public void onStartup(Set<Class<?>> jerryAppInitializerClasses, ServletContext servletContext) throws ServletException {
		System.out.println("servlet3.1 规定的  javax.servlet.ServletContainerInitializer 跑起来了");
	
		List<IJerryAppInitializer> initializers = new LinkedList<>();

		if (jerryAppInitializerClasses != null) {
			for (Class<?> clazz : jerryAppInitializerClasses) {
				if (!clazz.isInterface() 
						&& !Modifier.isAbstract(clazz.getModifiers()) 
						&& IJerryAppInitializer.class.isAssignableFrom(clazz))
				{
					try {
						initializers.add((IJerryAppInitializer)clazz.newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("实例化 JerryAppInitializer 失败!", ex);
					}
				}
			}
		}

		if (initializers.isEmpty()) {
			servletContext.log("木有找到 com.jerry.service.IJerryAppInitializer");
			return;
		}

		servletContext.log(initializers.size() + "个 IJerryAppInitializer 实现类在 classpath 出没");
		
		for (IJerryAppInitializer initializer : initializers) {
			// 
			initializer.onJerryStartup(servletContext);
		}
	
	}

}

启动 Tomcat 看效果

。。。
servlet3.1 规定的  javax.servlet.ServletContainerInitializer 跑起来了
我是 com.jerry.service.impl.JerryApplicationInitializer,我是被 /demo/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer 折腾起来的。

信息: 1个 IJerryAppInitializer 实现类在 classpath 出没
。。。

参考资料

【鲁班学院】2019全网最全面的spring boot源码分析
org.springframework.web.WebApplicationInitializer.java
org.springframework.web.SpringServletContainerInitializer.java

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑虾

多情黯叹痴情癫。情癫苦笑多情难

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值