1. 程式人生 > >利用JavaConfig配置Spring及SpringMvc的開發環境

利用JavaConfig配置Spring及SpringMvc的開發環境

記錄自己的學習總結--關於o配置web.xml

1.導Spring相關的包,略。

2.由於要全使用JavaConfig來配置,所以必須是servlet3.0及以上才可以。

3.servlet容器(如tomcat)啟動的時候會去呼叫ServletContainerInitializer介面(見servlet3.0api),而Spring的SpringServletContainerInitializer類就是這個介面的實現;

下面是原始碼:

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

@Override
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;
}
AnnotationAwareOrderComparator.sort(initializers);
servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}

}

從原始碼可以看出;

Spring實現了ServletContainerInitializer的onStartup(Set<Class<?>> c, ServletContext ctx)方法,並引入了自己的另一個介面WebApplicationInitializer (上述程式碼的最後就是呼叫WebApplicationInitializer 的onStartup()方法);

4.下面來看WebApplicationInitializer 介面;

public interface WebApplicationInitializer {

void onStartup(ServletContext servletContext) throws ServletException;
}

介面中只有一個onStartup()方法;

5.WebApplicationInitializer 實現類

public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer

public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer

public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer

5.1我們來看一下上述抽象類對應的原始碼:

public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer {

//實現介面的onStartup()方法
@Override
public void onStartup(ServletContext servletContext) throws ServletException {

//呼叫下面的方法
registerContextLoaderListener(servletContext);
}
//將SpringRoot容器上下文的監聽器註冊到servlet上下文中
protected void registerContextLoaderListener(ServletContext servletContext) {

//呼叫下面的建立SpringRoot容器
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
//建立Spring容器方法
protected abstract WebApplicationContext createRootApplicationContext();

protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() {
return null;
}
}

5.2 

//這個類主要的作用就是將DispatcherServlet註冊到ServletContext 中

public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
registerDispatcherServlet(servletContext);
}

protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return empty or null");

WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext,
"createServletApplicationContext() did not return an application " +
"context for servlet [" + servletName + "]");

FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());

ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
Assert.notNull(registration,
"Failed to register servlet with name '" + servletName + "'." +
"Check if there is another servlet registered under the same name.");

registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());

Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}

//將註冊的dispatcherServlet的動態servlet傳遞出來,方便擴充套件修改
customizeRegistration(registration);
}

protected String getServletName() {
return DEFAULT_SERVLET_NAME;
}
//自己建立mvc容器方法
protected abstract WebApplicationContext createServletApplicationContext();

protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
return new DispatcherServlet(servletAppContext);
}

protected ApplicationContextInitializer<?>[] getServletApplicationContextInitializers() {
return null;
}

protected abstract String[] getServletMappings();

protected Filter[] getServletFilters() {
return null;
}

protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) {
String filterName = Conventions.getVariableName(filter);
Dynamic registration = servletContext.addFilter(filterName, filter);
if (registration == null) {
int counter = -1;
while (counter == -1 || registration == null) {
counter++;
registration = servletContext.addFilter(filterName + "#" + counter, filter);
Assert.isTrue(counter < 100,
"Failed to register filter '" + filter + "'." +
"Could the same Filter instance have been registered already?");
}
}
registration.setAsyncSupported(isAsyncSupported());

registration.addMappingForServletNames(getDispatcherTypes(), false, getServletName());
return registration;
}

private EnumSet<DispatcherType> getDispatcherTypes() {
return (isAsyncSupported() ?
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) :
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE));
}

protected boolean isAsyncSupported() {
return true;
}

protected void customizeRegistration(ServletRegistration.Dynamic registration) {
}


}

5.3

public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer {

//重寫建立Spring容器方法(5.1中的)
@Override
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(configClasses);
return rootAppContext;
}
else {
return null;
}
}

//重寫建立mvc容器方法(5.2中的)
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext();
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
servletAppContext.register(configClasses);
}
return servletAppContext;
}

//得到Spring的配置類
protected abstract Class<?>[] getRootConfigClasses();

//得到Springmvc的配置類
protected abstract Class<?>[] getServletConfigClasses();

}

6.所以我們採用JavaConfig的方式類配置Spring的話有兩種:要麼繼承AbstractAnnotationConfigDispatcherServletInitializer 抽象類,要麼實現WebApplicationInitializer介面

public class CoreWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{

@Override
protected Class<?>[] getRootConfigClasses() {
//引入Spring的配置類
return new Class<?>[]{SpringConfig.class};
}
@Override
protected Filter[] getServletFilters() {
//定義字元過濾器
return new Filter[]{new CharacterEncodingFilter("utf-8", true)};
}
@Override
protected void customizeRegistration(Dynamic registration) {
// 擴充套件修改預設實現的DispatcherServlet
super.customizeRegistration(registration);
}
@Override
protected Class<?>[] getServletConfigClasses() {
//引入Springmvc的配置類
return new Class<?>[] {SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
// 預設DispatcherServlet的對映,攔截所有請求
return new String[]{"/"};
}

}

/**
 * Spring容器配置
 * @author admin
 */
@Configuration
@ComponentScan(basePackages={"com.tete.dao","com.tete.service","com.tete.config"})
@EnableAsync
public class SpringConfig {

}

/**
 * springMvc容器的配置
 * @author admin
 */
@Configuration
@ComponentScan(basePackages="com.tete.controller")
@EnableWebMvc
public class SpringMvcConfig {

//配置檢視解析器
@Bean
public InternalResourceViewResolver jspViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/");
resolver.setSuffix(".jsp");
return resolver;
}
}

通過繼承AbstractAnnotationConfigDispatcherServletInitializer類實現就完成了。

關於實現WebApplicationInitializer介面,就是實現他的onStartup()方法

......