Servlet3.0之动态注册web3大组件

在上一篇中我们可以使用注解注册自己编写的组件,但是对于第三方的组件,没有了web.xml,我们不能直接到人家类上去贴个注解,这时候该怎么呢。就得使用servlet3.0的 Sharedlibraries(共享库) / runtimes pluggability(运行时插件能力)。比如下面这个我们原本配置在web.xml中的组件,是没办法用注解替代的。

<!-- 编码过滤器开始 -->
	<filter>
		<filter-name>EncodeingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>EncodeingFilter</filter-name>
		<servlet-name>springmvc</servlet-name>
	</filter-mapping>
	<!-- 编码过滤器结束 -->


	<!-- 监听器开始 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	<!-- 监听器结束 -->

1.ServletContainerInitializer接口

看名字翻译就是servlet容器初始化器,这是属于servlet3.0的内容。

servlet3.0的 Sharedlibraries(共享库) / runtimes pluggability(运行时插件能力)
 	1.Servlet容器启动时(这里是tomcat)会扫描当前应用里面的每一个jar包的ServletContainerInitializer实现类
  	2.ServletContainerInitializer的实现类放的位置有要求:
  		必须绑定在,META-INF/services/javax.servlet.ServletContainerInitializer
		文件的内容就是ServletContainerInitializer实现类的全类名;
		
		
	使用举例:我这里直接在src目录下创建META-INF/services/javax.servlet.ServletContainerInitializ文件
			里面写我编写的ServletContainerInitializer实现类的全类名即可	(这个可以理解为web.xml文件的配置类)	

首先要创建一个类继承ServletContainerInitializer接口,然后将类的全类名配置在META-INF/services/javax.servlet.ServletContainerInitializer文件中(这个文件自己新建)。文件的内容就是ServletContainerInitializer实现类的全类名;
当应用启动时,会运行ServletContainerInitializer实现类里面的onStartup方法,我们可以在这个方法里面利用ServletContext参数对象创建web3大组件(包括自己写到的组件和第三方的组件)

2.编写ServletContainerInitializer实现类

package cn.hzu.web;

import java.util.EnumSet;
import java.util.Set;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.HandlesTypes;

import cn.hzu.filter.UserFilter;
import cn.hzu.listener.UserListener;
import cn.hzu.service.Hello;
import cn.hzu.servlet.HelloServlet;
@HandlesTypes(value= {Hello.class})
public class MyServletContainerInitializer implements ServletContainerInitializer{
	/*
	 * 	应用启动的时候,会运行onStartup方法;
	 *	参数说明:
	 *		 Set<Class<?>> arg0 	:可以拿到你要放入的类的所有实现类和继承接口类(注意不会拿到本身),通过@HandlesTypes注解设置你要传入的类
	 *		 ServletContext arg1	:应用上下文对象,可以用这个对象来创建监听器,过滤器,servlet
	 *		
	 *		重要说明:ServletContext注册web组件只能在应用启动的时候创建
	 *		必须在项目启动的时候来添加;(一般有两个地方)
	 * 		1)、ServletContainerInitializer得到的ServletContext;
	 * 		2)、ServletContextListener得到的ServletContext;
	 * 
	 * 		这种方式我们一般用来创建第三方的组件,如果是自己写的,直接贴注解就好了,不用这么麻烦
	 *		1)、使用ServletContext注册Web组件(Servlet、Filter、Listener)
	 * 		2)、使用编码的方式,在项目启动的时候给ServletContext里面添加组件;
	 * 
	 */
	
	
	@Override
	public void onStartup(Set<Class<?>> arg0, ServletContext arg1) throws ServletException {
		
		//打印@HandlesTypes(value= {Hello.class}) 注解传过来的类的子类型
		
		for (Class<?> claz : arg0) {
			System.out.println(claz);
			System.out.println(arg0.size());
		}
				
		//注册组件  ServletRegistration 
		//addServlet方法参数:servlet名称,servlet对象,返回Dynamic对象,用于配置servlet的映射信息
		ServletRegistration.Dynamic servlet = arg1.addServlet("helloServlet", new HelloServlet());
		//配置servlet的映射信息
		servlet.addMapping("/hello");
		
		
		//注册Listener
		arg1.addListener(UserListener.class);
		
		//注册Filter  FilterRegistration
		FilterRegistration.Dynamic filter = arg1.addFilter("userFilter", (Class<? extends Filter>) UserFilter.class);		
		//配置Filter的映射信息
		//参数:拦截的类型,第二个直接写true,第三个是拦截的路径
		filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
	}
	
	
}

注解@HandlesTypes(value= {Hello.class})这个注解传过去一个class对象,在onStartup的方法中有一个Set<Class<?>> arg0参数可以拿到你传入的对象的所有实现类和继承类(但是不会拿到你传入的对象本身)这里演示注册自己编写的组件,注册第三方的组件原理一样,也是new对象出来,一看就懂,等servlet3.0与ssm整合的时候在演示注册第三方组件。下面看一下在ServletContainerInitializer实现类中注册和使用到的类

3.类的说明

这里我使用@HandlesTypes(value= {Hello.class})注解传过去了Hello这个接口
Hello

public interface Hello {

}

Hello1

public interface Hello1 extends Hello {

}

HelloImpl

public class HelloImpl implements Hello{

}

监听器

public class UserListener implements ServletContextListener {

	
	//监听ServletContext销毁
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		// TODO Auto-generated method stub
		System.out.println("userListener...contextDestroyed...");
	}

	//监听ServletContext启动初始化
	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		//从ServletContextEvent中获取ServletContext对象
		ServletContext servletContext = arg0.getServletContext();
		System.out.println("UserListener...contextInitialized...");
	}

}

过滤器

public class UserFilter implements Filter {

	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		System.out.println("过滤器放行...................................................");
		chain.doFilter(request, response);
		
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("过滤器初始化............................................");
		
	}

	
}

servlet

public class HelloServlet extends HttpServlet{
	
	private static final long serialVersionUID = 1L;
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)  {
		System.out.println("hhh");
		try {
			resp.getWriter().write("hello...");
		} catch (java.io.IOException e) {
			e.printStackTrace();
		}
		
	}
}	

项目结构
在这里插入图片描述

4.运行项目测试

通过下图可以看出,在没有web.xml的情况下,我们配置了ServletContainerInitializer实现类,在项目启动的时候最先执行了ServletContainerInitializer实现类的onStartup方法,跟我们前面说的一样,在onStartup方法中可以拿到我用@HandlesTypes(value= {Hello.class})注解传过去了Hello接口的子类和实现类,但是拿不到它自己本身,只打印了2个对象。然后配置的监听器也生效了,过滤器也生效了,访问路径可以看出servlet也起作用了。这就是在没有web.xml的情况下不使用注解动态注册web组件。
在这里插入图片描述在这里插入图片描述
总结:动态注册web组件用的是ServletContext对象(但只有在容器启动的时候注册才有用)使用下面三个方法注册(其实在springMVC中没有xml的情况下也是这样,原理一样,下次servlet3.0集成ssm框架的时候测试)。在项目启动的时候注册一般就两个地方可以注册
1)、使用ServletContext注册Web组件(Servlet、Filter、Listener)就是我们刚才的onStartup方法中刚注册
2)、编写监听器,里面也有ServletContext对象,也可以用这个注册
动态注册组件的方法
ServletContext.addFilter
ServletContext.addListener
ServletContext.addServlet

动态注册这种方式我们一般用来创建第三方的组件,如果是自己写的,直接贴注解就好了,不用这么麻烦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值