|
前面學(xué)習(xí)ssm項(xiàng)目整合的時(shí)候都是配置一堆的xml文件,今天改成使用一堆的配置類替代xml文件,還是spring+mybatis+spring mvc項(xiàng)目整合,同時(shí)還會(huì)介紹其它額外的如整合shiro、redis的配置、事務(wù)管理與緩存管理的配置、異步線程池配置。 我可能不會(huì)介紹得很詳細(xì),挑先難點(diǎn)說(shuō)幾句就好了,其它的看xml配置就能看懂的就不介紹了。 我在配置的過(guò)程中參考了下面幾篇博客才解決的一些坑。 Spring 4 學(xué)習(xí)筆記7:MVC 配置(JAVA方式):https://blog.csdn.net/w1196726224/article/details/52687324 Spring MVC 無(wú)XML配置入門(mén)示例:https://blog.csdn.net/classicer/article/details/50753019 SpringMvc+Spring+MyBatis 基于注解整合:https://www.cnblogs.com/niechen/p/springmvc.html#_label2 spring4.0 @PropertySource讀取配置文件:https://blog.csdn.net/zz210891470/article/details/68948723 ServletContainerInitializer在 Servlet 3.0 的環(huán)境中,容器會(huì)在 classpath 中尋找繼承了 javax.servlet.ServletContainerInitializer 接口的類,用它來(lái)配置 servlet 容器。 Spring 提供了一個(gè)繼承這個(gè)接口的類 SpringServletContainerInitializer,在這個(gè)類中,它會(huì)尋找任何繼承了 WebApplicationInitializer 接口的類并用其來(lái)配置 servlet 容器。Spring 3.2 提供了一個(gè)繼承了 WebApplicationInitializer 接口的基類 AbstractAnnotationConfigDispatcherServletInitializer。所以,你的 servlet 配置類只需要繼承 AbstractAnnotationConfigDispatcherServletInitializer,就會(huì)被發(fā)現(xiàn)而用于 servlet 容器的配置。
這句話的意思就是說(shuō),只要我們創(chuàng)建一個(gè)類且繼承AbstractAnnotationConfigDispatcherServletInitializer類,那么我們就可以去掉之前在web.xml文件中配置的DispatcherServlet還有初始化spring容器的監(jiān)聽(tīng)器,甚至其它的過(guò)濾器等所有配置都可以在這個(gè)類中完成配置了。 首先,如果你在pom.xml文件中聲明依賴的servlet-api版本是低于3.0的,那么你需要修改servlet-api的依賴配置,改為如下。 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
同時(shí)清除web.xml文件下的所有配置 <web-app xmlns:xsi='http://www./2001/XMLSchema-instance' xmlns='http://java./xml/ns/javaee' xsi:schemaLocation='http://java./xml/ns/javaee http://java./xml/ns/javaee/web-app_2_5.xsd' id='WebApp_ID' version='2.5'>
<welcome-file-list> <welcome-file>index.jsp</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list>
</web-app>
WebConfigServletInitializerWebConfigServletInitializer是我創(chuàng)建的一個(gè)繼承AbstractAnnotationConfigDispatcherServletInitializer的類。 public class WebConfigServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; }
@Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMVCConfig.class}; }
@Override protected String[] getServletMappings() { return new String[]{'/'}; }
@Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext);
FilterRegistration.Dynamic characterEncodingDynamic= servletContext.addFilter('characterEncodingFilter', CharacterEncodingFilter.class); characterEncodingDynamic.addMappingForUrlPatterns(null,true,'/*'); characterEncodingDynamic.setInitParameter('encoding','UTF-8');
FilterRegistration.Dynamic shiroFilterDynamic = servletContext.addFilter('shiroFilter',DelegatingFilterProxy.class); shiroFilterDynamic.addMappingForUrlPatterns(null,true,'/*');
servletContext.addListener(InitRedisService.class); } }
其中g(shù)etRootConfigClasses方法、getServletConfigClasses方法、getServletMappings方法是必須要重寫(xiě)的。getRootConfigClasses是獲取spring的配置類、getServletConfigClasses是獲取配置DispatcherServlet的類(spring-mvc的配置類),getServletMappings是獲取DispatcherServlet要攔截的路徑。 onStartup方法是我重寫(xiě)父類的方法,在該方法中配置字符編碼過(guò)濾器和shiro的代理過(guò)濾器等。這樣就不需要在web.xml文件中做任何配置了。我們也不需要配置這個(gè)類,因?yàn)檫@個(gè)類是在服務(wù)啟動(dòng)的時(shí)候被全局掃描出來(lái)調(diào)用的。 先來(lái)看spring-mvc的配置,這個(gè)配置類就是WebConfigServletInitializer的getServletConfigClasses方法中指定的類。 @Configuration //包掃描 @ComponentScans( value = { @ComponentScan('wjy.weiai7lv.controller'), @ComponentScan('wjy.weiai7lv.exception') } ) @EnableWebMvc//將此注釋添加到@Configuration類將從WebMvcConfigurationSupport導(dǎo)入Spring MVC配置。 public class SpringMVCConfig extends WebMvcConfigurerAdapter {
@Autowired private WebConstantConfig webConstantConfig;
/** * 靜態(tài)資源配置 * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //圖片資源路由,需要在tomcat的server.xml配置中對(duì)應(yīng)的<Host>內(nèi)容添加配置: // <Context docBase='文件路徑' path='/images'/> registry.addResourceHandler('/images/**') //定向到外部文件目錄 .addResourceLocations('file:'+webConstantConfig.getPrivateUploadFileRootPath()+'/'); }
@Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
/** * 添加消息轉(zhuǎn)換器 * @param converters */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); List<MediaType> mediaTypeList = new ArrayList<>(); mediaTypeList.add(MediaType.parseMediaType('text/json;charset=UTF-8')); mediaTypeList.add(MediaType.parseMediaType('application/json;charset=UTF-8')); //支持的媒體類型 messageConverter.setSupportedMediaTypes(mediaTypeList); ObjectMapper objectMapper = new ObjectMapper(); //設(shè)置不輸出值為null的字段 objectMapper.setSerializationInclusion(NON_NULL); messageConverter.setObjectMapper(objectMapper); converters.add(messageConverter); }
/** * 配置視圖解析器 * @param registry */ @Override public void configureViewResolvers(ViewResolverRegistry registry) { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix('/WEB-INF/pages/'); viewResolver.setSuffix('.jsp'); registry.viewResolver(viewResolver); }
/** * * @return */ @Bean public CommonsMultipartResolver multipartResolver(){ CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setDefaultEncoding('utf-8'); multipartResolver.setMaxUploadSize(1024*1024*100); return multipartResolver; }
}
@Configuration注解:可以理解是將一個(gè)類聲明為spring的配置類吧,同時(shí)被@Configuration注解的類也是一個(gè)bean,可以在其它bean中使用@Autowired獲取到。 @ComponentScans和@ComponentScan注解:這兩個(gè)注解都是配置包掃描的,前一個(gè)多了一個(gè)'s',很容易理解就是一個(gè)集合,多個(gè)@ComponentScan組稱@ComponentScans,這樣可以聲明多個(gè)包。 @EnableWebMvc注解:開(kāi)啟mvc。就這么簡(jiǎn)單,再?gòu)?fù)雜的我也不懂了。 @Bean注解:用戶注解在一個(gè)方法上,@Bean注解必須是在被@Configuration注解的類中的方法上使用,被@Bean聲明的方法會(huì)在初始化時(shí)候被調(diào)用,且調(diào)用該方法返回的對(duì)象將作為bean保存在spring容器中。如果@Bean沒(méi)有配置bean名稱,則默認(rèn)使用方法名作為beanName。
SpringMVCConfig類中的addResourceHandlers方法配置靜態(tài)資源訪問(wèn)的,就是當(dāng)訪問(wèn)的url以“/images”開(kāi)頭的都定位到系統(tǒng)文件目錄“/目錄”中去找文件。 configureMessageConverters方法是添加消息轉(zhuǎn)換器的,就是配置使用jackson將數(shù)據(jù)轉(zhuǎn)成json字符串。對(duì)應(yīng)xml文件中的如下配置: <!-- 開(kāi)啟注解驅(qū)動(dòng),使用注解映射器和注解適配器 --> <mvc:annotation-driven> <!-- 指定消息轉(zhuǎn)換器 --> <mvc:message-converters> <ref bean='mappingJackson2HttpMessageConverter'/> </mvc:message-converters> </mvc:annotation-driven>
configureViewResolver方法用于注冊(cè)視圖解析器,而multipartResolver方法是用來(lái)注冊(cè)一個(gè)CommonsMultipartResolver,解決文件上傳的,對(duì)應(yīng)xml配置文件中的如下配置。 <!-- 文件上傳,id不能少,id='multipartResolver' --> <bean id='multipartResolver' class='org.springframework.web.multipart.commons.CommonsMultipartResolver'> <!-- 設(shè)置上傳文件的最大為100MB 100*1024*1024,maxUploadSize屬性的限制不是針對(duì)單個(gè)文件,而是所有文件的容量之和 --> <property name='maxUploadSize' value='104857600' /> <!-- 文件默認(rèn)編碼 --> <property name='defaultEncoding' value='utf-8' /> </bean>
在WebConfigServletInitializer類中的getRootConfigClasses方法返回的類就是spring的配置類。需要自己創(chuàng)建。 @Configuration //配置包掃描,mvc的交給mvc配置 @ComponentScans(value = { @ComponentScan('wjy.weiai7lv.service.impl'), @ComponentScan('wjy.weiai7lv.aspect'), @ComponentScan('wjy.weiai7lv.tasks.impl'), @ComponentScan('wjy.weiai7lv.listener'), @ComponentScan('wjy.weiai7lv.shiro') }) @Import(value = { RedisConfig.class, MyBatisConfig.class, TxAndCacheConfig.class, ShiroConfig.class, AsyncConfig.class, WebConstantConfig.class })//其它@Configuration類 public class SpringConfig{
/** * 要想使用@Value 用${}占位符注入屬性,這個(gè)bean是必須的。 * @return */ @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); }
}
這個(gè)類就是一堆注解,也很容易理解,其中@Configuration前面已經(jīng)說(shuō)過(guò)了,接著@ComponentScans和@ComponentScan注解也說(shuō)過(guò)了,不過(guò)配置有點(diǎn)區(qū)別,前面mvc配置類的@ComponentScans注解配置的是掃描Handler處理器(也叫控制器)的類,即被@Controller注解的類,而這里則是配置掃描普通bean以及數(shù)據(jù)持久化層Dao層的bean和業(yè)務(wù)處理層Server層的bean,當(dāng)然還有其它如切面類的bean。 @Import注解,import這個(gè)詞在導(dǎo)入類的時(shí)候用得特別多,所以很容易理解這個(gè)注解就是用于導(dǎo)入其它被@Configuration注解聲明的類,這樣我們就可以把mybatis的配置、shiro的配置等單獨(dú)寫(xiě)一個(gè)java類完成配置,然后在這里導(dǎo)入就可以。 下面這個(gè)方法照著寫(xiě)進(jìn)去就行了,這是解決使用@Value注解注入properties文件中的屬性獲取不到的問(wèn)題的。 /** * 要想使用@Value 用${}占位符注入屬性,這個(gè)bean是必須的。 * @return */ @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); }
配置mybatis需要完成的工作:配置一個(gè)數(shù)據(jù)源DataSource、連接工程sqlSessionFactory,還有一個(gè)事務(wù)管理者TransactionManager。同時(shí)還需要聲明掃描mapper接口。 @Configuration //導(dǎo)入properties配置文件 @PropertySource('classpath:mybatis/database.properties') //配置mapper接口掃描,掃描Mybatis的Mapper接口 @MapperScan(basePackages = 'wjy.weiai7lv.dao', sqlSessionFactoryRef = 'sqlSessionFactory') //開(kāi)啟事務(wù)管理 //@EnableTransactionManagement public class MyBatisConfig{
@Value('${dataSource.driver}') private String driverClass; @Value('${dataSource.url}') private String jdbcUrl; @Value('${dataSource.username}') private String user; @Value('${dataSource.password}') private String password;
@Value('${c3p0.initialPoolSize}') private Integer initialPoolSize; @Value('${c3p0.maxPoolSize}') private Integer maxPoolSize; @Value('${c3p0.minPoolSize}') private Integer minPoolSize; @Value('${c3p0.maxStatements}') private Integer maxStatements; @Value('${c3p0.acquireIncrement}') private Integer acquireIncrement; @Value('${c3p0.maxIdleTime}') private Integer maxIdleTime; @Value('${c3p0.idleConnectionTestPeriod}') private Integer idleConnectionTestPeriod;
/** * 配置數(shù)據(jù)源 * * @return */ @Bean //不指定bean的名稱默認(rèn)使用方法名為bean的名稱(id),并首字母小寫(xiě) public ComboPooledDataSource dataSource() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setAutoCommitOnClose(false);//關(guān)閉自動(dòng)提交 dataSource.setDriverClass(driverClass); dataSource.setJdbcUrl(jdbcUrl); dataSource.setUser(user); dataSource.setPassword(password); //c3p0的配置 dataSource.setInitialPoolSize(initialPoolSize); dataSource.setMaxPoolSize(maxPoolSize); dataSource.setMinPoolSize(minPoolSize); dataSource.setMaxStatements(maxStatements); dataSource.setAcquireIncrement(acquireIncrement); dataSource.setMaxIdleTime(maxIdleTime); dataSource.setIdleConnectionTestPeriod(idleConnectionTestPeriod); return dataSource; }
/** * 配置SqlSessionFactory * * @param dataSource * @return * @throws Exception */ @Bean public SqlSessionFactory sqlSessionFactory(@Qualifier('dataSource') DataSource dataSource) throws Exception { SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean(); sqlSessionFactory.setDataSource(dataSource); sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources('classpath:mapper/*.xml')); sqlSessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource('classpath:mybatis/mybatis-config.xml')); return sqlSessionFactory.getObject(); }
/** * 配置事務(wù)管理者 * * @param dataSource * @return */ @Bean public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier('dataSource') DataSource dataSource) { DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } }
這些配置我就不多說(shuō)了,跟xml配置的一樣,不過(guò)就是將注入的配置直接調(diào)用set方法賦值罷了。細(xì)心的你會(huì)發(fā)現(xiàn)這個(gè)配置類有一個(gè)@EnableTransactionManagement的注解被我注釋了,其實(shí)這個(gè)@EnableTransactionManagement注解的作用就是開(kāi)啟事務(wù)管理的,如果去掉注釋那么事務(wù)管理的配置也就完成了,@Transactional注解也就可以用了,因?yàn)槲覀冎宦暶髁艘粋€(gè)事務(wù)管理者(dataSourceTransactionManager方法)。但是這里我將事務(wù)管理放到另一個(gè)類中和緩存一起配置。 @Configuration @PropertySource('classpath:redis/redis.properties') //@EnableCaching public class RedisConfig{
@Value('${redis.host}') private String host; @Value('${redis.port}') private Integer port; @Value('${redis.dbIndex}') private Integer dbIndex;
@Value('${redis.maxTotal}') private Integer maxTotal; @Value('${redis.maxIdle}') private Integer maxIdle; @Value('${redis.minIdle}') private Integer minIdle; @Value('${redis.maxWaitMillis}') private Integer maxWaitMillis; @Value('${redis.testOnBorrow}') private Boolean testOnBorrow; @Value('${redis.expiration}') private Long expiration;
/** * 配置JedisPoolConfig實(shí)例,JedisPoolConfig是連接池的配置 * @return */ @Bean public JedisPoolConfig jedisPoolConfig(){ JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(maxTotal); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMinIdle(minIdle); jedisPoolConfig.setTestOnBorrow(testOnBorrow); return jedisPoolConfig; }
/** * 配置JedisConnectionFactory,連接池工廠 * @param jedisPoolConfig JedisPoolConfig實(shí)例,使用@Autowired聲明自動(dòng)注入 * @return */ @Bean public JedisConnectionFactory jedisConnectionFactory(@Autowired JedisPoolConfig jedisPoolConfig){ JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); jedisConnectionFactory.setUsePool(true); jedisConnectionFactory.setPoolConfig(jedisPoolConfig); jedisConnectionFactory.setDatabase(dbIndex); jedisConnectionFactory.setHostName(host); jedisConnectionFactory.setPort(port); return jedisConnectionFactory; }
/** * 配置操作redis的RedisTemplate對(duì)象 * spring-data-redis封裝了RedisTemplate對(duì)象來(lái)進(jìn)行對(duì)Redis的各種操作,它支持所有的Redis原生的api。 * @param jedisConnectionFactory * @return */ @Bean public RedisTemplate redisTemplate(@Autowired JedisConnectionFactory jedisConnectionFactory){ RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setEnableTransactionSupport(true); redisTemplate.setConnectionFactory(jedisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer()); return redisTemplate; }
/** * 配置一個(gè)緩存管理者,使用spring-data-redis提供的RedisCacheManager類配置, * RedisCacheManager實(shí)現(xiàn)了spring cache提供的CacheManager接口 * @param redisTemplate * @return */ @Bean public RedisCacheManager redisCacheManager(@Autowired RedisTemplate redisTemplate){ RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
//注入緩存名稱 Set<String> cacheNames = new HashSet<>(); cacheNames.add('userCache'); cacheNames.add('rolesCache'); cacheNames.add('movieBoxOffice'); redisCacheManager.setCacheNames(cacheNames);
//默認(rèn)緩存過(guò)期時(shí)間 redisCacheManager.setDefaultExpiration(expiration);
//指定某個(gè)緩存名稱下的緩存的過(guò)期時(shí)間 Map<String,Long> expirationMap = new HashMap<>(); expirationMap.put('userCache',3600l); redisCacheManager.setExpires(expirationMap);
return redisCacheManager; } }
最終要獲取的是一個(gè)CacheManager對(duì)象,即緩存管理者,Redis提供的實(shí)現(xiàn)CacheManager的類是RedisCacheManager。就是redisCacheManager方法配置的bean。能看懂xml的配置這里也就不難看懂了。 同樣,這里的@EnableCaching注解也被我注釋了,就是因?yàn)槲乙獙⑹聞?wù)管理和緩存單獨(dú)配置。 因?yàn)槲蚁胍獙?shí)現(xiàn)像xml配置那樣指定默認(rèn)的事務(wù)管理者和默認(rèn)的緩存管理者。 /** * 開(kāi)啟緩存 * 開(kāi)啟事務(wù)管理 */ @Configuration // 配合CachingConfigurerSupport可指定緩存管理者, // 否則spring從bean容器中查找一個(gè)實(shí)現(xiàn)CacheManager的對(duì)象 @EnableCaching // 配合TransactionManagementConfigurer可指定事務(wù)管理者, // 為@TransactionManager注解配置默認(rèn)的緩存管理者 @EnableTransactionManagement public class TxAndCacheConfig extends CachingConfigurerSupport implements TransactionManagementConfigurer {
/** * 在MyBatisConfig中配置了dataSourceTransactionManager,所以@Autowired注入的就是dataSourceTransactionManager */ @Autowired private PlatformTransactionManager dataSourceTransactionManager;
/** * 在RedisConfig中配置了redisCacheManager,所以@Autowired注入的就是redisCacheManager */ @Autowired private CacheManager cacheManager;
@Override public PlatformTransactionManager annotationDrivenTransactionManager() { return dataSourceTransactionManager; }
@Override public CacheManager cacheManager() { return cacheManager; } }
@EnableCaching開(kāi)啟緩存,@EnableTransactionManagement開(kāi)啟事務(wù)管理。這里使用@Autowired注入了之前配置的事務(wù)管理者和redis緩存管理者。 CachingConfigurerSupport實(shí)現(xiàn)CachingConfigurer接口,雖然CachingConfigurerSupport是CachingConfigurer接口的空實(shí)現(xiàn),但是我們沒(méi)有必要直接去實(shí)現(xiàn)CachingConfigurer接口,因?yàn)槲覀兿胍闹皇菍?shí)現(xiàn)cacheManager這一個(gè)方法。重寫(xiě)CachingConfigurerSupport的cacheManager方法返回緩存管理者就是指定默認(rèn)的緩存管理者。 實(shí)現(xiàn)TransactionManagementConfigurer接口,在annotationDrivenTransactionManager方法中返回事務(wù)管理者就是指定默認(rèn)事務(wù)管理者。 由于并不是很多人都采用Shiro做權(quán)限驗(yàn)證,所以這里就不介紹它的配置了,給個(gè)參考大家看就行了。 @Configuration public class ShiroConfig {
@Autowired private AuthorizingRealm realm;
/** * 配置SecurityManager * @return */ @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm); return securityManager; }
/** * 被代理的shiroFilter * @param securityManager * @return */ @Bean('shiroFilter') public ShiroFilterFactoryBean shiroFilterFactory(@Qualifier('securityManager') SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //注入SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager);
//注入過(guò)濾器 Map<String, Filter> filterMap = new HashMap<>(); filterMap.put('authc', new WeiAi7LvUserAuthcFilter()); filterMap.put('roles', new WeiAi7LvRolesAuthorizationFilter()); shiroFilterFactoryBean.setFilters(filterMap);
//過(guò)濾器Chain定義,指定哪些資源(url)交給哪個(gè)過(guò)濾器過(guò)濾,責(zé)任鏈模式 Map<String, String> map = new HashMap<>(); map.put('/', 'anon'); map.put('/sms/send', 'anon'); map.put('/user/login', 'anon'); map.put('/user/regist', 'anon'); map.put('/user/logout', 'authc'); map.put('/lover/record', 'roles[lover]'); map.put('/lover/*', 'authc'); map.put('/found/*', 'authc'); map.put('/**', 'roles[lover]'); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; }
}
使用@EnableAsync注解開(kāi)啟異步管理,如果項(xiàng)目中配置了多個(gè)線程池,則可以實(shí)現(xiàn)AsyncConfigurer接口指定當(dāng)@Async注解不指定線程池時(shí)使用的默認(rèn)線程池。這里我為了偷懶就不使用@Value注入屬性了,直接賦值。 @Configuration // 啟用spring線程池,配合AsyncConfigurer接口使用指定線程池 // 如果不配合AsyncConfigurer使用則spring會(huì)從bean容器中查找一個(gè)實(shí)現(xiàn)Executor接口的bean對(duì)象作為默認(rèn)的線程池 @EnableAsync public class AsyncConfig implements AsyncConfigurer {
private Integer corePoolSize = 5; private Integer maxPoolSize = 10; private Integer queueCapacity = 200; private Integer keepAlive = 300;//單位秒
@Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize); executor.setMaxPoolSize(maxPoolSize); executor.setQueueCapacity(queueCapacity); executor.setThreadNamePrefix('weiai-executor-'); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.setKeepAliveSeconds(keepAlive); executor.initialize(); return executor; }
@Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new AsyncUncaughtExceptionHandler() { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... objects) { System.err.println(method.getName()+'異步方法執(zhí)行異常===>'+throwable.getMessage()); throwable.printStackTrace(); } }; } }
完成。。。。 本文的很多配置都是我根據(jù)spring提供的注解的詞意猜出來(lái)的,像@Import、@EnableAsync等注解的使用都是猜出來(lái)的。其實(shí)可以看出個(gè)規(guī)律,如@EnableCaching、@EnableTransactionManagement注解分別是用來(lái)開(kāi)啟緩存管理和事務(wù)管理的,所以@Enable開(kāi)頭的注解都是用來(lái)聲明開(kāi)啟xx的,而且實(shí)現(xiàn)CachingConfigurer接口可以指定默認(rèn)的緩存管理者、實(shí)現(xiàn)TransactionManagementConfigurer接口可以指定默認(rèn)的事務(wù)管理者,那么@EnableXXX注解一定提供一個(gè)XXXConfigurer接口來(lái)實(shí)現(xiàn)指定默認(rèn)XXX。
|