時代在不斷進步,大量基於xml的配置所帶來的弊端也顯而易見,在XML配置和直接注解式配置之外還有一種有趣的選擇方式-JavaConfig,它是在Spring 3.0開始從一個獨立的項目並入到Spring中的。它結合了XML的解耦和JAVA編譯時檢查的優點。JavaConfig可以看成一個XML文件,只不過是使用Java編寫的。現在下面為大家展示如何編寫基於java Config 配置 spring+springmvc+hibernate。
項目是在intellj IDE 下創建的maven項目,目錄如下
按照傳統的方式,像DispatchServlet這樣的Servlet會配置在web.xml文件中,但是借助Servlet3規范和Spring3.1增強,我們可以使用java將DispatchServlet配置在Servlet容器中,下面展示初始化類文件
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { //指定配置類 @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } //將DispatchServlet映射到“/” @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected void customizeRegistration(ServletRegistration.Dynamic registration) { new MultipartConfigElement("/temp",2097152,4194304,0); } }
創建WebInitializer需要繼承AbstractAnnotationConfigDispatcherServletInitializer,因為繼承該類的任意類都會自動地配置DispatchServlet和Spring應用上下文,Spring的應用上下文會位於應用程序的Servlet上下文之中。
我們可以看到底層的AbstractAnnotationConfigDispatcherServletInitializer拓展和實現了WebApplicationInitializer,在Servlet3 環境中,容器會在類路徑中查找實現了javax.servlet.ServletContainerInitializer接口的類,並將該類來配置Servlet容器,而spring提供了這個接口的實現,名為SpringServletContainerInitializer,這個類反過來又會查找實現了WebApplicationInitializer的類並將配置的任務交給他們來完成,所以當我們WebInitializer拓展了AbstractAnnotationConfigDispatcherServletInitializer ,同時就實現了WebApplicationInitializer,因此當部署到Servlet3.0容器中的時候,容器就會自動發現他,並用它來配置Servlet上下文。
WebInitializer中要求DispatchServlet加載應用上下文時,使用定義在WebConfig配置類中的bean。
在使用xml配置spring的時候,必須配置spring監聽器,也是就ContextLoaderListener,然而很多人不知道的是,ContextLoaderListener會創建spring web 應用中的另一個上下文。
我們希望DispatchServlet加載包含Web組件的bean,如控制器、視圖解析器以及處理器映射,而ContextLoaderListener要加載應用中的其他bean,這些bean通常是驅動應用後端的中間層和數據層組件。
也就是說WebConfig的類中會用來定義DispatcherServlet應用上下文的bean,RootConfig的類中會用來配置ContextLoadListener創建的上下文的bean
@Configuration @EnableWebMvc //注解驅動springMVC 相當於xml中的<mvc:annotation-driven> @ComponentScan("scau.zzf.web")//啟用組件掃描 public class WebConfig extends WebMvcConfigurerAdapter { @Bean public ViewResolver viewResolver(){ InternalResourceViewResolver resolver= new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } //配置靜態資源的處理,要求DispatchServlet對靜態資源的請求轉發到servlet容器中默認的Servlet上 @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
@Configuration @Import(HibernateConfig.class)//導入Hibernate配置文件 @ComponentScan(basePackages={"scau.zzf"}, excludeFilters={ @ComponentScan.Filter(type= FilterType.CUSTOM, value=RootConfig.WebPackage.class) } ) public class RootConfig { //掃描除了web以外的所有包 public static class WebPackage extends RegexPatternTypeFilter { public WebPackage() { super(Pattern.compile("scau.zzf\\.web")); } } }
HbernateConfig 如下
@Configuration @PropertySource( value={"classpath:ds/ds-jdbc.properties"}, ignoreResourceNotFound = true)//加載在resources下的ds-jdbc.properties public class HibernateConfig { @Value("${jdbc.driverClassName}") private String driverClassName; @Value("${jdbc.url}") private String jdbcURL; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; //配置sessionFactory @Bean public SessionFactory sessionFactoryBean() { try { LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean(); lsfb.setDataSource(dataSource()); //掃描實體類 lsfb.setPackagesToScan("scau.zzf.entity"); Properties props = new Properties(); //設置方言 ,采用的是MySql props.setProperty("dialect", "org.hibernate.dialect.MySQLDialect"); lsfb.setHibernateProperties(props); lsfb.afterPropertiesSet(); SessionFactory object = lsfb.getObject(); return object; } catch (IOException e) { return null; } } //配置DataSource @Bean public DataSource dataSource(){ BasicDataSource ds=new BasicDataSource(); ds.setDriverClassName(driverClassName); ds.setUrl(jdbcURL); ds.setUsername(username); ds.setPassword(password); return ds; }
@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
實體類如下
@Entity @Table(catalog = "hibernate",name = "users") public class User { @Column private String username; @Column private String password; @Column private String sex; @Column private String address; @Column private int enabled; //GeneratedValue覆蓋@id的默認訪問策略 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // @GenericGenerator是在hibernate中定義的,使用hibernate內置的各種主鍵生成粗略生成主鍵值 // @GenericGenerator(name = "hibernate-uuid",strategy = "uuid") // @GeneratedValue(generator = "hibernate-uuid") private int id; public int getEnabled() { return enabled; } public void setEnabled(int enabled) { this.enabled = enabled; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
在Test的環境下進行測試
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {WebConfig.class, RootConfig.class}) @WebAppConfiguration public class ServiceTest { @Autowired private UserService userService; @Test public void userServiceTest(){ User user=userService.findUser(1); System.out.println(user.getUsername()); } }
在test的環境下,類上的三個注解是一定要配置的,不然會出錯。