`
hitmit1314
  • 浏览: 12126 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

究 Spring 3.1之无web.xml式 基于代码配置的servlet3.0应用

阅读更多
 
        大家应该都已经知道Spring 3.1对无web.xml式基于代码配置的servlet3.0应用。通过spring的api或是网络上高手们的博文,也一定很快就学会并且加到自己的应用中去了。PS:如果还没,也可以小小参考一下鄙人的上一篇文章<<探 Spring 3.1之无web.xml式 基于代码配置的servlet3.0应用>>。

        经过一天的深度research, 我了解,理解以及重现了springframework的那一小段代码。


        OK,第一步,入手点,WebApplicationInitializer接口。因为我们只需实现这个接口覆写它的一个方法,就可以做到配置web.xml同样的功效。看它的源码,其实看和不看没什么两样:

package org.springframework.web;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
public interface WebApplicationInitializer {
	void onStartup(ServletContext servletContext) throws ServletException;
}

   就这么点儿,有效代码5行,弄地我一头雾水,就是一个普通接口,声明了一个方法。连注解都没有,server是怎么找到实现了它的类的?如果这样,何不找我定义的其它接口(的实现类完成配置工作)呢。可见现在java的解耦技术,真令人汗颜。
   第二步,这个接口旁边(同包)有个SpringServletContainerInitializer, 看下它是何方神圣吧:

package org.springframework.web;

import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				// Be defensive: Some servlet containers provide us with invalid classes,
				// no matter what @HandlesTypes says...
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&				WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer) waiClass.newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
					}
				}
			}
		}

		if (initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
			return;
		}

		Collections.sort(initializers, new AnnotationAwareOrderComparator());
		servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);

		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}

}


     以上的有效代码28行。刚看时也很迷茫,其实慢慢就理解了。拟个伪代码吧,方便大家理解:
      1,定义一个类SpringServletContainerInitializer,并标明该类要操作的一个类WebApplicationInitializer
      2, 该类会行使ServletContainerInitializer接口的一个行为onStartup,从而将一个集合中的初始化设置 全部配置到ServletContext的实例中。
      3,具体的onStartup方法中,建立合格配置列表,
      4,如果确定集合中有配置,逐一检查配置是否是合格配置,具体判断依据:这个类不是接口,不是抽象类,而且是所要操作的那个接口的一个实现类。满足此依据,合格。将合格的配置类实例化放入合格配置列表。过程中有错要通知控制台。
     5,如若执行完步骤4,发现没有合格配置,在ServletContext记录该结果,并结束onStartup行为。
     6,将找到配置按一定排列方式(AnnotationAwareOrder)排序。
     7,在ServletContext中记录找到结果。
     8,逐一执行配置。 即驱动每一个WebApplicationInitializer的实现类行使其onStartup行为。

     第三步很明显了,去research 接口ServletContainerInitializer和注解HandleType。在这里:
http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html

    该接口允许一个库或运行时,(运行时应该指server)声明为一个web程序的启动状态,并执行任何所需的程序中注册的servlet,filter,listener来响应它......
     其它也就不用看了,可以想象得到支持Servlet3机制的服务器,会找到这样接口的实现类,执行onStartup行为。至于如何找,无非也是这样一系列的反射机制的应用。自己做一个试试吧:
     自定义的WebApplicationInitializer:


package com.gxino.imagecapture.cfg;

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

public interface WebParameter {
	public void loadInfo(ServletContext servletContext) throws ServletException;
}


     自定义的ServletContainerInitializer,我做得很简单,直接去执行找到配置类中的loadInfo方法

package com.gxino.imagecapture.cfg;

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

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

@HandlesTypes(WebParameter.class)
public class WebConfiguration implements ServletContainerInitializer {

	@Override
	public void onStartup(Set<Class<?>> webParams, ServletContext servletCtx)
			throws ServletException {
		if (webParams != null) {
			for (Class<?> paramClass : webParams) {
				if (!paramClass.isInterface() && !Modifier.isAbstract(paramClass.getModifiers()) &&
						WebParameter.class.isAssignableFrom(paramClass)) {
					try {
						((WebParameter) paramClass.newInstance()).loadInfo(servletCtx);
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebParam class", ex);
					}
				}
			}//loop
		}//Web Params
	}//onStartup

}

      写个测试Servlet:

package com.gxino.imagecapture.ctrl;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gxino.imagecapture.cfg.WebParameter;

public class TestServlet extends HttpServlet {
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp){
		System.out.println("Some client access once");
		try {
			req.getRequestDispatcher("/index.jsp").forward(req, resp);
		} catch (ServletException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}


       实现WebParam配置接口来配置刚才的Servlet:

package com.gxino.imagecapture.cfg;

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


public class ServletParameter implements WebParameter {

	@Override
	public void loadInfo(ServletContext servletContext) throws ServletException {
		ServletRegistration.Dynamic testServlet=servletContext.addServlet("test","com.gxino.imagecapture.ctrl.TestServlet");
		testServlet.setLoadOnStartup(1);
		testServlet.addMapping("/index.html");
	}

}

     启动服务器,访问http://localhost:xxxx/xxxxx/index.html
 
     失败。Debug. 发现没有走这些代码。应该还差关键环节。看来还得知道Servlet3中是怎么找ServletContainerInitializer的。再回刚才ServletContainerInitializer的api有这样一句:该接口的实现必须声明一个JAR资源放到程序中的META-INF/services下,并且记有该接口那个实现类的全路径,才会被运行时(server)的查找机制或是其它特定机制找到。那篇api需要仔细阅读啊。
     到org.springframework.web-3.0.1.RELEASE.jar中能找到META-INF/services下的javax.servlet.ServletContainerInitializer文件,内容为org.springframework.web.SpringServletContainerInitializer同样,我们专门作这样一个包,在mkdir好的META-INF/services下vi 一个文件命名为javax.servlet.ServletContainerInitializer,内容为自定的那个WebConfiguration的全路径类名。 然后在META-INF的parent路径下运行jar cvf test.jar META-INF。一切完毕,将其放到WEB-INF/lib下。启动。

    
     这回大功告成。
    
     访问http://localhost:xxxx/xxxxx/index.html。页面跳到了index.jsp下。
     并且控制台打出: Some client access once

     再使个劲,将Servlet和Servlet配置合二为一:

package com.gxino.imagecapture.ctrl;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gxino.imagecapture.cfg.WebParameter;

public class TestServlet extends HttpServlet implements WebParameter{

	@Override
	public void loadInfo(ServletContext servletContext) throws ServletException {
		ServletRegistration.Dynamic testServlet=servletContext.addServlet("test", "com.gxino.imagecapture.ctrl.TestServlet");
		testServlet.setLoadOnStartup(1);
		testServlet.addMapping("/index.html");
	}
	public void doGet(HttpServletRequest req, HttpServletResponse resp){
		System.out.println("Some client access once");
		try {
			req.getRequestDispatcher("/index.jsp").forward(req, resp);
		} catch (ServletException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}


这回我们看到,配置文件与servlet放到了一起。这样将回节省大量时间。

    以后直接运用Spring Framework的WebApplicationInitializer也知道是怎么一回事儿了。而且可以将Spring 的applicationContext.xml与web.xml融合在一个类中。即注解为@Configuration,并实现WebApplicationInitializer.回头试试。
2
1
分享到:
评论
5 楼 hitmit1314 2012-12-02  
xknew_boy 写道
请问你有无尝试过无xml的事务配置,我配置后,事务运行不正常

有啊,运行很正常,不仅可以正常,还可用Junit进行测试,等下我更新新的博文给你看
4 楼 hitmit1314 2012-03-22  
xknew_boy 写道
请问你有无尝试过无xml的事务配置,我配置后,事务运行不正常

你是说spring的@Transactional?
3 楼 xknew_boy 2012-03-01  
请问你有无尝试过无xml的事务配置,我配置后,事务运行不正常
2 楼 hitmit1314 2011-12-31  
OK.TestServlet 可以只被实例化一次。servletContext.addServlet  这个方法有多个重载方法。传递两个参数,一个是servlet的name.就是我们通常配置的<servlet-name>. 还有一个是servlet信息,serveltContext通过这个信息找到正确的servlet。这个信息可以是多种多样。上面的例子中是一种,传入servlet类的全类路径名。还有传入那个类,所以上面的还可以是 addServlet("test", TestServlet.class);这两个都是系统通过这个信息去实例化。而还有一个就是直接传入实例。从而改成addServlet("test", this);
1 楼 hitmit1314 2011-12-20  
今天想了个问题,最后这段代码在行使它不同功效的方法时,会被各自实例化一次。有米有方法可以只实例化一次呢?Spring不是可以注入嘛~,不过很难做到。

相关推荐

    spring-boot-reference.pdf

    27.1. The “Spring Web MVC Framework” 27.1.1. Spring MVC Auto-configuration 27.1.2. HttpMessageConverters 27.1.3. Custom JSON Serializers and Deserializers 27.1.4. MessageCodesResolver 27.1.5. Static...

    SpringSecurity 3.0.1.RELEASE.CHM

    2.2.1. 配置web.xml 2.2.2. 最小 配置 2.2.2.1. auto-config包含了什么? 2.2.2.2. 表单和基本登录选项 2.2.3. 使用其他认证提供器 2.2.3.1. 添加一个密码编码器 2.3. 高级web特性 2.3.1. Remember-Me认证 ...

    springboot参考指南

    创建一个非web(non-web)应用 ii. 63. 属性&配置 i. 63.1. 外部化SpringApplication配置 ii. 63.2. 改变应用程序外部配置文件的位置 iii. 63.3. 使用'short'命令行参数 iv. 63.4. 使用YAML配置外部属性 v. 63.5. ...

    Spring中文帮助文档

    2.2.2. 更简单的XML配置 2.2.3. 可扩展的XML编写 2.2.4. Annotation(注解)驱动配置 2.2.5. 在classpath中自动搜索组件 2.3. 面向切面编程(AOP) 2.3.1. 更加简单的AOP XML配置 2.3.2. 对@AspectJ 切面的支持 ...

    Spring Security 中文教程.pdf

    2.2.1. 配置web.xml 2.2.2. 最小 &lt;http&gt; 配置 2.2.2.1. auto-config 包含了什么? 2.2.2.2. 表单和基本登录选项 2.2.3. 使用其他认证提供器 2.2.3.1. 添加一个密码编码器 2.3. 高级web特性 2.3.1. ...

    Spring API

    2.2.2. 更简单的XML配置 2.2.3. 可扩展的XML编写 2.2.4. Annotation(注解)驱动配置 2.2.5. 在classpath中自动搜索组件 2.3. 面向切面编程(AOP) 2.3.1. 更加简单的AOP XML配置 2.3.2. 对@AspectJ 切面的支持 ...

    DWR.xml配置文件说明书(含源码)

    DWR.xml配置文件说明书 1、 建立dwr.xml 配置文件 任何一个dwr.xml的文件都需要包含DWR DOCTYPE的声明行,格式如下: &lt;!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" ...

    Spring Security-3.0.1中文官方文档(翻译版)

    2.2.1. 配置web.xml 2.2.2. 最小&lt;http&gt; 配置 2.2.2.1. auto-config 包含了什么? 2.2.2.2. 表单和基本登录选项 2.2.3. 使用其他认证提供器 2.2.3.1. 添加一个密码编码器 2.3. 高级web 特性 2.3.1. ...

    spring和hibernate__jar包,详细说明看jar包列表

    org.springframework.web.servlet-3.1.1.RELEASE.jar org.springframework.web.struts-3.1.1.RELEASE.jar slf4j-api-1.5.8.jar slf4j-log4j12-1.5.8.jar spring-aop-3.1.1.RELEASE.jar spring-asm-3.1.1.RELEASE.jar...

    spring-framework-reference-4.1.2

    3.1. Improved Getting Started Experience .................................................................. 17 3.2. Removed Deprecated Packages and Methods ...............................................

    Spring 3.x 中文开发手册.pdf

    10、支持Servlet3的某个东东,可以写程序直接启动webapp,而非web.xml,不感兴趣 11、支持servlet3的上传东东,可能是对现有MultipartResolver的加强 12、JPA什么,直接无视 以下都是springmvc的加强,可以注意了 ...

    spring-mvc3-javaconfig:配置为不使用XML的Java Spring MVC 3应用程序。 还使用Servlet 3 API绕过web.xml

    Spring @MVC 3.1 Java配置这是一个使用Spring的Java配置而不是XML的简单示例。 我的解释了此示例。 这是一个伪造的登录应用程序。 在现实生活中,您可能会改用Spring Security。 有一个服务和数据访问层,但是存储库...

    spring-framework-reference4.1.4

    3.1. Improved Getting Started Experience .................................................................. 17 3.2. Removed Deprecated Packages and Methods ...............................................

    Spring.3.x企业应用开发实战(完整版).part2

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    10.3.4 建立Spring的配置文档dispatcherServlet-servlet.xml 10.3.5 配置web.xml 10.3.6 启动Tomcat运行程序 10.4 Spring 的视图(View) 10.4.1 视图简介 10.4.2 视图解析 10.5 Spring的控制器(Controller) ...

    struts2.4+spring3.1+hibernate4.1的SSH框架

    SSH 为 struts2.4+spring3.1+hibernate4.1的一个集成框架,是目前较流行的一种Web应用程序开源框架。  集成SSH框架的系统从职责上分为四层:表示层、业务逻辑层、数据持久层和域模块层,以帮助开发人员在短期内搭建...

    271个java需要用的jar包

    servlet.jar shiro-cas-1.2.2.jar shiro-core-1.2.2.jar shiro-spring-1.2.2.jar shiro-web-1.2.2.jar sitemesh-2.4.2.jar slf4j-api-1.3.1.jar slf4j-api-1.6.0.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.7.jar ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    10.3.4 建立Spring的配置文档dispatcherServlet-servlet.xml 10.3.5 配置web.xml 10.3.6 启动Tomcat运行程序 10.4 Spring 的视图(View) 10.4.1 视图简介 10.4.2 视图解析 10.5 Spring的控制器(Controller) ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    10.3.4 建立Spring的配置文档dispatcherServlet-servlet.xml 10.3.5 配置web.xml 10.3.6 启动Tomcat运行程序 10.4 Spring 的视图(View) 10.4.1 视图简介 10.4.2 视图解析 10.5 Spring的控制器(Controller) ...

    cxf(jax-ws)+spring+hibernate整合包

    FastInfoset-1.2.12.jar,geronimo-javamail_1.4_spec-1.7.1.jar,geronimo-jaxws_2.2_spec-1.1.jar,geronimo-jms_1.1_spec-1.1.1.jar,geronimo-servlet_3.0_spec-1.0.jar,hibernate-annotations.jar,hibernate-...

Global site tag (gtag.js) - Google Analytics