/**
- @author:Kevin
- @create: 2023-10-24 17:13
- @Description: 实现动态线程池对象
*/public class DtpExecutor extends ThreadPoolExecutor {
public DtpExecutor(int corePoolSize, int maximumPoolSize) {
super(corePoolSize, maximumPoolSize, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
}
}###### 创建动态线程池核心配置类 1.相关Bean的注入 2. nacos监听的bean注入
package com.laoyang.dtp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;/**
@author:Kevin
@create: 2023-10-24 18:36
@Description: 动态线程池核心配置类
*/
@Configuration
public class DtpExecutorAutoConfiguration {@Autowired
private Environment environment;//最大核心数
private static final String CORE_POOL_SIZE = “dtp.core-pool-size”;
//最大线程数
private static final String MAXIMUM_POOL_SIZE = “dtp.maximum-pool-size”;//创建动态线程池对象
@Bean
public DtpExecutor executor(){Integer corePoolSize = Integer.valueOf(environment.getProperty(CORE_POOL_SIZE)); Integer maximumPoolSize = Integer.valueOf(environment.getProperty(MAXIMUM_POOL_SIZE)); return new DtpExecutor(corePoolSize,maximumPoolSize);
}
@Bean
public NacosLinsenter NacosLinsenter(){
return new NacosLinsenter();
}}
###### 然后通过springboot的自动配置实现将核心配置类注入 ![](https://img-blog.csdnimg.cn/16e758dbb2384b9ba463a10850092ddf.png) 然后写入以下代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.laoyang.dtp.DtpExecutorAutoConfiguration
###### 创建nacos的监听类并实现动态绑定 通过nacos的 **Listener** 接口实现相应的方法编写动态变换逻辑,同时实现spring提供的
InitializingBean接口将当前监听类通过nacos的ConfigService的addListener()方法与dataId一一绑定。(只要dataId的配置文件发生改变,当前绑定的监听类就会调用相应的方法),最终注入线程池对象Bean,将修改的配置文件值再注入进线程池对象Bean,就实现动态线程池。
| | | | --- | --- | |
getExecutor()
|
创建一个线程池供下面的调用
| |
receiveConfigInfo()
|
每次当前的dataId只要改变,就会调用这个方法
|
package com.laoyang.dtp;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ByteArrayResource;import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;/**
- @author:Kevin
- @create: 2023-10-24 19:56
- @Description: nacos自带监听器
*/public class NacosLinsenter implements Listener, InitializingBean {
@NacosInjected private ConfigService configService; @Autowired private DtpExecutor executor; //nacos的dataId的名称 private static final String DATA_ID = "dtp.yaml"; private static final String GROUP = "DEFAULT_GROUP"; //最大核心数 private static final String CORE_POOL_SIZE = "dtp.core-pool-size"; //最大线程数 private static final String MAXIMUM_POOL_SIZE = "dtp.maximum-pool-size"; //创建一个线程池供下面的调用 @Override public Executor getExecutor() { return Executors.newFixedThreadPool(1); } //每次当前的dataId只要改变,就会调用这个方法 //但是调用这个方法的线程需要上面的方法创建一个线程池 @Override public void receiveConfigInfo(String s) { //首先需要将字符串yml格式转化为map的格式 YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean(); factoryBean.setResources(new ByteArrayResource(s.getBytes())); //使用springboot内置工具类转换为Properties类似于map的格式 Properties object = factoryBean.getObject(); //获取更新后的数据 String corePoolSize = object.getProperty(CORE_POOL_SIZE); String maximumPoolSize = object.getProperty(MAXIMUM_POOL_SIZE); //直接更新数据 executor.setCorePoolSize(Integer.parseInt(corePoolSize)); executor.setMaximumPoolSize(Integer.parseInt(maximumPoolSize)); } @Override public void afterPropertiesSet() throws Exception { //将这个NacosLinsenter与当前的dataId一一绑定 configService.addListener(DATA_ID,GROUP,this); }
}
3. 开始在user模块使用 dtp-spring-boot-starter模块
创建启动Springboot配置类
package com.laoyang; import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource; import com.alibaba.nacos.spring.context.annotation.discovery.EnableNacosDiscovery; import com.laoyang.dtp.DtpExecutor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; /** * @author:Kevin * @create: 2023-10-24 17:04 * @Description: */ @SpringBootApplication @NacosPropertySource(dataId = "dtp.yaml", autoRefreshed = true) public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); } }
创建Controller注入动态线程池对象来使用
package com.laoyang.Controller; import com.laoyang.dtp.DtpExecutor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import java.util.concurrent.ThreadPoolExecutor; /** * @author:Kevin * @create: 2023-10-24 17:05 * @Description: 视图层 */ @Controller public class UserController { @Autowired private DtpExecutor executor; @GetMapping public Integer test(){ executor.execute(() -> dotest()); return 1; } public void dotest(){ System.out.println("dotest"); } }
到此大功告成 !!
二,改进
优化1: 假如我们没有配置核心线程数或者最大线程数的话会报错,所以我们要优雅的创建默认值。
步骤:创建配置文件对象(
@ConfigurationProperties("dtp")这个注解会根据参数,找到nacos的配置文件的yml格式的字段,并变成Bean对象。
)
package com.laoyang.dtp; import org.springframework.boot.context.properties.ConfigurationProperties; /** * @author:Kevin * @create: 2023-10-24 21:29 * @Description: 创建配置文件对象 */ @ConfigurationProperties("dtp") public class DtpProperties { private String corePoolSize = "10"; private String maximumPoolSize = "100"; public String getCorePoolSize() { return corePoolSize; } public void setCorePoolSize(String corePoolSize) { this.corePoolSize = corePoolSize; } public String getMaximumPoolSize() { return maximumPoolSize; } public void setMaximumPoolSize(String maximumPoolSize) { this.maximumPoolSize = maximumPoolSize; } }
然后在DtpExecutorAutoConfiguration核心配置类中加上@EnableConfigurationProperties(DtpProperties.class) 注解
然后通过传参的形式优化
优化2. 上面的只能实现一个线程池对象,但是实际项目中并不只是这一个线程池对象,所以接下来我们需要进行优化!
创建一个DtpUtil 将来用来存放创建的多个线程池对象
package com.laoyang.dtp; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; /** * @author:Kevin * @create: 2023-10-24 22:29 * @Description: 线程安全的ConcurrentHashMap */ public class DtpUtil { // public static ConcurrentHashMap<String,DtpExecutor> map = new ConcurrentHashMap<>(); public static HashMap<String,DtpExecutor> map = new HashMap<>(); public static void set(String name,DtpExecutor dtpExecutor){ map.put(name,dtpExecutor); } public static DtpExecutor get(String name) { return map.get(name); } }
实现手动注册bean对象
package com.laoyang.dtp; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.ResolvableType; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; /** * @author:Kevin * @create: 2023-10-24 21:57 * @Description: 注册配置文件bean */ public class DtpImportBeanDefinationRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware { //传入配置文件对象 private Environment environment; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { //注册bean,读取用户配置的dtp后面定义的线程池列表,然后转换为DtpProperties对象 DtpProperties dtpProperties = new DtpProperties(); Binder binder = Binder.get(environment); ResolvableType type = ResolvableType.forClass(DtpProperties.class); Bindable<?> target = Bindable.of(type).withExistingValue(dtpProperties); binder.bind("dtp",target); //遍历配置,拿到所有的线程池列表 for (DtpProperties.DtpExecutorProperties executorProperties : dtpProperties.getDtpExecutors()) { AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(DtpExecutor.class); //往这个DtpExecutor的有参函数中传入两个值 beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(executorProperties.getCorePoolSize()); beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(executorProperties.getMaximumPoolSize()); registry.registerBeanDefinition(executorProperties.getName(),beanDefinition); } } // @Override public void setEnvironment(Environment environment) { this.environment = environment; } }
同时不要忘了在核心配置类注入这个配置
创建bean的后置处理器
package com.laoyang.dtp; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** * @author:Kevin * @create: 2023-10-25 10:29 * @Description: bean的后置处理器:用于注入我们的多动态线程池对象 */ public class DtpBeanPostProcessor implements BeanPostProcessor { /** * 注入这个对象 DtpExecutor * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof DtpExecutor){ DtpUtil.set(beanName,(DtpExecutor)bean); } return bean;
为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!
这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。
本份面试集锦涵盖了
- 174 道运维工程师面试题
- 128道k8s面试题
- 108道shell脚本面试题
- 200道Linux面试题
- 51道docker面试题
- 35道Jenkis面试题
- 78道MongoDB面试题
- 17道ansible面试题
- 60道dubbo面试题
- 53道kafka面试
- 18道mysql面试题
- 40道nginx面试题
- 77道redis面试题
- 28道zookeeper
总计 1000+ 道面试题, 内容 又全含金量又高
- 174道运维工程师面试题
1、什么是运维?
2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?
3、现在给你三百台服务器,你怎么对他们进行管理?
4、简述raid0 raid1raid5二种工作模式的工作原理及特点
5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?
6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
作中你怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!