我承认,是我spring的渣渣功底导致了如今这不可挽回的局面。。。
这本书第五章主要讲述如何用纯java配置来完成springmvc程序的构建。
主要就是讲,实现了spring的AbstractAnnotationConfigDispatcherServletInitializer类的java类来作为总配置文件,
关于为啥实现它了就能基于java配置要讲一下
因为在Servlet3.0环境中,容器会在类路径中查找javax.servlet.ServletContainerInitializer接口的实现类,找到就用实现类来
配置Servlet容器,而spring提供了这个实现,是SpringServletContainerInitializer类,而后者就被赋予了这种能力,它会
反过来找有没有实现它spring自己的WebApplicationInitializer接口的类,找到则将自己的配置容器的任务交给它,
而前面提到的老长一串的类名,AbstractAnnotationConfigDispatcherServletInitializer就是一个基础的实现,所以我们实现它,稍作修改就可以了。
下面:
package spittr.config;
import javax.servlet.Filter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/*
* 实现了抽象注解配置DispatcherServlet初始化器
**/
public class SpittrWebAppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer{
//获取系统级配置
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
//获取服务级配置
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebConfig.class};
}
//获取Servlet接收请求的范围
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
public Filter[] getServletFilters() {
CharacterEncodingFilter cd
=new CharacterEncodingFilter();
cd.setEncoding("UTF-8");
return new Filter[]{cd};
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
}
}
大概这么个东西,而RootConfig是一个普通的基于java配置的spring配置文件,功能上和application.xml差不多
package spittr.config;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import spittr.Spittle;
import spittr.data.SpittleRepository;
@Configuration
@ComponentScan(basePackages={"spittr"},
//扫描时排除这些内容
excludeFilters={
@Filter(type=FilterType.ANNOTATION,value=EnableWebMvc.class)
,@Filter(type=FilterType.REGEX,pattern="spittr.web.*")
})
public class RootConfig {
@Bean
public SpittleRepository spittleRepository(){
return new SpittleRepository() {
@SuppressWarnings("serial")
public List<Spittle> findSpittles(long max, int count) {
return new ArrayList<Spittle>(){
{
add(new Spittle("消息1",new Date()));
add(new Spittle("消息2",new Date(),15.0,65.0));
}
};
}
public Spittle findOne(long spittleId) {
return new Spittle("傻逼",new Date());
}
};
}
/**应该是RootConfig先扫描,因为扫描范围中有spittr.web的范围,所以想装填,但发现没有对应的bean,就报错了*/
/*@Bean
public SpitterRepository spitterRepository(){
return new SpitterRepository() {
private Map<String,Spitter> spitterList=new HashMap<String,Spitter>();
public Spitter save(Spitter unsaved) {
spitterList.put(unsaved.getUsername(),unsaved);
return unsaved;
}
public Spitter findByUsername(String username) {
System.out.println(spitterList);
return spitterList.get(username);
}
};
}*/
}
@Configuration 表明这是个java配置类
@ComponentScan是注解扫描,basepackages表明这个包以及它的后代都会被扫描
excludeFilters里的是排除过滤器,即扫描时排除类上有EnableWebMvc注解的bean
,而WebConfig是实现了Spring的WebMvcConfigurerAdapter类的专门服务SpringMvc的一个配置文件和根据正则来判断的,排除spittr.web包下的类,至于为啥排除。。。等会说
package spittr.config; import java.util.HashMap; import java.util.Map; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; import spittr.data.Spitter; import spittr.data.SpitterRepository; //配置基于注解的web配置 @Configuration //作用相当于<mvc:annotation-driven> @EnableWebMvc @ComponentScan("spittr.web") public class WebConfig //继承webmvc配置类适配器 extends WebMvcConfigurerAdapter{ //视图解析Bean 相当于当年的那啥 @Bean public ViewResolver viewResolver(){ System.out.println("视图解析疯狂奔跑!"); //创建视图解析bean,这个bean我们用过,当年xml就是配置的这个 //拼接而成的路徑,因此不要忘记路径分隔符等东西 InternalResourceViewResolver resolver= new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); //设置是否将所有spring上下文中的bean都作为请求属性访问 resolver.setExposeContextBeansAsAttributes(true); return resolver; } //配置静态资源的处理 @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){ configurer.enable(); } @Bean public SpitterRepository spitterRepository(){ System.out.println("spitter"); return new SpitterRepository() { private Map<String,Spitter> spitterList=new HashMap<String,Spitter>(); public Spitter save(Spitter unsaved) { spitterList.put(unsaved.getUsername(),unsaved); return unsaved; } public Spitter findByUsername(String username) { System.out.println(spitterList); return spitterList.get(username); } }; } }
好,问题来了,spittr.web中的一个类要用到实现SpitterRepository接口的对象。
我刚开始是在WebConfig中添加的Bean,启动报错说找不到,提示NoSuchBean
放在RootConfig就好使了,我知道RootConfig先于WebConfig,因为后者只服务SpringMvc,前者服务整个项目。
想起来RootConfig扫描的时候就扫描到spittr.web中的类了,bean初始化就要找自动装填的实现SpitterRepository接口的对象,但
我把他放在WebConfig里了,环境中找不到这个Bean,于是报错。
所以我在RootConfig中的ComponentScan里添加了过滤,不扫描spittr.web,这样spittr.web中的bean就不会在NoSuchBean的情况下提前初始化了,启动成功。
不过好像还有个懒惰加载的选项。。。。总感觉那个才是首选。。