首页 文章 精选 留言 我的

精选列表

搜索[java],共10000篇文章
优秀的个人博客,低调大师

java适配器模式

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。 案例: 定义机器接口和其具体实现的两个不同机器 /** * @author Gjing * 刷卡器 **/ public interface CardMachine { /** * 刷身份证 */ void blushIdCard(String number); /** * 刷银行卡 */ void blushBankCard(String number); } /** * 身份证刷卡器 */ class IdCardMachine implements CardMachine{ @Override

优秀的个人博客,低调大师

Java日志正确使用姿势

前言 关于日志,在大家的印象中都是比较简单的,只须引入了相关依赖包,剩下的事情就是在项目中“尽情”的打印我们需要的信息了。但是往往越简单的东西越容易让我们忽视,从而导致一些不该有的bug发生,作为一名严谨的程序员,怎么能让这种事情发生呢?所以下面我们就来了解一下关于日志的那些正确使用姿势。 正文 日志规范 命名 首先是日志文件的命名,尽量要做到见名知意,团队里面也必须使用统一的命名规范,不然“脏乱差”的日志文件会影响大家排查问题的效率。这里推荐以projectName_logName_logType.log来命名,这样通过名字就可以清晰的知道该日志文件是属于哪个项目,什么类型,有什么作用。例如在我们MessageServer项目中监控Rabbitmq 消费者相关的日志文件名可以定义成messageserver_rabbitmqconsumer_monitor.log。 保存时间 关于日志保存的时间,普通的日志文件建议保留15天,若比较重要的可根据实际情况延长,具体请参考各自服务器磁盘空间以及日志文件大小作出最优选择。 日志级别 常见的日志级别有以下: DEBUG级别:记录调试程序相关的信息。 INFO级别:记录程序正常运行有意义的信息。 WARN级别:记录可能会出现潜在错误的信息。 ERROR级别:记录当前程序出错的信息,需要被关注处理。 Fatal级别:表示出现了严重错误,程序将会中断执行。建议在项目中使用这四种级别, ERROR、WARN、INFO 、DEBUG。 正确姿势 1、提前判断日志级别 //条件判断 if(logger.isDebugEnabled){ logger.debug("server info , id : " + id + ", user : " + user); } //使用占位符 logger.debug("server info , id : {}, user : {}",id,user); 对于DEBUG,INFO级别的日志,在我们的程序中是比较高频的存在,当我们的项目大了,日志变多了,这时候为了程序运行的效率,我们必须以条件判断或者占位符的方式来打印日志。为什么呢?假如我们项目中配置的日志级别为WARN,那么对于我们下面的日志输出语句logger.debug("server info , id : " + id + ", user : " + user);,虽然该日志不会被打印,但是却会执行字符串拼接的操作,这里我们的user是一个实例对象,所以还会执行toString方法,这样就白白浪费了不少系统的资源。 2、避免多余日志输出 在我们的生产环境中,一般禁止DEBUG日志的输出,其打印的频率是非常高的,容易对正常运行的程序造成严重的影响,在我们最近的项目中就有遇到过类似的情况。 那么这时候该学会使用additivity属性<logger name="xx" additivity="true">在这边配置成true的话,也就是默认的情况,这时候当前Logger会继承父Logger的Appender,说白了就是当前日志的输出除了输出在当前日志文件以外,还会输出至父文件里。所以一般情况下,我们为了避免重复打印,会将这个参数设置成false,以减少不必要的输出。 3、保证日志记录信息完整 在我们的代码中,日志记录的内容要包含异常的堆栈,请勿随意输出“XX出错”等简单的日志,这对于错误的调试毫无帮助。所以我们在记录异常的时候一定要带上堆栈信息,例如 logger.error("rabbitmq consumer error,cause : "+e.getMessage(),e);切记在输出对象实例的时候,须确保对象重写了toString方法,否则只会输出其hashCode值。 4、定义logger变量为staticprivate static final Logger logger = LoggerFactory.getLogger(XX.class);确保一个对象只使用一个Logger对象,避免每次都重新创建,否则可能会导致OOM。 5、正确使用日志级别 try{ //.. }catch(xx){ logger.info(..); } 这样一来,本来是ERROR的信息,全都打印在INFO日志文件里了,不知情的同事还会在死盯着错误日志,而且还找不出问题,多影响工作效率是吧? 6、推荐使用slf4j+logback组合 logback库里自身就已经实现了slf4j的接口,就无需引入多余的适配器了,而且logback也具有更多的优点,建议新项目可以使用这个组合。 还有一点需要注意,当引入slf4j后,要注意其实际使用的日志库是否是由我们引入的,也有可能会使用了我们第三方依赖包所带入的日志库,这样就可能会导致我们的日志失效。 7、日志的聚合分析 日志的聚合可以把位于不同服务器之间的日志统一起来分析处理,如今ELK技术栈亦或者的EFG(fluentd+elasticsearch+grafana)等都是一些比较成熟的开源解决方案。 拿ELK来说,可以在我们的服务器上直接通过logstash来读取应用打印的日志文件,或者也可以在我们项目中的日志配置文件里配置好相关的socket信息,打印的时候直接把日志信息输出至logstash。再交由elasticsearch存储,kibana展示。 本文作者: wangzenghuang 文章来源:深夜里的程序猿

优秀的个人博客,低调大师

漫谈Java高并发方案

0 相关源码 1 基本概念 1.1 并发 同时拥有两个或者多个线程,如果程序在单核处理器上运行多个线程将交替地换入或者换出内存,这些线程是同时“存在"的,每个线程都处于执行过程中的某个状态,如果运行在多核处理器上,此时,程序中的每个线程都将分配到一个处理器核上,因此可以同时运行. 1.2 高并发( High Concurrency) 互联网分布式系统架构设计中必须考虑的因素之一,通常是指,通过设计保证系统能够同时并行处理很多请求. 1.3 区别与联系 并发: 多个线程操作相同的资源,保证线程安全,合理使用资源 高并发:服务能同时处理很多请求,提高程序性能 2 CPU 2.1 CPU 多级缓存 为什么需要CPU cacheCPU的频率太快了,快到主存跟不上 如此,在处理器时钟周期内,CPU常常需要等待主存,浪费资源。所以cache的出现,是为了缓解CPU和

优秀的个人博客,低调大师

JAVA学习day12

1、构造方法在创建对象的时候,就有属性值——构造方法 set和get方法时对象创建后使用的 2、什么时候需要写构造方法2-1)当描述的事物在创建其对象时就要明确属性的值,这时就需要在定义类的时候书写带参数的构造方法。2-2)若创建对象时不需要明确具体的数据,这时可以不用书写构造方法(不书写也有默认的构造方法)。 没有写构造方法的:在编译时系统会自动创建一个空的构造方法class Person { //如果没有显示指定构造方法,编译会在编译时自动添加默认的构造方法 //Person(){} //空参数的默认构造方法 } 3、构造方法的格式:修饰符 构造方法名(参数列表){} 4、构造方法的体现: 构造方法没有返回值类型。也不需要写返回值。因为它是为构建对象的,对象创建完,方法就执行结束。 构造方法名称必须和类型保持一致。 构造方法没有具体的返回值。 构造方法的代码体现:class Person { // Person的成员属性age和name private int age; private String name; // Person的构造方法,拥有参数列表 Person(int a, String nm) { // 接受到创建对象时传递进来的值,将值赋给成员属性 age = a; name = nm; } } 5、构造方法的细节:1、一个类中可以有多个构造方法,多个构造方法是以重载的形式存在的2、构造方法是可以被private修饰的,作用:其他程序无法创建该类的对象。class Person { private int age; private String name; // 私有无参数的构造方法,即外界不能通过new Person();语句创建本类对象 private Person() { } // 多个构造方法是以重载的形式存在 Person(int a) { age = a; } Person(String nm, int a) { name = nm; age = a; } } 6、this调用构造方法构造方法之间的调用,可以通过this关键字来完成。l 构造方法调用格式:this(参数列表);l 构造方法的调用class Person { // Person的成员属性 private int age; private String name; // 无参数的构造方法 Person() { } // 给姓名初始化的构造方法 Person(String nm) { name = nm; } // 给姓名和年龄初始化的构造方法 Person(String nm, int a) { // 由于已经存在给姓名进行初始化的构造方法 name = nm;因此只需要调用即可 // 调用其他构造方法,需要通过this关键字来调用 this(nm); // 给年龄初始化 age = a; } } l 注意:this到底代表什么呢?this代表的是对象,具体代表哪个对象呢?哪个对象调用了this所在的方法,this就代表哪个对象。调用其他构造方法的语句必须定义在构造方法的第一行,原因是初始化动作要最先执行。 7、子父类中构造方法的调用在创建子类对象时,父类的构造方法会先执行,因为子类中所有构造方法的第一行有默认的隐式super();语句。格式:调用本类中的构造方法this(实参列表);调用父类中的空参数构造方法super();调用父类中的有参数构造方法 super(实参列表); 为什么子类对象创建都要访问父类中的构造方法?因为子类继承了父类的内容,所以创建对象时,必须要先看父类是如何对其内容进行初始化的,看如下程序:public class Test { public static void main(String[] args) { new Zi(); } }class Fu{ int num ; Fu(){ System.out.println("Fu构造方法"+num); num = 4; } }class Zi extends Fu{ Zi(){ //super(); 调用父类空参数构造方法 System.out.println("Zi构造方法"+num); } }执行结果: Fu构造方法0 Zi构造方法4 通过结果发现,子类构造方法执行时中,调用了父类构造方法,这说明,子类构造方法中有一句super()。那么,子类中的构造方法为什么会有一句隐式的super()呢?原因:子类会继承父类中的内容,所以子类在初始化时,必须先到父类中去执行父类的初始化动作。这样,才可以使用父类中的内容。当父类中没有空参数构造方法时,子类的构造方法必须有显示的super语句,指定要访问的父类有参数构造方法。 8、知识点总结l this关键字n this关键字,本类对象的引用 u this是在方法中使用的,哪个对象调用了该方法,那么,this就代表调用该方法的对象引用 u this什么时候存在的?当创建对象的时候,this存在的 u this的作用:用来区别同名的成员变量与局部变量(this.成员变量) public void setName(String name) { this.name = name; } l 构造方法: 用来给类的成员进行初始化操作n 格式: 修饰符 类名 (参数列表) { ... } n 构造方法的特点: u 1, 方法名与类名相同 u 2,没有返回值,也没有返回值类型,连void也没有 n 构造方法什么时候会被调用执行? 只有在创建对象的时候才可以被调用 l super: 指的是父类的存储空间(理解为父类的引用)调用父类的成员变量: super.成员变量; 调用父类的构造方法: super(参数); 调用方法的成员方法: super.成员方法(); l 继承中的构造方法注意事项: 1,如果我们手动给出了构造方法,编译器不会在给我们提供默认的空参数构造方法 如果我们没写任何的构造方法,编译器提供给我们一个空参数构造方法 2, 在构造方法中,默认的第一条语句为 super(); 它是用来访问父类中的空参数构造方法,进行父类成员的初始化操作 3, 当父类中没有空参数构造方法的时候,怎么办? a: 通过 super(参数) 访问父类有参数的构造方法 b: 通过 this(参数) 访问本类中其他构造方法 注意:[本类中的其他构造方法已经能够正常访问父类构造方法] 4, super(参数) 与 this(参数) 不能同时在构造方法中存在

优秀的个人博客,低调大师

Kafka 消息队列 Java

消费者 apache kafka工具类,消费者Consumer类 public class Consumer { private ConsumerHandler handler; private ConsumerConfig config; private KafkaConsumer<String, String> consumer; private boolean startFlag = false; /** * 创建消费者 * * @param handler * 消费者处理类 * @param config * 消费者处理配置 */ public Consumer(ConsumerHandler handler, ConsumerConfig config) { this.handler = handler; this.config = config; init(); } /** * 初始化接收器 */ private void init() { Properties props = new Properties(); props.put("bootstrap.servers", config.getBootstrapServers());// 服务器ip:端口号,集群用逗号分隔 props.put("group.id", config.getGroupID()); /* 是否自动确认offset */ props.put("enable.auto.commit", "true"); /* 自动确认offset的时间间隔 */ props.put("auto.commit.interval.ms", config.getAutoCommitInterVal()); props.put("session.timeout.ms", config.getSessionTimeOut()); /* key的序列化类 */ props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); /* value的序列化类 */ props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); consumer = new KafkaConsumer<>(props); if (config.isProcessBeforeData()) { /* 消费者订阅的topic, 可同时订阅多个 */ consumer.subscribe(config.getTopicList(), new ConsumerRebalanceListener() { @Override public void onPartitionsRevoked(Collection<TopicPartition> partitions) { } @Override public void onPartitionsAssigned(Collection<TopicPartition> partitions) { for (TopicPartition partition : partitions) { long offset = handler.getSeek(partition.topic(), partition.partition()); if (offset >= 0) { if (consumer != null) { consumer.seek(partition, offset + 1); } } else { consumer.seekToBeginning(partitions); } } } }); start(); } else { consumer.subscribe(config.getTopicList()); } } public void start() { startFlag = true; while (startFlag) { /* 读取数据,读取超时时间为XXms */ ConsumerRecords<String, String> records = consumer.poll(config.getPollTime()); if (records.count() > 0) { long offset = 0; int partition = 0; for (ConsumerRecord<String, String> record : records) { if (record != null) { offset = record.offset(); partition = record.partition(); try { handler.processObject(record.topic(), record.partition(), record.offset(), record.value()); } catch (Exception e) { e.printStackTrace(); } } } } try { Thread.currentThread(); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } consumer.close(); } public void stop() { startFlag = false; } } 消费者配置ConsumerConfig类 public class ConsumerConfig { private String bootstrapServers; private String groupID; private int autoCommitInterVal =1000; private int sessionTimeOut = 30000; private List<String> topicList; private boolean processBeforeData; private long pollTime = 100; public ConsumerConfig() { super(); } /** * 创建消费者配置 * @param bootstrapServers 服务器配合 格式为服务器ip:端口号,集群用逗号分隔 例如 192.168.1.1:9092,192.168.1.2:9092 * @param groupID groupID * @param autoCommitInterVal 自动提交时间单位毫秒, 默认1000 * @param sessionTimeOut 超时时间单位毫秒 , 默认30000 * @param topicList topicList列表 * @param processBeforeData 是否处理启动之前的数据,该开关需要配置consumerHandler的跨步存储使用 * @param pollTime 每次获取数据等待时间单位毫秒,默认100毫秒 */ public ConsumerConfig(String bootstrapServers, String groupID, int autoCommitInterVal, int sessionTimeOut ,List<String> topicList,boolean processBeforeData,long pollTime) { this.bootstrapServers = bootstrapServers; this.groupID = groupID; this.autoCommitInterVal = autoCommitInterVal; this.sessionTimeOut = sessionTimeOut; this.topicList = topicList; this.processBeforeData = processBeforeData; this.pollTime = pollTime; } public String getBootstrapServers() { return bootstrapServers; } public void setBootstrapServers(String bootstrapServers) { this.bootstrapServers = bootstrapServers; } public String getGroupID() { return groupID; } public void setGroupID(String groupID) { this.groupID = groupID; } public int getAutoCommitInterVal() { return autoCommitInterVal; } public void setAutoCommitInterVal(int autoCommitInterVal) { this.autoCommitInterVal = autoCommitInterVal; } public int getSessionTimeOut() { return sessionTimeOut; } public void setSessionTimeOut(int sessionTimeOut) { this.sessionTimeOut = sessionTimeOut; } public List<String> getTopicList() { return topicList; } public void setTopicList(List<String> topicList) { this.topicList = topicList; } public boolean isProcessBeforeData() { return processBeforeData; } public void setProcessBeforeData(boolean processBeforeData) { this.processBeforeData = processBeforeData; } public long getPollTime() { return pollTime; } public void setPollTime(long pollTime) { this.pollTime = pollTime; } } 消费者处理ConsumerHandler类 public interface ConsumerHandler { /** * 处理收到的消息 * @param topic 收到消息的topic名称 * @param partition 收到消息的partition内容 * @param offset 收到消息在队列中的编号 * @param value 收到的消息 */ void processObject(String topic,int partition,long offset,String value); /** * 获取跨步 * @param topic 接受消息的topic * @param partition 接受消息的partition * @return 当前topic,partition下的seek */ long getSeek(String topic , int partition); } 生产者 kafka生产者,工具Producer类 public class Producer { private ProducerConfig config ; private org.apache.kafka.clients.producer.Producer<String,String> producer; public Producer(ProducerConfig config){ this.config = config; init(); } private void init(){ Properties props = new Properties(); props.put("bootstrap.servers",config.getBootstrapServers()); props.put("acks", "all"); props.put("retries", config.getRetries()); props.put("batch.size", config.getBatchSize()); props.put("linger.ms", config.getLingerMs()); props.put("buffer.memory", config.getBufferMemory()); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); producer = new KafkaProducer<>(props); } /** * 发送消息 * @param topic 要发送的topic * @param msg */ public void sendMessage(String topic,String msg){ try { producer.send(new ProducerRecord<String, String>(config.getTopic(), String.valueOf(new Date().getTime()), msg)).get(); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (ExecutionException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } producer.flush(); } public void close(){ producer.close(); } } kafka生产者配置ProducerConfig类 public class ProducerConfig { private String bootstrapServers; private String topic; private int retries = 0; private int batchSize = 16384; private int lingerMs=1; private int bufferMemory=33554432; public ProducerConfig() { super(); } /** * 创建生产者配置文件 * @param bootstrapServers 服务器配合 格式为服务器ip:端口号,集群用逗号分隔 例如 192.168.1.1:9092,192.168.1.2:9092 * @param retries * @param batchSize * @param lingerMs * @param bufferMemory */ public ProducerConfig(String bootstrapServers,int retries, int batchSize, int lingerMs, int bufferMemory) { this.bootstrapServers = bootstrapServers; this.retries = retries; this.batchSize = batchSize; this.lingerMs = lingerMs; this.bufferMemory = bufferMemory; } public String getBootstrapServers() { return bootstrapServers; } public void setBootstrapServers(String bootstrapServers) { this.bootstrapServers = bootstrapServers; } public String getTopic() { return topic; } public void setTopic(String topic) { this.topic = topic; } public int getRetries() { return retries; } public void setRetries(int retries) { this.retries = retries; } public int getBatchSize() { return batchSize; } public void setBatchSize(int batchSize) { this.batchSize = batchSize; } public int getLingerMs() { return lingerMs; } public void setLingerMs(int lingerMs) { this.lingerMs = lingerMs; } public int getBufferMemory() { return bufferMemory; } public void setBufferMemory(int bufferMemory) { this.bufferMemory = bufferMemory; } } 测试 消费者处理实现ConsumerHandlerImpl类 public class ConsumerHandlerImpl implements ConsumerHandler{ /** * 处理收到的消息 * @param topic 收到消息的topic名称 * @param partition 收到消息的partition内容 * @param offset 收到消息在队列中的编号 * @param value 收到的消息 */ public void processObject(String topic,int partition,long offset,String value) { System.out.println(topic+"从kafka接收"+partition+"到"+offset+"的消息是:"+value); } /** * 获取跨步 * @param topic 接受消息的topic * @param partition 接受消息的partition * @return 当前topic,partition下的seek */ public long getSeek(String topic , int partition) { return 1; } } main方法类 public class AppResourceTest{ public static void main(String[] args){ BeanDefinitionRegistry reg=new DefaultListableBeanFactory(); PropertiesBeanDefinitionReader reader=new PropertiesBeanDefinitionReader(reg); reader.loadBeanDefinitions(new ClassPathResource("resources/kafka-consumer.properties")); reader.loadBeanDefinitions(new ClassPathResource("resources/kafka-producer.properties")); BeanFactory factory=(BeanFactory)reg; ConsumerConfig consumerConfig=(ConsumerConfig)factory.getBean("consumerConfig"); System.out.println(consumerConfig.getPollTime()); ProducerConfig producerConfig=(ProducerConfig)factory.getBean("producerConfig"); System.out.println(producerConfig.getBatchSize()); Producer producer = new Producer(producerConfig); producer.sendMessage(producerConfig.getTopic(),"s4335453453454"); producer.close(); System.out.println("consumer"); Consumer consumer = new Consumer(new ConsumerHandlerImpl(),consumerConfig); try{ Thread.currentThread(); Thread.sleep(10000); }catch(Exception e){ e.printStackTrace(); } } } 运行结果

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册