首页
留言板
友链
关于
Search
1
内测“合金弹头”嘿嘿
889 阅读
2
Nginx搭建一个简易的图床
836 阅读
3
Kettle循环遍历结果集作为参数传入转换
816 阅读
4
Apache Dubbo初步认识
437 阅读
5
Maven打包插件与idea
415 阅读
知识库
好奇猫
日常说
笔记本
登录
/
注册
Search
标签搜索
maven
Spring
vue
Java
Java代码
前端
idea
帆软
MySQL
git
CSS
游戏
Bootstrap
生活
网上冲浪
邮件配置
说说
Nginx
Excel
数据库调优
龙流
累计撰写
61
篇文章
累计收到
18
条评论
首页
栏目
知识库
好奇猫
日常说
笔记本
页面
留言板
友链
关于
搜索到
61
篇与
龙流
的结果
2022-03-23
序列化与反序列化
把对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为对象的过程称为对象的反序列化。对象的序列化主要有两种用途:把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;在网络上传送对象的字节序列。使用场景 在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些session先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。 当两个进程在进行远程通信时,当我们需要使用的对象很复杂或者需要很长时间去构造,这时就会引入使用代理模式(Proxy)。例如:如果构建一个对象很耗费时间和计算机资源,代理模式(Proxy)允许我们控制这种情况,直到我们需要使用实际的对象。一个代理(Proxy)通常包含有和将要使用的对象同样的方法,一旦开始使用这个对象,这些方法将通过代理(Proxy)传递给实际的对象。解读:在微服务化盛行的今天,很多复杂的对象构造起来比较耗时,为了节省开支,某些公司将这部分复杂的对象先圈起来,写成服务起在远端B,并在调用端A端以代理(Proxy)的形式提供对服务的访问,这期间从B到A远程调的过程形成了Java对象序列化和反序列化的相关操作!深入理解JDK提供了个代理类:import java.lang.reflect.Proxy; 来看一下Proxy的实现Proxy在JDK中实现了Serializable(序列化)接口,但是代理是怎么实现将服务端的对象运行到客户端上的呢?第一步:远端JVM(服务端)对“对象”使用序列化后通过网络传输的方式将对象的字节序列发送到本地(客户端)第二步:本地代理(Proxy)将接收到的字节序列再通过反序列化恢复成”对象”,并使这个"对象"活在本地的JVM中;从上面两步来看,序列化的过程是在服务端做的;反序列化是在客户端做的;那么有个问题来了,从源码上看,Proxy(本地)实现了反序列化,服务端在哪里实现了序列化呢?带着这个问题,继续查看了服务端所有的代码,发现有的公司直接在实体上Serialize,有的则在类上加@Serializable注解利用切面实现,但终究实现了序列化;JDK类库中的序列化APIjava.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。 只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。对象序列化/** * @ClassName: Student * @author: WeiLong * @description 学生类 */ public class Student implements Serializable{ private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }注意:需要序列化的类需要实现Serializable接口,获取上述其他方法,否则会出现NotSerializableException //实现序列化 public static void SerializeStudent() throws IOException{ //1、序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("java基础\\oos.txt")); //2、创建student对象 Student student = new Student("张三",18); oos.writeObject(student); System.out.println("Student对象序列化成功"); //3、关闭流 oos.close(); }对象反序列化 public static Student DeserializeStudent() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("java基础\\oos.txt")); Student student = (Student) ois.readObject(); System.out.println("Student对象反序列化完成"); ois.close(); return student; }serialVersionUID的作用序列化对象未加serialVersionUID时,反序列化异常serialVersionUID: 字面意思上是序列化的版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量 序列化版本ID的真实用途:当实体中增加属性后,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。在例子中,如果没有指定Person类的serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,添加了一个字段后,由于没有显指定serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个序列化版本号不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法或者属性可以用。可以说serialVersionUID是序列化和反序列化之间彼此认识的唯一信物。IDEA设置自动生成serialVersionUID
2022年03月23日
76 阅读
0 评论
0 点赞
2022-03-21
实际使用数据库建表时varchar类型使用的区别
一直有纠结过一个问题,不知道其他同学有没有,实际开发中数据库字段类型varchar类型是最好用的,不会出现类型不符的异常;管它是int类型还是double、date类型都能当字符占用类型存储。这真的是一个“坏味道”要改一改了:1、从字段类型的执行效率上,int最高,varchar最低。例如状态类型字段,使用char或者varchar是不可取的,int类型更容易建立索引和进行检索,毕竟数字类型是数据库检索的基础,char类型的毕竟需要经过转换,而varchar就更复杂了,其排序不仅需要转换和计算,还需要访问和遵循数据库的排序规则(实际上char也需要排序规则),而消耗的资源也更大。2、占用空间大小不同例如用varchar 来存储年月日,那么需要10个字节,而date类型只需4个字节,而datetime类型也只需要8个字节,都小于varchar类型3、建立索引问题频繁改动的字段类型建议使用varchar。varchar类型的字段用来建立索引容易产生的索引碎片简单理解索引碎片是空间利用率不足SQL索引与碎片=>删除索引并重建这种方式并不好.在删除索引期间,索引不可用.会导致阻塞发生。而对于删除聚集索引,则会导致对应的非聚集索引重建两次(删除时重建,建立时再重建).虽然这种方法并不好,但是对于索引的整理最为有效=>使用DROP_EXISTING语句重建索引为了避免重建两次索引,使用DROP_EXISTING语句重建索引,因为这个语句是原子性的,不会导致非聚集索引重建两次,但同样的,这种方式也会造成阻塞=>如前面文章所示,使用ALTER INDEX REBUILD语句重建索引使用这个语句同样也是重建索引,但是通过动态重建索引而不需要卸载并重建索引.是优于前两种方法的,但依旧会造成阻塞。可以通过ONLINE关键字减少锁,但会造成重建时间加长.
2022年03月21日
113 阅读
0 评论
0 点赞
2022-02-23
实例volatile关键字使用场景 了解volatile关键字作用
volatile用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值。volatile很容易被误用,用来进行原子性操作。如果要深入了解volatile关键字的作用,就必须先来了解一下JVM在运行时候的内存分配过程。在 java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图:以上是JVM在运行时候的内存分配过程以后,我们开始真正深入的讨论volatile的具体作用public class VolatileTest extends Thread { boolean flag = false; int i = 0; public void run() { while (!flag) { i++; } } public static void main(String[] args) throws Exception { VolatileTest vt = new VolatileTest(); vt.start(); Thread.sleep(2000); vt.flag = true; System.out.println("stope" + vt.i); } }上面的代码是通过标记flag来控制VolatileTest线程while循环退出的例子!下面让我用伪代码来描述一下我们的程序首先创建 VolatileTest vt = new VolatileTest();然后启动线程 vt.start();暂停主线程2秒(Main) Thread.sleep(2000);这时的vt线程已经开始执行,进行i++;主线程暂停2秒结束以后将 vt.flag = true;打印语句 System.out.println("stope" + vt.i); 在此同时由于vt.flag被设置为true,所以vt线程在进行下一次while判断 while (!flag) 返回假 结束循环 vt线程方法结束退出!主线程结束上面的叙述看似并没有什么问题,“似乎”完全正确。那就让我们把程序运行起来看看效果吧,执行mian方法。2秒钟以后控制台打印stope-202753974。可是奇怪的事情发生了 程序并没有退出。vt线程仍然在运行,也就是说我们在主线程设置的 vt.flag = true;没有起作用。 说明:有的同学在测试上面代码的时候程序可以正常退出。那是因为你的JVM没有优化造成的。在DOC下面输入 java -version 查看 如果显示Java HotSpot(TM) ... Server 则JVM会进行优化 如果显示Java HotSpot(TM) ... Client 为客户端模式,需要设置成Server模式 设置方法问Google问题出现了,为什么我在主线程(main)中设置了vt.flag = true; 而vt线程在进行判断flag的时候拿到的仍然是false?那么按照我们上面所讲的 “JVM在运行时候的内存分配过程” 就很好解释上面的问题了。 首先 vt线程在运行的时候会把 变量 flag 与 i (代码3,4行)从“主内存” 拷贝到 线程栈内存(上图的线程工作内存) 然后 vt线程开始执行while循环while (!flag) { i++ }while (!flag)进行判断的flag 是在线程工作内存当中获取,而不是从 “主内存”中获取。i++; 将线程内存中的i++; 加完以后将结果写回至 "主内存",如此重复。然后再说说主线程的执行过程。 我只说明关键的地方vt.flag = true;主线程将vt.flag的值同样 从主内存中拷贝到自己的线程工作内存 然后修改flag=true. 然后再将新值回到主内存。这就解释了为什么在主线程(main)中设置了vt.flag = true; 而vt线程在进行判断flag的时候拿到的仍然是false。那就是因为vt线程每次判断flag标记的时候是从它自己的“工作内存中”取值,而并非从主内存中取值!这也是JVM为了提供性能而做的优化。那我们如何能让vt线程每次判断flag的时候都强制它去主内存中取值呢。这就是volatile关键字的作用。再次修改我们的代码public class VolatileTest extends Thread { volatile boolean flag = false; int i = 0; public void run() { while (!flag) { i++; } } public static void main(String[] args) throws Exception { VolatileTest vt = new VolatileTest(); vt.start(); Thread.sleep(2000); vt.flag = true; System.out.println("stope" + vt.i); } }在flag前面加上volatile关键字,强制线程每次读取该值的时候都去“主内存”中取值。在试试我们的程序吧,已经正常退出了。原文出处:https://www.cnblogs.com/xd502djj/p/9873067.html作者:懂俊杰
2022年02月23日
68 阅读
0 评论
0 点赞
2022-01-17
反射动态调用某个类某个方法
简单的通过配置文件加反射的方法执行某方法{collapse}{collapse-item label="普通方法反射调用" open}public static void main(String[] args){ /** * eg:txt配置文件class.txt或properties的配置文件 * className=xxx * methodName=xxx */ Properties prop = new Properties(); FileRead fr = new FileRead("MyProject\\class.txt"); prop.load(fr); fr.close(); String className = prop.getProperty("className"); String methodName = prop.getProperty("methodName"); //通过反射来使用 Class<?> c = Class.forName(className); Constructor<?> con = c.getConstructor(); Object obj = con.newInstance(); Method m = c.getMethod(methodName); m.invoke(obj); }{/collapse-item}{collapse-item label="折叠标题二"} 折叠内容二{/collapse-item}{/collapse}
2022年01月17日
94 阅读
0 评论
0 点赞
2021-12-14
Apache Dubbo初步认识
Dubbo简介 Apache Double是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。 什么是RPC? RPC全称为remote procedure call,即**远程过程调用**。比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用 想调用B服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。 需要注意的是RPC并不是一个具体的技术,而是指整个网络远程调用过程。 RPC是一个泛化的概念,严格来说一切远程过程调用手段都属于RPC范畴。各种开发语言都有自己的RPC框架。 Java中的RPC框架比较多,广泛使用的有RMI、Hessian、Dubbo等。 Dubbo官网地址:http://dubbo.apache.org Dubbo提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。Dubbo架构图节点角色说明:节点角色名称Provider暴露服务的服务提供方Consumer调用远程服务的服务消费方Registry服务注册与发现的注册中心Monitor统计服务的调用次数和调用时间的监控中心Container服务运行容器虚线都是异步访问,实线都是同步访问蓝色虚线:在启动时完成的功能红色虚线(实线)都是程序运行过程中执行的功能服务注册中心Zookeeper通过前面的Dubbo架构图可以看到,Registry(服务注册中心)在其中起着至关重要的作用。Dubbo官方推荐使用Zookeeper作为服务注册中心。Zookeeper介绍 Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。Zookeeper树型目录服务:流程说明:服务提供者(Provider)启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址服务消费者(Consumer)启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址,并向 `/dubbo/com.foo.BarService/consumers` 目录下写入自己的 URL 地址监控中心(Monitor)启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址安装Zookeeper下载地址:http://archive.apache.org/dist/zookeeper/ 安装步骤: 第一步:安装 jdk(略) 第二步:把 zookeeper 的压缩包(zookeeper-3.4.6.tar.gz)上传到 linux 系统 第三步:解压缩压缩包 tar -zxvf zookeeper-3.4.6.tar.gz 第四步:进入zookeeper-3.4.6目录,创建data目录 mkdir data 第五步:进入conf目录 ,把zoo_sample.cfg 改名为zoo.cfg cd conf mv zoo_sample.cfg zoo.cfg 第六步:打开zoo.cfg文件, 修改data属性:dataDir=/root/zookeeper-3.4.6/data启动、停止Zookeeper进入Zookeeper的bin目录,启动服务命令 ./zkServer.sh start 停止服务命令 ./zkServer.sh stop 查看服务状态: ./zkServer.sh statusDubbo快速入门Dubbo作为一个RPC框架,其最核心的功能就是要实现跨网络的远程调用。实例创建两个应用,一个作为服务的提供方,一个作为服务的消费方。通过Dubbo来实现服务消费方远程调用服务提供方的方法。服务提供方开发{collapse}{collapse-item label="(1)创建maven工程(打包方式为war)dubbodemo_provider,在pom.xml文件中导入如下坐标"}<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- dubbo相关 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.7</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <!-- 指定端口 --> <port>8081</port> <!-- 请求路径 --> <path>/</path> </configuration> </plugin> </plugins> </build>{/collapse-item}{collapse-item label="(2)配置web.xml文件"}<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>{/collapse-item}{collapse-item label="(3)创建服务接口"}package com.lwlong.service; public interface HelloService { public String sayHello(String name); }{/collapse-item}{collapse-item label="(4)创建服务实现类"}package com.lwlong.service.impl; import com.alibaba.dubbo.config.annotation.Service; import com.lwlong.service.HelloService; @Service public class HelloServiceImpl implements HelloService { public String sayHello(String name) { return "hello " + name; } } //注意:服务实现类上使用的Service注解是Dubbo提供的,用于对外发布服务{/collapse-item}{collapse-item label="(5)在src/main/resources下创建applicationContext-service.xml "}<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 --> <dubbo:application name="dubbodemo_provider" /> <!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址--> <dubbo:registry address="zookeeper://192.168.134.129:2181"/> <!-- 注册 协议和port 端口默认是20880 --> <dubbo:protocol name="dubbo" port="20881"></dubbo:protocol> <!-- 扫描指定包,加入@Service注解的类会被发布为服务 --> <dubbo:annotation package="com.lwlong.service.impl" /> </beans>{/collapse-item}{/collapse}(6)启动服务 tomcat7:run服务消费方开发 (1)创建maven工程(打包方式为war)dubbodemo_consumer,pom.xml配置和上面服务提供者相同,只需要将Tomcat插件的端口号改为8082即可{collapse}{collapse-item label="(2)配置web.xml文件"}<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-web.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>{/collapse-item}{/collapse} (3)将服务提供者工程中的HelloService接口复制到当前工程{collapse}{collapse-item label="(4)编写Controller"}package com.lwlong.controller; import com.alibaba.dubbo.config.annotation.Reference; import com.lwlong.service.HelloService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/demo") public class HelloController { @Reference private HelloService helloService; @RequestMapping("/hello") @ResponseBody public String getName(String name){ //远程调用 String result = helloService.sayHello(name); System.out.println(result); return result; } } //注意:Controller中注入HelloService使用的是Dubbo提供的@Reference注解{/collapse-item}{collapse-item label="(5)在src/main/resources下创建applicationContext-web.xml"}<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 --> <dubbo:application name="dubbodemo-consumer" /> <!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址--> <dubbo:registry address="zookeeper://192.168.134.129:2181"/> <!-- 扫描的方式暴露接口 --> <dubbo:annotation package="com.lwlong.controller" /> </beans>{/collapse-item}{/collapse}(6)运行测试 tomcat7:run启动 在浏览器输入http://localhost:8082/demo/hello.do?name=Jack,查看浏览器输出结果思考一:上面的Dubbo入门案例中我们是将HelloService接口从服务提供者工程(dubbodemo_provider)复制到服务消费者工程(dubbodemo_consumer)中,这种做法是否合适?还有没有更好的方式?答:这种做法显然是不好的,同一个接口被复制了两份,不利于后期维护。更好的方式是单独创建一个maven工程,将此接口创建在这个maven工程中。需要依赖此接口的工程只需要在自己工程的pom.xml文件中引入maven坐标即可。思考二:在服务消费者工程(dubbodemo_consumer)中只是引用了HelloService接口,并没有提供实现类,Dubbo是如何做到远程调用的?答:Dubbo底层是基于代理技术为HelloService接口创建代理对象,远程调用是通过此代理对象完成的。可以通过开发工具的debug功能查看此代理对象的内部结构。另外,Dubbo实现网络传输底层是基于Netty框架完成的。思考三:上面的Dubbo入门案例中我们使用Zookeeper作为服务注册中心,服务提供者需要将自己的服务信息注册到Zookeeper,服务消费者需要从Zookeeper订阅自己所需要的服务,此时Zookeeper服务就变得非常重要了,那如何防止Zookeeper单点故障呢?答:Zookeeper其实是支持集群模式的,可以配置Zookeeper集群来达到Zookeeper服务的高可用,防止出现单点故障。Dubbo相关配置说明 **包扫描** <dubbo:annotation package="com.lwlong.service" /> 服务提供者和服务消费者都需要配置,表示包扫描,作用是扫描指定包(包括子包)下的类。 如果不使用包扫描,也可以通过如下配置的方式来发布服务: <bean id="helloService" class="com.lwlong.service.impl.HelloServiceImpl" /> <dubbo:service interface="com.lwlong.api.HelloService" ref="helloService" /> 作为服务消费者,可以通过如下配置来引用服务: <!-- 生成远程服务代理,可以和本地bean一样使用helloService --> <dubbo:reference id="helloService" interface="com.lwlong.api.HelloService" /> 上面这种方式发布和引用服务,一个配置项(<dubbo:service>、<dubbo:reference>)只能发布或者引用一个服务, 如果有多个服务,这种方式就比较繁琐了。推荐使用包扫描方式。 **协议** <dubbo:protocol name="dubbo" port="20880"/> 一般在服务提供者一方配置,可以指定使用的协议名称和端口号。 其中Dubbo支持的协议有:dubbo、rmi、hessian、http、webservice、rest、redis等。 推荐使用的是dubbo协议。 dubbo 协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于 服务提供者机器数的情况。不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。 也可以在同一个工程中配置多个协议,不同服务可以使用不同的协议,例如: <!-- 多协议配置 --> <dubbo:protocol name="dubbo" port="20880" /> <dubbo:protocol name="rmi" port="1099" /> <!-- 使用dubbo协议暴露服务 --> <dubbo:service interface="com.lwlong.api.HelloService" ref="helloService" protocol="dubbo" /> <!-- 使用rmi协议暴露服务 --> <dubbo:service interface="com.lwlong.api.DemoService" ref="demoService" protocol="rmi" /> **启动时检查** <dubbo:consumer check="false"/> 上面这个配置需要配置在服务消费者一方,如果不配置默认check值为true。Dubbo 缺省会在启动时检查依赖的服务 是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题。 可以通过将check值改为false来关闭检查。建议在开发阶段将check值设置为false,在生产环境下改为true。 **负载均衡** 负载均衡(Load Balance):其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任务。 在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性Hash),缺省为random随机调用。 配置负载均衡策略,既可以在服务提供者一方配置,也可以在服务消费者一方配置,如下: @Controller @RequestMapping("/demo") public class HelloController { //在服务消费者一方配置负载均衡策略 @Reference(check = false,loadbalance = "random") private HelloService helloService; @RequestMapping("/hello") @ResponseBody public String getName(String name){ //远程调用 String result = helloService.sayHello(name); System.out.println(result); return result; } } //在服务提供者一方配置负载均衡 @Service(loadbalance = "random") public class HelloServiceImpl implements HelloService { public String sayHello(String name) { return "hello " + name; } } /** 可以通过启动多个服务提供者来观察Dubbo负载均衡效果。 注意:因为我们是在一台机器上启动多个服务提供者,所以需要修改tomcat的端口号和Dubbo服务的端口号来防止端口冲突。 在实际生产环境中,多个服务提供者是分别部署在不同的机器上,所以不存在端口冲突问题。 */
2021年12月14日
437 阅读
0 评论
0 点赞
2021-12-09
node.js安装 简介 使用
Node.js安装1、下载地址:https://nodejs.org/en/download/ 下载你系统对于的安装包(.msi文件可执行安装程序包) 2、以.msi安装程序包为例:下载完成后双击运行,一直下一步选择安装目录即可。 3、环境配置:这里的环境配置主要配置的是npm安装的全局模块所在的路径,也可以不配置即使用默认配置路径默认在C盘 我希望将全模块所在路径和缓存路径放在我node.js安装的文件夹中,则在我安装的文件夹【D:\Develop\nodejs】下创建两个文件夹【node_global】及【node_cache】 创建完两个空文件夹之后,打开cmd命令窗口,输入 npm config set prefix "D:\Develop\nodejs\node_global" npm config set cache "D:\Develop\nodejs\node_cache" 接下来设置环境变量,关闭cmd窗口,“我的电脑”-右键-“属性”-“高级系统设置”-“高级”-“环境变量” 进入环境变量对话框,在【系统变量】下新建【NODE_PATH】,输入【D:\Develop\nodejs\node_global\node_modules】,将【用户变量】下的【Path】修改为【D:\Develop\nodejs\node_global】 4、测试: node -v 查看node版本 npm -v 查看npm版本 安装个module测试下,我们就安装最常用的express模块 npm install express -g # -g是全局安装的意思Node.js简介Node.js 是一个开源和跨平台的 JavaScript 运行时环境。 它几乎是任何类型项目的流行工具!Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)。 这使得 Node.js 的性能非常好。npm 以其简单的结构帮助 Node.js 生态系统蓬勃发展,现在 npm 仓库托管了超过 1,000,000 个开源包,你可以自由使用。更多详细了解请移步文档说明Node.js使用运行 Node.js 程序的常规方法是,运行全局可用的 node 命令(已安装 Node.js)并传入要执行的文件的名称。 如何从 Node.js 程序退出:1、当在控制台中运行程序时,可以使用 ctrl C 将其关闭 2、使用process.exit() 进程会被立即强制终止 3、也可以设置process.exitCode = 1 当进程完成所有处理后,程序会正常地退出。
2021年12月09日
160 阅读
0 评论
0 点赞
2021-11-25
git安装详细介绍(不要再按有些教程说的只管点下一步,咱们要知其然并知其所以然)
git详细安装过程,操作解释git下载官网地址: https://git-scm.com/安装双击exe安装包1、软件说明2、设置安装路径3、设置一下插件配置4、自定义应用名称5、Git的默认编辑器,建议选默认的Vim编辑器,直接下一步6、这个界面是调整您的PATH环境。 第一种配置是“仅从Git Bash使用Git”。这是最安全的选择,因为您的PATH根本不会被修改。您只能使用 Git Bash 的 Git 命令行工具。但是这将不能通过第三方软件使用。 第二种配置是“从命令行以及第三方软件进行Git”。该选项被认为是安全的,因为它仅向PATH添加了一些最小的Git包装器,以避免使用可选的Unix工具造成环境混乱。您将能够从Git Bash,命令提示符和Windows PowerShell以及在PATH中寻找Git的任何第三方软件中使用Git。这也是推荐的选项。 第三种配置是“从命令提示符使用Git和可选的Unix工具”。警告:这将覆盖Windows工具,如 “ find 和 sort ”。只有在了解其含义后才使用此选项。 推荐的选项第二种配置,点击“Next”按钮继续到下图的界面:7、选择Https后端传输 第一个选项是“使用 OpenSSL 库”。服务器证书将使用ca-bundle.crt文件进行验证。这也是我们常用的选项。 第二个选项是“使用本地 Windows 安全通道库”。服务器证书将使用Windows证书存储验证。此选项还允许您使用公司的内部根CA证书,例如通过Active Directory Domain Services 。 我使用默认选项第一项,点击“Next”按钮继续到下图的界面:8、配置尾行符合转换这个界面是配置行尾符号转换。 第一个选项是“签出Windows风格,提交Unix风格的行尾”。签出文本文件时,Git会将LF转换为CRLF。提交文本文件时,CRLF将转换为LF。对于跨平台项目,这是Windows上的推荐设置(“ core.autocrlf”设置为“ true”) 第二个选项是“按原样签出,提交Unix样式的行尾”。签出文本文件时,Git不会执行任何转换。 提交文本文件时,CRLF将转换为LF。对于跨平台项目,这是Unix上的建议设置(“ core.autocrlf”设置为“ input”) 第三种选项是“按原样签出,按原样提交”。当签出或提交文本文件时,Git不会执行任何转换。不建议跨平台项目选择此选项(“ core.autocrlf”设置为“ false”) 我选择第一种选项,点击“Next”按钮继续到下图的界面:9、配置终端模拟器以与Git Bash一起使用这个界面是配置终端模拟器以与Git Bash一起使用。 第一个选项是“使用MinTTY(MSYS2的默认终端)”。Git Bash将使用MinTTY作为终端模拟器,该模拟器具有可调整大小的窗口,非矩形选择和Unicode字体。Windows控制台程序(例如交互式Python)必须通过“ winpty”启动才能在MinTTY中运行。 第二个选项是“使用Windows的默认控制台窗口”。Git将使用Windows的默认控制台窗口(“cmd.exe”),该窗口可以与Win32控制台程序(如交互式Python或node.js)一起使用,但默认的回滚非常有限,需要配置为使用unicode 字体以正确显示非ASCII字符,并且在Windows 10之前,其窗口不能自由调整大小,并且只允许矩形文本选择。 我选择默认的第一种选项,点击“Next”按钮继续到下图的界面:10、配置额外的选项这个界面是配置配置额外的选项。 第一个选项是“启用文件系统缓存”。文件系统数据将被批量读取并缓存在内存中用于某些操作(“core.fscache”设置为“true”)。 这提供了显著的性能提升。 第二个选项是“启用Git凭证管理器”。Windows的Git凭证管理器为Windows提供安全的Git凭证存储,最显着的是对Visual Studio Team Services和GitHub的多因素身份验证支持。 (需要.NET Framework v4.5.1或更高版本) 第三个选项是“启用符号链接”。启用符号链接(需要SeCreateSymbolicLink权限)。请注意,现有存储库不受此设置的影响。 我勾选默认的第一、第二选项,点击“Install”11、安装完成12、启动测试到此,Git的安装完成,可以在开始菜单中看到Git的三个启动图标(Git Bash、Git CMD(Deprecated)、Git GUI)。 Git Bash,是Git配套的一个控制台 Git CMD(Deprecated),是通过CMD使用Git(不推荐使用) Git GUI,是Git的可视化操作工具
2021年11月25日
367 阅读
0 评论
0 点赞
2021-11-11
Maven3.3.9的安装与配置
安装下载地址:http://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/首先Maven安装简单三步:下载、解压、配置环境变量 解压到全英文路径下 解压后配置MAVEN_HOME环境变量 右键计算机–>属性–>高级系统设置–>环境变量 变量名填入:MAVEN_HOME 变量值填入:Maven解压的路径,我这里是D:\Program Files\apache-maven-3.3.9 点击确定 找到Path(这里不区分大小写),编辑它 点击新建–>填入%MAVEN_HOME%\bin -->确定 验证: WIN + R, 输入cmd 输入mvn -v 输出Apach Maven 3.3.9字样说明安装配置成功配置settings.xml配置settings文件,找到maven安装目录下的config,打开settings文件'找到<localRepository>标签,配置默认仓库指定目录' '<localRepository>D:/Program Files/DevApps/apache-maven-3.3.9/repository</localRepository>' 配置阿里云镜像,找到标签 <!--阿里源--> ~~ <mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror>~~ 已不能使用 <mirror> <id>mirrorId</id> <mirrorOf>repositoryId</mirrorOf> <name>Human Readable Name for this Mirror.</name> <url>http://my.repository.com/repo/path</url> </mirror>选配JDK版本,找到标签 <!--配置JDK--> <profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>idea中使用Maven点击File -> Settings
2021年11月11日
415 阅读
0 评论
0 点赞
2021-11-10
Maven打包插件与idea
日常开发一个小项目或在企业中开发项目时,Maven管理项目是很好的一个选择; 项目所需的依赖包,项目的打包安装,都很方便也提高了开发人员操作效率。 然它也会带来使用上的成本,所以对于需要使用的功能进行一个记录,方便下次更方便的使用。Maven插件:打包第三方jar包 <!-- spring-boot-maven-plugin (提供了直接运行项目的插件:如果是通过parent方式继承spring-boot-starter-parent则不用此插件) --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <executable>true</executable> <includeSystemScope>true</includeSystemScope><!--引入第三方jar包--> </configuration> <executions> <execution> <goals> <goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中--> </goals> </execution> </executions> </plugin>Maven安装请参考
2021年11月10日
415 阅读
0 评论
0 点赞
2021-10-18
Java关于文件和目录的操作
{collapse}{collapse-item label="判断文件大小是否变化" open} 通过持续判断文件大大小有没有变化,在网络传输过程中,稳定的传输文件大小肯定会不断变大;当文件一段时间文件大小不变,不考虑其他情况(如断网),说明文件传输完成注意点:1、等待文件(非目录)读写完毕,费时的操作,不要放在主线程2、判断文件长度的方法不适用于粘贴复制操作的判断,粘贴复制一般file.length()时固定的不会有写入写出(test)public static boolean checkFileWritingOn(String fileName) throws Exception{ long oldLen = 0; long newLen = 0; File file = new File(fileName); while(true){ newLen = file.length(); if ((newLen - oldLen) > 0) { oldLen = newLen; System.out.println(file.length()); Thread.sleep(10000); } else { System.out.println("done"); return true; } } }{/collapse-item}{collapse-item label="获取文件创建时间、最后更新时间等" open} /** * 获取文件的创建时间 * @param file * @return */ public static Date getCreationTime(File file) throws IOException { if (file == null) { return null; }else { Path path = file.toPath(); BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class); // 创建时间 Instant instant = attr.creationTime().toInstant(); Date fordate = Date.from(instant); return fordate; } // 更新时间 //Instant instant = attr.lastModifiedTime().toInstant(); // 上次访问时间 //Instant instant = attr.lastAccessTime().toInstant(); //String format = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneId.systemDefault()).format(instant); //return format; }{/collapse-item}{collapse-item label="获取某路径下的所有文件/文件夹" open} /** * 获取路径下的所有文件/文件夹 * @param rootDir 需要遍历的文件夹路径 * @param isAddDirectory 是否将子文件夹的路径也添加到list集合中 * @return */ public static List<String> getAllFile(String rootDir, boolean isAddDirectory){ List<String> list = new ArrayList<String>(); File baseFile = new File(rootDir); if (baseFile.isFile() || !baseFile.exists()) { return list; } File[] files = baseFile.listFiles(); for (File file : files) { if (file.isDirectory()) { if(isAddDirectory){ list.add(file.getAbsolutePath()); } list.addAll(getAllFile(file.getAbsolutePath(),isAddDirectory)); } else { list.add(file.getAbsolutePath()); } } return list; }{/collapse-item}{collapse-item label="复制文件到指定目录" open} /** * @param filePath * @param targetPath * @throws IOException */ public static void fileCope(String filePath, String targetPath) throws IOException { //获得流 FileInputStream fileInputStream = new FileInputStream(filePath); File targetFile = new File(targetPath); //获取父目录 File parentFile = targetFile.getParentFile(); //判断是否存在 if (!parentFile.exists()) { // 创建父目录文件夹 parentFile.mkdirs(); } //判断文件是否存在 if (!targetFile.exists()) { //创建文件 targetFile.createNewFile(); } //新文件输出流 FileOutputStream fileOutputStream = new FileOutputStream (targetFile); byte[] buffer= new byte[1024]; int len; //将文件流信息读取文件缓存区,如果读取结果不为-1就代表文件没有读取完毕,反之已经读取完毕 while ((len=fileInputStream.read(buffer))!=-1) { fileOutputStream.write(buffer, 0, len); fileOutputStream.flush(); } fileInputStream.close(); fileOutputStream.close(); }{/collapse-item}{/collapse}
2021年10月18日
161 阅读
0 评论
0 点赞
1
...
3
4
5
...
7