Common-pool2

The Apache Commons Pool open source software library provides an object-pooling API and a number of object pool implementations. Version 2 of Apache Commons Pool contains a completely re-written pooling implementation compared to the 1.x series. In addition to performance and scalability improvements, version 2 includes robust instance tracking and pool monitoring.

common-pool2 是一个开源的对象池
在高并发情况下避免了重 对象新建的操作。
典型如 httpclient
phantomjs

spring 引入第三方jar 包

spring context 注册第三方jar 包中的对象 一般使用

@Configuration 和@Bean 注解组合

/**
 * @author hamish-wu
 */
@Configuration
public class CommonPoolConfig {

    @Bean
    public static GenericObjectPoolConfig genericObjectPoolConfig() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
      /*  genericObjectPoolConfig.setJmxEnabled(false);*/
        return genericObjectPoolConfig;
    }

    @Bean(name = "mypool")
    public GenericObjectPool<HttpClient> getHttpClientPool() {
        return new GenericObjectPool<>(pooledHttpClientFactory, genericObjectPoolConfig);
    }


}

使用@Bean 注解修饰的方法可以使用 static 修饰,影响spring context 注册顺序

static 修饰的方法会被优先注册

@Bean注解可以自定义bean name

使用的时候 建议搭配 @Resource 注解

另外@bean 注册 可以使用@Import 注解替换,但是@import 注解
不如@bean 注解灵活

spring 集成 common-pool2

2.1 启动类:

@SpringBootApplication(scanBasePackages = {"com.fancv.*", "com.google.common.*"}, exclude = {DataSourceAutoConfiguration.class})
@ServletComponentScan(basePackages = {"com.fancv.filter", "com.fancv.listener"})
@EnableSwagger2
@MapperScan("com.fancv.dao")
@Import({MyConfig.class, GuavaConfig.class, IntMath.class, PooledHttpClientFactory.class})
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class SpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApp.class, args);
    }
}

2.2 配置类

import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.http.client.HttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * @author hamish-wu
 */
@Configuration
public class CommonPoolConfig {

    /**
     * Pool  一般配置信息
     */
    @Resource
    GenericObjectPoolConfig genericObjectPoolConfig;

    /**
     *
     */
    @Resource
    PooledHttpClientFactory pooledHttpClientFactory;

    @Bean
    public static GenericObjectPoolConfig genericObjectPoolConfig() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
      /*  genericObjectPoolConfig.setJmxEnabled(false);*/
        return genericObjectPoolConfig;
    }

    @Bean(name = "mypool")
    public GenericObjectPool<HttpClient> getHttpClientPool() {
        return new GenericObjectPool<>(pooledHttpClientFactory, genericObjectPoolConfig);
    }


}

PooledObjectFactory实现类

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;


public class PooledHttpClientFactory implements PooledObjectFactory<HttpClient> {

    @Override
    public PooledObject<HttpClient> makeObject() throws Exception {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        return new DefaultPooledObject<>(httpClient);
    }

    @Override
    public void destroyObject(PooledObject<HttpClient> pooledObject) throws Exception {
        //不处理
    }

    @Override
    public boolean validateObject(PooledObject<HttpClient> pooledObject) {
        return true;
    }

    @Override
    public void activateObject(PooledObject<HttpClient> pooledObject) throws Exception {
        //不处理
    }

    @Override
    public void passivateObject(PooledObject<HttpClient> pooledObject) throws Exception {
        //不处理
    }
}

service 层使用

import com.google.common.math.IntMath;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * guava 单节点限流
 */
@Service
@Slf4j
public class AccessLimitService {


    @Resource(name = "myRate")
    RateLimiter hello;


    @Resource
    IntMath intMath;

    @Resource(name = "mypool")
    GenericObjectPool<HttpClient> httpClientPool;

    /**
     * 尝试获取令牌
     */
    public Boolean tryAcquire() {

        IntMath.isPowerOfTwo(2);

        return hello.tryAcquire();
    }


    /***
     * 获取HTTPClient
     */

    public String getPage() {

        try {
            HttpClient client = httpClientPool.borrowObject();

            try {
                RequestBuilder requestBuilder = RequestBuilder.get("https://www.oschina.net");
                requestBuilder.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.106 Safari/537.36");
                HttpUriRequest httpUriRequest = requestBuilder.build();
                HttpClientContext httpClientContext = new HttpClientContext();

                HttpResponse httpResponse = client.execute(httpUriRequest, httpClientContext);

                byte[] contentBytes = IOUtils.toByteArray(httpResponse.getEntity().getContent());
                System.out.println("获取的网页源码:" + new String(contentBytes, "utf-8"));
                log.info("getFactoryType:{}", httpClientPool.getFactoryType());
                httpClientPool.returnObject(client);
            } catch (Exception ex) {
                httpClientPool.invalidateObject(client);
                ex.printStackTrace();
            }
        } catch (final Exception e) {
            log.error("获取HttpClient 报错", e);
        }

        return "hello";
    }
}

遇到问题

报错信息

org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [GenericObjectPool [maxTotal=8, blockWhenExhausted=true, maxWaitMillis=-1, lifo=true, fairness=false, testOnCreate=false, testOnBorrow=false, testOnReturn=false, testWhileIdle=false, timeBetweenEvictionRunsMillis=-1, numTestsPerEvictionRun=3, minEvictableIdleTimeMillis=1800000, softMinEvictableIdleTimeMillis=-1, evictionPolicy=org.apache.commons.pool2.impl.DefaultEvictionPolicy@4a03c4bc, closeLock=java.lang.Object@3d0c88f4, closed=false, evictionLock=java.lang.Object@5aad4194, evictor=null, evictionIterator=null, factoryClassLoader=java.lang.ref.WeakReference@50a1c2f3, oname=org.apache.commons.pool2:type=GenericObjectPool,name=pool, creationStackTrace=java.lang.Exception
	at org.apache.commons.pool2.impl.BaseGenericObjectPool.<init>(BaseGenericObjectPool.java:147)
	at org.apache.commons.pool2.impl.GenericObjectPool.<init>(GenericObjectPool.java:111)
	at com.fancv.config.CommonPoolConfig.getHttpClientPool(CommonPoolConfig.java:38)
	at com.fancv.config.CommonPoolConfig$$EnhancerBySpringCGLIB$$9d954d11.CGLIB$getHttpClientPool$0(<generated>)
	at com.fancv.config.CommonPoolConfig$$EnhancerBySpringCGLIB$$9d954d11$$FastClassBySpringCGLIB$$f8408bf0.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
	at com.fancv.config.CommonPoolConfig$$EnhancerBySpringCGLIB$$9d954d11.getHttpClientPool(<generated>)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:484)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:454)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:543)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:513)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:653)
	at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:224)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:334)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeanByName(AbstractAutowireCapableBeanFactory.java:454)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:543)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:513)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:653)
	at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:224)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116)
	at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:334)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
	at com.fancv.SpringBootApp.main(SpringBootApp.java:25)
, borrowedCount=0, returnedCount=0, createdCount=0, destroyedCount=0, destroyedByEvictorCount=0, destroyedByBorrowValidationCount=0, activeTimes=StatsStore [values=[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], size=100, index=0], idleTimes=StatsStore [values=[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], size=100, index=0], waitTimes=StatsStore [values=[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], size=100, index=0], maxBorrowWaitTimeMillis=0, swallowedExceptionListener=null, factoryType=null, maxIdle=8, minIdle=0, factory=com.fancv.config.PooledHttpClientFactory@453ca7f, allObjects={}, createCount=0, idleObjects=[], abandonedConfig=null]] with key 'mypool'; nested exception is javax.management.InstanceAlreadyExistsException: MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=pool
	at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:626) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:552) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at java.base/java.util.HashMap.forEach(HashMap.java:1336) ~[na:na]
	at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:552) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:435) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:896) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at com.fancv.SpringBootApp.main(SpringBootApp.java:25) ~[classes/:na]
Caused by: javax.management.InstanceAlreadyExistsException: MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=pool
	at java.management/com.sun.jmx.mbeanserver.MXBeanLookup.addReference(MXBeanLookup.java:151) ~[na:na]
	at java.management/com.sun.jmx.mbeanserver.MXBeanSupport.register(MXBeanSupport.java:160) ~[na:na]
	at java.management/com.sun.jmx.mbeanserver.MBeanSupport.preRegister2(MBeanSupport.java:173) ~[na:na]
	at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:919) ~[na:na]
	at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:890) ~[na:na]
	at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:320) ~[na:na]
	at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[na:na]
	at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:138) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:672) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:616) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	... 14 common frames omitted

原因分析:

MXBean already registered,bean已经被注册
GenericObjectPoolConfig被注册的时候 自动注册了一个GenericObjectPool

解决方法:

1.启动类加上:

@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)

2.bean GenericObjectPoolConfig中有一个genericObjectPoolConfig.setJmxEnabled(false); 关掉监控 这个异常就不会抛出了~

思考

1.spring 中注册第三方jar包的对象
2.@bean 和@import的异同
3.common-pool 中Pool 的初始化
4.spring 注册 bean的顺序

参考资料:https://www.cnblogs.com/gaoquanquan/p/11347843.html

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐