【SpringMVC】零配置实现原理
1.配置方式的springMVC官方地址初始化主要任务初始化spring容器添加Servlet在使用springMVC时通常我们是配置了web.xml,在里面通过ContextLoadLisener和DispatherServlet来加载我们的配置文件初始化spring容器,这样配置的原因主要是Tomcat会主动加载web.xml;在Servlet3.0以后可以不需要通过配置文件...
·
1.配置方式的springMVC
- 初始化主要任务
- 初始化spring容器
- 添加Servlet
- 在使用springMVC时通常我们是配置了web.xml,在里面通过ContextLoadLisener和DispatherServlet来加载我们的配置文件初始化spring容器,这样配置的原因主要是Tomcat会主动加载web.xml;在Servlet3.0以后可以不需要通过配置文件的方式完成,直接通过实现接口webApplicationInitalizer,tomcat也会主动执行该接口的方法;只要在该方法中向tomcat中添加servlet同样可以实现配置文件的效果
2.无xml SpringMVC实现
- 此处用到了再tomcat启动时调用的一个接口, 以此来实现无配置的方式初始化容器以及添加Servlet
1.WebApplicationInitializer
- 代码实现
- 初始化spring容器
- 添加Servlet
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
2.实现配置类AppConfig
- 这里就相当于在以前的spring-mvc的配置文件中配置的包扫描和视图解析器
@Configuration
@ComponentScan("com.hgy")
public class AppConfig {
@Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("/WEB-INF/");
internalResourceViewResolver.setSuffix(".jsp");
return internalResourceViewResolver;
}
}
3.为什么tomcat会主动执行WebApplicationInitializer
3.1 spring源码
- 根据调试可以发现调用webApplicationInitializer的startUp方法是SpringServletContainerInitializer, 而这个类又实现了ServletContainerInitializer接口至此我们大致明白tomcat真正执行的类是javax.servlet.ServletContainerInitializer; 如果你也去实现该接口你会发现不会执行你的代码
@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);
}
}
}
}
3.2 ServletContainerInitializer需要的配置
- 在resources下面添加META-INF/services文件夹
- 在文件夹中添加配置文件javax.servlet.ServletContainerInitializer
- 在配置文件中添加你的ServletContainerInitializer的实现类权限定类名
- 在实现类上添加上HandlesTypes注解,添加需要处理的类型
4. 实现自己的ServletContainerInitializer
-
添加配置文件
-
代码实现(不加处理类型注解)
public class MyServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("==================");
}
}
- 代码实现(添加注解)
- Test必须是接口
- Test接口需要有实现类
@HandlesTypes(Test.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println(set.isEmpty());
}
}
5.总结
- ServletContainerInitializer这个接口能在tomcat启动的时候动态添加Servlet、Filter等组件;使用需要一定要在meta-inf下添加配置文件
- 该接口的实现类还可以利用HandleTypes来自己扩展需要处理的接口,如Spring中利用SpringServletContainerInitializer实现该接口然后在扩展处理了WebApplicationInitializer,以此屏蔽了底层实现;调式时观察堆栈发现调用源头
- 如果是通用功能可以写在一个jar中,这样就能动态的插拔jar实现功能的动态扩展,对代码毫无侵入性
更多推荐
已为社区贡献1条内容
所有评论(0)