本文介绍使用spring-security-oauth2进行授权认证后,获取用户资源时,使用oauth2RestTemplate进行访问,没有使用连接池,进行优化。
设置连接池的代码
package org.springframework.security.oauth2.client.test;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.security.oauth2.resource.DefaultUserInfoRestTemplateFactory;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateCustomizer;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import java.util.List;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import java.util.concurrent.TimeUnit;
/**
* @Author wfl 2021/12/23
* 功能
*/
@Component
public class OAuth2RestTemplatePool extends DefaultUserInfoRestTemplateFactory {
public long timeToLive = 2;
public int maxTotalConnections = 256;
public int maxRouteTotalConnections = 256;
public OAuth2RestTemplatePool(ObjectProvider<List<UserInfoRestTemplateCustomizer>> customizers, ObjectProvider<OAuth2ProtectedResourceDetails> details, ObjectProvider<OAuth2ClientContext> oauth2ClientContext) {
super(customizers, details, oauth2ClientContext);
}
@Override
public OAuth2RestTemplate getUserInfoRestTemplate() {
OAuth2RestTemplate userInfoRestTemplate = super.getUserInfoRestTemplate();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(timeToLive, TimeUnit.SECONDS);
// 设置连接池最大连接数
connectionManager.setMaxTotal(maxTotalConnections);
// 设置路由最大连接
connectionManager.setDefaultMaxPerRoute(maxRouteTotalConnections);
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
HttpClientBuilder.create().setConnectionManager(connectionManager)
.evictIdleConnections(60, TimeUnit.SECONDS)
.disableAutomaticRetries()
.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
.build()
);
userInfoRestTemplate.setRequestFactory(factory);
return userInfoRestTemplate;
}
}
查找方法
点击配置项
security: oauth2: resource: user-info-uri: xxx/user
到达
ResourceServerProperties类的方法--public void set(String userInfoUri) { this.userInfoUri = userInfoUri; }
看哪里使用了这个路径,点击getUserInfoUri()方法,到达
ResourceServerTokenServicesConfiguration类的-内部类-->UserInfoTokenServicesConfiguration类的--public UserInfoTokenServices userInfoTokenServices()方法
@Bean
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
public UserInfoTokenServices userInfoTokenServices() {
UserInfoTokenServices services = new UserInfoTokenServices(this.sso.getUserInfoUri(),
this.sso.getClientId());
//这里设置restTemplate
services.setRestTemplate(this.restTemplate);
services.setTokenType(this.sso.getTokenType());
if (this.authoritiesExtractor != null) {
services.setAuthoritiesExtractor(this.authoritiesExtractor);
}
if (this.principalExtractor != null) {
services.setPrincipalExtractor(this.principalExtractor);
}
return services;
}
看到了设置restTemplate的设置方法,点击找到上边的
public UserInfoTokenServicesConfiguration(ResourceServerProperties sso,
UserInfoRestTemplateFactory restTemplateFactory,
ObjectProvider<AuthoritiesExtractor> authoritiesExtractor,
ObjectProvider<PrincipalExtractor> principalExtractor) {
this.sso = sso;
this.restTemplate = restTemplateFactory.getUserInfoRestTemplate();
this.authoritiesExtractor = authoritiesExtractor.getIfAvailable();
this.principalExtractor = principalExtractor.getIfAvailable();
}
原来是由restTemplateFactory获取的,点击有2个实现,应该DefaultUserInfoRestTemplateFactory这个实现类,因为再这个配置类中,配置的是这个类,看代码
@Configuration
@ConditionalOnMissingBean(AuthorizationServerEndpointsConfiguration.class)
public class ResourceServerTokenServicesConfiguration {
@Bean
@ConditionalOnMissingBean
public UserInfoRestTemplateFactory userInfoRestTemplateFactory(
ObjectProvider<List<UserInfoRestTemplateCustomizer>> customizers,
ObjectProvider<OAuth2ProtectedResourceDetails> details,
ObjectProvider<OAuth2ClientContext> oauth2ClientContext) {
return new DefaultUserInfoRestTemplateFactory(customizers, details, oauth2ClientContext);
}
上边代码有个@ConditionalOnMissingBean注解,表示没有这个bean就创建。
我们看到上边有行代码this.restTemplate =restTemplateFactory.getUserInfoRestTemplate()。进入方法;DefaultUserInfoRestTemplateFactory类的getUserInfoRestTemplate()方法。
@Override
public OAuth2RestTemplate getUserInfoRestTemplate() {
if (this.oauth2RestTemplate == null) {
//这里是赋值
this.oauth2RestTemplate = createOAuth2RestTemplate(
this.details == null ? DEFAULT_RESOURCE_DETAILS : this.details);
this.oauth2RestTemplate.getInterceptors().add(new AcceptJsonRequestInterceptor());
AuthorizationCodeAccessTokenProvider accessTokenProvider = new AuthorizationCodeAccessTokenProvider();
accessTokenProvider.setTokenRequestEnhancer(new AcceptJsonRequestEnhancer());
this.oauth2RestTemplate.setAccessTokenProvider(accessTokenProvider);
if (!CollectionUtils.isEmpty(this.customizers)) {
AnnotationAwareOrderComparator.sort(this.customizers);
for (UserInfoRestTemplateCustomizer customizer : this.customizers) {
customizer.customize(this.oauth2RestTemplate);
}
}
}
return this.oauth2RestTemplate;
}
private OAuth2RestTemplate createOAuth2RestTemplate(OAuth2ProtectedResourceDetails details) {
if (this.oauth2ClientContext == null) {
return new OAuth2RestTemplate(details);
}
//这里才是真正为restTempalte赋值的地方进入构造方法
return new OAuth2RestTemplate(details, this.oauth2ClientContext);
}
进入无参构造方法,会看到下面有个有参构造,设置连接池的地方
一直点击去
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
这个里面获取请求对象都是新创建
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
}
else {
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
}
}
改用连接池,提高性能见最上边
我们用restTemplate发送请求的时候执行的是父类HttpAccessor的这个方法
protected ClientHttpRequest createRequest(URI url, HttpMethod method)
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
initialize(request);
if (logger.isDebugEnabled()) {
logger.debug("HTTP " + method.name() + " " + url);
}
return request;
}
这里就是先获取RequestFactory()在创建请求,我们只要在RequestFactory里面设置好链接池就好了