我承认,是我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 findSpittles(long max, int count) {
return new ArrayList(){
{
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 spitterList=new HashMap();
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
和根据正则来判断的,排除spittr.web包下的类,至于为啥排除。。。等会说
,而WebConfig是实现了Spring的WebMvcConfigurerAdapter类的专门服务SpringMvc的一个配置文件
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
//作用相当于
@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 spitterList=new HashMap();
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的情况下提前初始化了,启动成功。
不过好像还有个懒惰加载的选项。。。。总感觉那个才是首选。。