Spring源码阅读引导篇
write by donaldhan, 2017-12-14 16:33引言
上一篇文章导入spring源码到eclipse,我们从github上拉取spring框架源码,并导入的eclipse,从今天开始,我们将会从spring bean容器,事务,mvc三个方面,去窥探这3个方面的内部机制。 在spring框架源码分析这类文章中,所讲到的spring3,表示spring-3.2.18, 所讲到的spring4,表示spring-4.3.13。所设计到的源码参见spring3-demo和。 这篇文章我们作为spring源码阅读部分的引导篇,源码我们使用 spring-4.3.13 版本。
目录
下面我们简单看一下,这3个方面。
spring bean 容器
在我们将spring bean容器的时候,往往回想到应用上下文 ApplicationContext ,因为通过应用上下文,我们获取bean容器中的bean实例。 spring3的时候,我们会用于xml配置的bean声明,并通过 ClassPathXmlApplicationContext 去加载bean上下文配置文件 ApplicationContext.xml,实例如下:
package cn.home.bootstrap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.home.modules.beans.entity.ExampleBean;
import cn.home.util.JacksonUtil;
/**
* @author donald
* 2017年11月26日
* 下午12:45:55
*/
public class ClassPathXmlApplicationContextBoot {
private static final Logger log = LoggerFactory.getLogger(ClassPathXmlApplicationContextBoot.class);
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"ApplicationContext.xml"});
ExampleBean exampleBean = context.getBean(ExampleBean.class);
log.info("exampleBean:{}",JacksonUtil.getInstance().toJson(exampleBean));
}
}
下面是 ApplicationContext.xml 一个简单配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- scan component and add applicationContext -->
<context:component-scan base-package="cn.home.modules.transaction" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:jdbc.properties</value>
</property>
</bean>
<!-- 阿里 druid数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<!-- 数据库基本信息配置 -->
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="filters" value="${filters}" />
</bean>
<!-- transaction support ,PlatformTransactionMnager -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启事务注解时,屏蔽tx:advice,aop:config -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="edit*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="UnsupportedOperationException"/>
<tx:method name="remove*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* cn.home.modules.*.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
<!-- enable transaction annotation support,开始事务注解配置,手动控制那些方法或类需要进行事务控制,
当开启事务注解时,需要屏蔽上面的tx:advice和aop:config标签的事务声明 -->
<!-- <tx:annotation-driven transaction-manager="txManager" /> -->
</beans>
从spring4开始全面支持注解配置,其实从spring3.2.18开始,spring注解配置已经出现,只不过,在当时的开发环境下,大家还习惯与基于xml的配置, spring4注解配置加载bean的通过注解扫描 @Bean 具体代码如下:
package cn.home.bootstrap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import cn.home.config.AppConfig;
import cn.home.modules.beans.service.FooService;
import cn.home.util.JacksonUtil;
/**
* @author donald
* 2017年11月22日
* 下午9:40:07
*/
public class AnnotationConfigApplicationContextBoot {
private static final Logger log = LoggerFactory.getLogger(AnnotationConfigApplicationContextBoot.class);
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
FooService fooService = ctx.getBean(FooService.class);
log.info("fooService:{}",JacksonUtil.getInstance().toJson(fooService));
fooService.doStuff(1);
}
}
注意这个里面使用的上下文配置类是 AnnotationConfigApplicationContext,同时传入的还有一个配置类参数 AppConfig.class , 这个与 ApplicationContext.xml 的作用相同。下面是 AppConfig.class 的一个简单示例:
package cn.home.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import com.alibaba.druid.pool.DruidDataSource;
import cn.home.modules.beans.entity.DbInfo;
import cn.home.modules.beans.service.MyService;
import cn.home.modules.beans.service.impl.MyServiceImpl;
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "cn.home.modules")
@PropertySource("classpath:jdbc.properties")
public class AppConfig implements TransactionManagementConfigurer {
private static final Logger log = LoggerFactory.getLogger(Logger.class);
private static final String JDBC_URL = "jdbc.url";
private static final String JDBC_USERNAME = "jdbc.username";
private static final String JDBC_PASSWORD = "jdbc.password";
private static final String JDBC_DRIVE_CLASS_NAME = "jdbc.driverClassName";
// 初始化时数据库连接数
private static final int INITIAL_THREAD = 5;
// 空闲时保存数据库连接数
private static final int MINIDLE_THREAD = 2;
// 数据库连接池最大连接数
private static final int MAX_ACTIVE_THREAD = 100;
// 数据库连接等待的最长时间
private static final int MAX_WAIT = 1000;
// 检查连接是否正常的查询
private static final String CHECK_CONNECTION_QUERY = "Select 'X'";
// 连接池状态监控过滤器名
private static final String STAT_FILETER = "mergeStat";
// MyBait sql文件
private static final String MY_BAITS_MAPPER_PATH = "classpath*:mappers/**/**.xml";
@Autowired
Environment env;
/**
* durid数据源
*
* @return
* @throws SQLException
*/
@Bean(destroyMethod = "close")
public DataSource dataSource() throws SQLException {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setInitialSize(INITIAL_THREAD);
dataSource.setMinIdle(MINIDLE_THREAD);
dataSource.setMaxActive(MAX_ACTIVE_THREAD);
dataSource.setMaxWait(MAX_WAIT);
dataSource.setTimeBetweenEvictionRunsMillis(60000);
dataSource.setValidationQuery(CHECK_CONNECTION_QUERY);
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
dataSource.setPoolPreparedStatements(false);
dataSource.setFilters(STAT_FILETER);
dataSource.setUrl(env.getProperty(JDBC_URL));
dataSource.setDriverClassName(env.getProperty(JDBC_DRIVE_CLASS_NAME));
dataSource.setUsername(env.getProperty(JDBC_USERNAME));
dataSource.setPassword(env.getProperty(JDBC_PASSWORD));
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
PathMatchingResourcePatternResolver loader = new PathMatchingResourcePatternResolver();
sessionFactory.setMapperLocations(loader.getResources(MY_BAITS_MAPPER_PATH));
return sessionFactory.getObject();
}
@Bean
public SqlSession sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory());
}
@Bean
public PlatformTransactionManager txManager() throws SQLException {
return new DataSourceTransactionManager(dataSource());
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
PlatformTransactionManager transactionManager = null;
try {
transactionManager = txManager();
} catch (SQLException e) {
log.error("transactionManager config exception...",e);
e.printStackTrace();
}
return transactionManager;
}
@Bean
public MyService myService() {
return new MyServiceImpl();
}
@Bean
DbInfo dbInfo() {
DbInfo dbInfo = new DbInfo();
dbInfo.setUrl(env.getProperty(JDBC_URL));
dbInfo.setDriverClassName(env.getProperty(JDBC_USERNAME));
dbInfo.setUsername(env.getProperty(JDBC_PASSWORD));
dbInfo.setPassword(env.getProperty(JDBC_DRIVE_CLASS_NAME));
return dbInfo;
}
}
如果我们想要继承spring的核心容器部分到web,我们可以在 web.xml 中配置,spring3,为:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
spring4具体配置如下:
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also
be specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>cn.home.config.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
spring事务
在使用spring事务,一般我们会使用声明式事务,在spring3中一般是声明事务如下:
<!-- transaction support ,PlatformTransactionMnager -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 开启事务注解时,屏蔽tx:advice,aop:config -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="edit*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="UnsupportedOperationException"/>
<tx:method name="remove*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* cn.home.modules.*.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
<!-- enable transaction annotation support,开始事务注解配置,手动控制那些方法或类需要进行事务控制,
当开启事务注解时,需要屏蔽上面的tx:advice和aop:config标签的事务声明 -->
<!-- <tx:annotation-driven transaction-manager="txManager" /> -->
spring4的事务配置如下:
package cn.home.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import com.alibaba.druid.pool.DruidDataSource;
import cn.home.modules.beans.entity.DbInfo;
import cn.home.modules.beans.service.MyService;
import cn.home.modules.beans.service.impl.MyServiceImpl;
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "cn.home.modules")
@PropertySource("classpath:jdbc.properties")
public class AppConfig implements TransactionManagementConfigurer {
private static final Logger log = LoggerFactory.getLogger(Logger.class);
private static final String JDBC_URL = "jdbc.url";
private static final String JDBC_USERNAME = "jdbc.username";
private static final String JDBC_PASSWORD = "jdbc.password";
private static final String JDBC_DRIVE_CLASS_NAME = "jdbc.driverClassName";
// 初始化时数据库连接数
private static final int INITIAL_THREAD = 5;
// 空闲时保存数据库连接数
private static final int MINIDLE_THREAD = 2;
// 数据库连接池最大连接数
private static final int MAX_ACTIVE_THREAD = 100;
// 数据库连接等待的最长时间
private static final int MAX_WAIT = 1000;
// 检查连接是否正常的查询
private static final String CHECK_CONNECTION_QUERY = "Select 'X'";
// 连接池状态监控过滤器名
private static final String STAT_FILETER = "mergeStat";
// MyBait sql文件
private static final String MY_BAITS_MAPPER_PATH = "classpath*:mappers/**/**.xml";
@Autowired
Environment env;
/**
* durid数据源
*
* @return
* @throws SQLException
*/
@Bean(destroyMethod = "close")
public DataSource dataSource() throws SQLException {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setInitialSize(INITIAL_THREAD);
dataSource.setMinIdle(MINIDLE_THREAD);
dataSource.setMaxActive(MAX_ACTIVE_THREAD);
dataSource.setMaxWait(MAX_WAIT);
dataSource.setTimeBetweenEvictionRunsMillis(60000);
dataSource.setValidationQuery(CHECK_CONNECTION_QUERY);
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
dataSource.setPoolPreparedStatements(false);
dataSource.setFilters(STAT_FILETER);
dataSource.setUrl(env.getProperty(JDBC_URL));
dataSource.setDriverClassName(env.getProperty(JDBC_DRIVE_CLASS_NAME));
dataSource.setUsername(env.getProperty(JDBC_USERNAME));
dataSource.setPassword(env.getProperty(JDBC_PASSWORD));
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
PathMatchingResourcePatternResolver loader = new PathMatchingResourcePatternResolver();
sessionFactory.setMapperLocations(loader.getResources(MY_BAITS_MAPPER_PATH));
return sessionFactory.getObject();
}
@Bean
public SqlSession sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory());
}
@Bean
public PlatformTransactionManager txManager() throws SQLException {
return new DataSourceTransactionManager(dataSource());
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
PlatformTransactionManager transactionManager = null;
try {
transactionManager = txManager();
} catch (SQLException e) {
log.error("transactionManager config exception...",e);
e.printStackTrace();
}
return transactionManager;
}
}
注意开启@EnableTransactionManagement注解配置。
springmvc
开启springmvc 一般我们要会在 web.xml 中进行配置servlet分发器,具体配置如下:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
spring-mvc配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- autowired controller -->
<context:annotation-config />
<!-- scan component and add applicationContext -->
<context:component-scan base-package="cn.home.modules.webmvc.controller" />
<!-- It configures a DefaultServletHttpRequestHandler with a URL mapping
of "/**" and the lowest priority relative to other URL mappings. This handler
will forward all requests to the default Servlet. -->
<mvc:default-servlet-handler />
<!-- model model binding conversion, JSR-303 support will be detected on
classpath and enabled automatically -->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<ref bean="stringHttpMessageConverter" />
<ref bean="mappingJacksonHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 从请求和响应读取/编写字符串。默认情况下,它支持媒体类型 text/* 并使用文本/无格式内容类型编写。 -->
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- 使用 Jackson 的 ObjectMapper 读取/编写 JSON 数据。它转换媒体类型为 application/json 的数据。 -->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
</property>
</bean>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
<mvc:interceptor>
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/admin/**" />
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/secure/*" />
<bean class="cn.home.modules.webmvc.interceptor.SecurityInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
<bean id="exceptionResolver" class="cn.home.modules.webmvc.exception.GlobalHandlerExceptionResolver"></bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- To enable @AspectJ support with XML based configuration use the aop:aspectj-autoproxy
element: -->
<aop:aspectj-autoproxy />
<!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->
</beans>
对于spring4,在 web.xml 中进行配置servlet分发器,具体配置如下:
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>cn.home.config.WebMvcConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
同时开启webmvc注解即可,具体如下:
package cn.home.config;
import java.text.SimpleDateFormat;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import cn.home.modules.webmvc.Interceptor.CostTimeInterceptor;
import cn.home.modules.webmvc.Interceptor.SystemLogInterceptor;
import cn.home.modules.webmvc.exceptionhandler.GlobalHandlerExceptionResolver;
@Configuration
@ComponentScan(basePackages = "cn.home.modules")
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Autowired
private CostTimeInterceptor costTimeInterceptor;
@Autowired
SystemLogInterceptor systemLogInterceptor;
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(systemLogInterceptor).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(costTimeInterceptor).addPathPatterns("/**");
}
/**
* to serve resource requests with a URL pattern of /resources/** from a
* public-resources directory within the web application root
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setCache(true);
resolver.setRequestContextAttribute("request");
resolver.setContentType("text/html;charset=UTF-8");
registry.viewResolver(resolver);
}
@Bean
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(104857600);
return resolver;
}
@Bean
public GlobalHandlerExceptionResolver globalHandlerExceptionResolver(){
return new GlobalHandlerExceptionResolver();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void extendHandlerExceptionResolvers( List list){
list.add(globalHandlerExceptionResolver());
}
}
到这里,我们基本把,spring3和spring4的核心配置已经讲完,主要的不同一个是xml,一个是基于注解的。
总结
我们从spring应用上下文、事务、springmvc3个方法分析了spring3和spring4的区别,主要是配置的形式不同。 spring应用上下文是基于spring核心 bean 容器,spring事务主要通过spring aop 和ThreadLocal来实现; spring mvc 主要通过 DispatcherServlet 来分发Web请求。下面我们将从 ClassPathXmlApplicationContext 开始 阅读spring上下文(核心benn容器)相关的代码。