SpringBoot用某个组件,并自定义有关配置
【1】自定义ResetTemplate
【1】导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--自定义resttemplate连接池时,依赖该jar-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
</dependencies>
【2】编写yml配置文件,有些硬编码可自行抽取
server:
port: 8001
spring:
application:
name: consumer
resttemplate:
maxTotalConnect: 20 #最大连接数
maxConnectPerRoute: 20 #最大并发数
getRequestTimeout: 2500 #获取连接的等待时间
connectTimeout: 2000 #连接服务器的等待时间
readTimeout: 1000 #等待服务器数据的时间
【3】配置类编写:总顺序:创建连接池,用连接池创建客户端对象,用客户端对象创建restTemplate对象
// Desc:自定义创建RestTemplate对象的配置类
@Configuration
@ConditionalOnClass(value = {RestTemplate.class, HttpClient.class})//如果这两个类存在该配置才会生效
public class RestConfig {
//连接池最大连接数
@Value("${resttemplate.maxTotalConnect}")
private int maxTotalConnect;
//最大并发数
@Value("${resttemplate.maxConnectPerRoute}")
private int maxConnectPerRoute;
@Value("${resttemplate.connectTimeout}")
private int connectTimeout;
@Value("${resttemplate.readTimeout}")
private int readTimeout;
@Value("${resttemplate.getRequestTimeout}")
private int getRequestTimeout;
/**
* 创建RestTemplate对象
* @return
*/
@Bean
@ConditionalOnMissingBean(RestTemplate.class)//IOC中不存在这个类型的bean才会创建自定义的bean
public RestTemplate createtempLate() {
//创建ClientHttpRequestFactory对象,作为参数传递给resttemplate
RestTemplate restTemplate = new RestTemplate(this.createFactory());
//设置默认的异常处理器
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
//创建一个内容转换器然后在set到resttemplate中
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
//添加字符转换器
messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
//添加
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
messageConverters.add(new MappingJackson2HttpMessageConverter());
//将内容转换器添加到resttemplate对象中
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
//另一种方式添加内容转换器,了解即可。获取resttemplate对象中的内容转换器,然后在内容转化器中添加
/* List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
HttpMessageConverter<?> converterTarget = null;
for (HttpMessageConverter<?> item : converterList) {
if (StringHttpMessageConverter.class == item.getClass()) {
converterTarget = item;
break;
}
}
if (null != converterTarget) {
converterList.remove(converterTarget);
}
converterList.add(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));*/
//加入FastJson转换器 根据使用情况进行操作,此段注释,默认使用jackson
//converterList.add(new FastJsonHttpMessageConverter4());
}
/** n
* 创建http客户端工厂
* @return 客户端工厂
*/
public ClientHttpRequestFactory createFactory() {
// 最大连接数小于等于0,使用spring整合的默认resttemplate配置,底层使用jdk的HttpConnection,
if (this.maxTotalConnect <= 0) {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(this.connectTimeout);
factory.setReadTimeout(this.readTimeout);
return factory;
}
// 大于0使用Apache的HttpClient,自定义连接池的相关属性
//【1】创建连接池,并设置参数
//设置长连接时间为30秒
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
//设置整个连接池最大连接数
connectionManager.setMaxTotal(maxTotalConnect);
//最大并行数
connectionManager.setDefaultMaxPerRoute(maxConnectPerRoute);
//【2】创建HttpClient对象,并设置请求的参数,httpclient对象依赖连接池
HttpClientBuilder builder = HttpClients.custom();
RequestConfig config = RequestConfig.custom()
//服务器返回数据(response)的时间,超过该时间抛出read timeout
.setSocketTimeout(this.readTimeout)
//连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
.setConnectTimeout(this.connectTimeout)
//从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException:
// Timeout waiting for connection from pool
.setConnectionRequestTimeout(this.getRequestTimeout)
.build();
List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
headers.add(new BasicHeader("Accept-Language", "zh-CN"));
HttpClient httpClient = HttpClientBuilder.create()
//添加连接池
.setConnectionManager(connectionManager)
//添加默认重试机制
.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
//添加长接连所需的请求头
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
//添加请求配置
.setDefaultRequestConfig(config)
//设置请求头
.setDefaultHeaders(headers)
//建造对象
.build();
//【3】创建连接工厂,依赖httpClient对象
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
return factory;
}
}
【2】自定义RedisTemplate,并自定义Springboot Cache设置(使用redis作为缓存的设置)
package com.dist.xdata.dedms.infrastructure.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class RedisConfig {
@Value("${spring.redis.clusterNodes:}")
private String clusterNodes;
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Value("${spring.redis.password:}")
private String redisPasswd;
private int timeOut = 2000;
private int redirects = 8;
/**
* redis配置
* @return
*/
@Bean
public RedisClusterConfiguration redisClusterConfiguration() {
Map<String, Object> source = Maps.newHashMap();
if (!StringUtils.isBlank(clusterNodes)) {
source.put("spring.redis.cluster.nodes", clusterNodes);
}
source.put("spring.redis.cluster.timeout", timeOut);
source.put("spring.redis.cluster.max-redirects", redirects);
return new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
}
/**
* redis连接
* @param redisClusterConfiguration
* @return
*/
@Bean
public RedisConnectionFactory redisConnectionFactory(RedisClusterConfiguration redisClusterConfiguration) {
JedisConnectionFactory cf;
if (!StringUtils.isBlank(clusterNodes)) {
cf = new JedisConnectionFactory(redisClusterConfiguration);
} else {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(redisHost);
redisStandaloneConfiguration.setPort(redisPort);
redisStandaloneConfiguration.setPassword(RedisPassword.of(redisPasswd));
cf = new JedisConnectionFactory(redisStandaloneConfiguration);
}
cf.afterPropertiesSet();
return cf;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(factory);
// 定义key序列化方式
RedisSerializer<String> keySerializer = new StringRedisSerializer();
// 定义value的序列化方式
Jackson2JsonRedisSerializer valueSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
valueSerializer.setObjectMapper(om);
template.setKeySerializer(keySerializer);
template.setValueSerializer(valueSerializer);
template.setHashKeySerializer(keySerializer);
template.setHashValueSerializer(valueSerializer);
template.afterPropertiesSet();
return template;
}
/**
* 创建RedisCacheManager,替换默认的
* @param redisConnectionFactory redis的连接工厂1
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
// 默认配置,过期时间指定是30分钟
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
defaultCacheConfig.entryTtl(Duration.ofMinutes(30));
// redisExpire1h cache配置,过期时间指定是1小时,缓存key的前缀指定成dist-_(存到redis的key会自动添加这个前缀)
RedisCacheConfiguration userCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().
entryTtl(Duration.ofHours(1)).prefixKeysWith("dist-");
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(8);
redisCacheConfigurationMap.put("redisExpire1h", userCacheConfiguration);
RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig, redisCacheConfigurationMap);
return cacheManager;
}
}
【3】自定义@Scheduler定时任务注解设置
@Configuration
public class AsyncTaskConfig implements SchedulingConfigurer {
//线程池线程数量,获取当前处理的的逻辑处理器数,本台电脑i7是12线程,得到是12
private final static int corePoolSize = Runtime.getRuntime().availableProcessors() * 5;
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.initialize();// 初始化线程池
scheduler.setPoolSize(corePoolSize);// 线程池容量
scheduler.setDaemon(true); // 设置守护线程
return scheduler;
}
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
//注册定时任务的线程池
scheduledTaskRegistrar.setTaskScheduler(taskScheduler());
}
}
【4】自定义Filter的两种方式
1,使用注解@WebFilter
package com.dist.web.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPattern = "*.txt")
public class TxtPreviewFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if (httpServletRequest.getRequestURI().endsWith("txt")) {
httpServletResponse.setHeader("Content-Type", "text/plain;charset=UTF-8");
}
chain.doFilter(httpServletRequest, httpServletResponse);
}
@Override
public void destroy() {
}
}
2,使用配置类添加自定义过滤器
2.1,实现一个Filter接口,然后在配置类中添加过滤器
package com.dist.web.config;
import com.dist.web.filter.AasWopiFilter;
import com.dist.web.filter.AppValidateFilter;
import com.dist.web.filter.TxtPreviewFilter;
import com.dist.web.filter.WopiFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class FilterConfig {
/**
* txt文件预览过滤器
* @return
*/
@Bean
public FilterRegistrationBean txtPreviewFilterRegistrationBean() {
//创建注册器
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
//new 过滤器对象
TxtPreviewFilter txtPreviewFilter = new TxtPreviewFilter();
//注册
registrationBean.setFilter(txtPreviewFilter);
//添加过滤规则
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("*.txt");
registrationBean.setUrlPatterns(urlPatterns);
// 数字越小,优先级越高
registrationBean.setOrder(Integer.MAX_VALUE - 3);
return registrationBean;
}
}
【5】springboot中使用线程池
5.1,编写配置类,自定义一个线程池注册到容器中
@Configuration
public class ThreadConfig {
//线程池线程数量
private final static int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 5;
// 最大线程数量
private final static int MAX_POOL_SIZE = CORE_POOL_SIZE * 2;
/**
* 获取线程池
* @return
*/
@Bean(name = "threadExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//设置核心线程数量
executor.setCorePoolSize(CORE_POOL_SIZE);
//设置最大线程数
executor.setMaxPoolSize(MAX_POOL_SIZE);
//设置线程名前缀
executor.setThreadNamePrefix("web-thread-");
//设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//设置线程活跃时间
executor.setKeepAliveSeconds(60);
//设置队列容量
executor.setQueueCapacity(10);
//初始化线程池
executor.initialize();
//可以继续设置其它线程池相关配置,这里省略
return executor;
}
}
5.2、在主类中开启异步执行功能,使用@EnableAsync注解
5.3、在需要异步执行的方法上使用@Async注解。
5.4、注意点:异步执行需要返回值,见下例
@Override
@Async
public ListenableFuture<String> asyncDoWithResult(String mark) {
logger.info("开始执行任务,当前线程为: " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
if (!"yes".equals(mark)) {
throw new IllegalArgumentException("参数错误");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("任务执行完成");
//创建返回值,并设置回调接口
AsyncResult<String> result = new AsyncResult<>("success");
result.addCallback(new ListenableFutureCallback<String>() {
@Override
public void onFailure(Throwable ex) {
logger.info("失败的回调接口:" + ex.getMessage());
}
@Override
public void onSuccess(String result) {
logger.info("成功的回调接口,结果为:" + result);
}
});
return result;
}