修改spring-security-oauth2获取用户资源使用连接池

        本文介绍使用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;
    }
}

下载源码Gitee 极速下载/spring-security-oauth2-autoconfigurehttps://gitee.com/mirrors/spring-security-oauth2-boot.git

查找方法

点击配置项

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里面设置好链接池就好了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值