0%

源码:https://github.com/xuanfong1/DubboLearning

  1. 新建目录 mkdir DubboLearning,然后cd Dubbolearning进去之后执行gradle init初始化gradle项目

  2. 新建三个子项目目录mkdir library,provider,consumer 分别为公共依赖项目、提供者、消费者

  3. 复制build.gradle到三个子项目目录

  4. 分别为三个子项目创建目录mkdir -p src/main/java,src/test/java,src/main/resources

  5. 修改顶级项目目录的setting.gradle添加三个子项目

    1
    2
    3
    include 'library'
    inclede 'provider'
    inclede 'consumer'
  6. 复制项目helloworld的源码到项目目录

  7. 然后修改顶级项目目录build.gradle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    plugins {
    id "org.springframework.boot" version "2.0.1.RELEASE"
    }
    allprojects {
    repositories {
    jcenter() //将jcenter仓库配置到所有项目
    }
    }
    subprojects {
    version = '1.0' //设置版本号
    }
    configure(subprojects.findAll {it.name == 'provider' || it.name == 'consumer'} ) {

    apply plugin: 'java'
    apply plugin: 'eclipse'
    apply plugin: "org.springframework.boot"
    apply plugin: 'io.spring.dependency-management'

    group = 'exxk.dubbo'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = 1.8

    dependencies {
    compile('org.springframework.boot:spring-boot-starter')
    compile group: 'com.alibaba', name: 'dubbo', version: '2.6.1'
    testCompile('org.springframework.boot:spring-boot-starter-test')
    compile project(':library')
    }
    }

额外

https://plugins.gradle.org/plugin/org.springframework.boot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//低版本,动态
buildscript {
ext {
springBootVersion = '2.0.1.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
//等效于
//高版本
plugins {
id "org.springframework.boot" version "2.0.2.RELEASE"
}

报错:

1
2
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/curator/RetryPolicy
at com.alibaba.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter.connect(CuratorZookeeperTransporter.java:26)

解决:添加依赖compile group: 'org.apache.curator', name: 'curator-framework', version: '4.0.1'

gradle init --type <name>其中name可选

  • java-application
  • java-library
  • scala-library
  • groovy-library
  • basic

build java-library

This guide walks you through the process of using Gradle’s Build Init plugin to produce a JVM library which is suitable for consumption by other JVM libraries and applications.

本指南引导您完成使用Gradle的Build Init插件生成适合其他JVM库和应用程序使用的JVM库的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir demo-java-lib #创建项目目录
cd demo-java-lib
gradle init --type java-library #初始化构建为java-library
tree #查看生成的目录树
├── build.gradle
├── gradle
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main #java资源为件
│   └── java
│   └── Library.java
└── test #java测试文件
└── java
└── LibraryTest.java

build.gradle解读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
plugins {
// Java Library依赖插件
id 'java-library'
}
dependencies {
// 依赖该api
api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:23.0'
testImplementation 'junit:junit:4.12'
}
repositories {
// 仓库
jcenter()
}

执行./gradew build第一次构建会下载依赖jar包比较慢,下载到目录~/.gradle/wrapper/dists,编译完成后生成

  • build/reports/tests/test/index.html 测试报告
  • build/libs/building-java-libraries.jar 编译生成的jar

jar tf build/libs/building-java-libraries.jar命令查看jar包内容,其中-f指定jar文件名,-t列出包的内容

修改build.gradle文件在文件里添加版本好version = '0.1.0',结果会修改打包的名称为build/libs/demo-java-lib-0.1.0.jar

修改build.gradle文件在文件里添加jar task任务

1
2
3
4
5
6
jar {
manifest {
attributes('Implementation-Title': project.name,
'Implementation-Version': project.version)
}
}

会修改build/libs/building-java-libraries-0.1.0.jar/META-INF/MANIFEST.MFjar包文件的内容为

1
2
3
Manifest-Version: 1.0
Implementation-Title: demo-java-lib
Implementation-Version: 0.1.0

java-library内置支持javadoc,执行./gradlew javadoc会生成/build/docs/javadoc/index.html文档

build java-application

java项目和library项目一样,只是多了tasks任务 run

多项目构建

初始化顶级项目
  1. 项目初始化

    1
    2
    3
    mkdir multi-project
    cd multi-project
    gradle init
  2. 顶级构建,也就是采用跟项目的配置,从而减少子项目的重复配置,可以把子项目的公共配置抽离到跟项目配置里。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //跟项目build.gradle添加
    allprojects {
    repositories {
    jcenter() //将jcenter仓库配置到所有项目
    }
    }
    subprojects {
    version = '1.0' //设置版本号
    }
添加Groovy library子项目
  1. 执行mkdir multi-library创建一个子项目名为multi-library

  2. 进入multi-library子项目根目录,新建一个build.gradle

    1
    2
    3
    4
    5
    6
    7
    8
    //multi-library/build.gradle
    apply plugin : 'groovy'
    dependencies {
    compile 'org.codehaus.groovy:groovy:2.4.10'
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
    exclude module : 'groovy-all'
    }
    }
  3. 修改顶级项目根项目的settings.gradle,添加include 'multi-library'

  4. 完善子项目,创建两个目录mkdir -p multi-library/src/main/groovy/greetermkdir -p multi-library/src/test/groovy/greeter

  5. 在目录src/main/groovy/greeter新建GreetingFormatter.groovy文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //multi-library/src/main/groovy/greeter/GreetingFormatter.groovy
    package greeter
    import groovy.transform.CompileStatic
    @CompileStatic
    class GreetingFormatter {
    static String greeting(final String name) {
    "Hello, ${name.capitalize()}"
    }
    }
  6. 在目录src/test/groovy/greeter新建GreetingFormatterSpec.groovy文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //multi-library/src/test/groovy/greeter/GreetingFormatterSpec.groovy
    package greeter
    import spock.lang.Specification
    class GreetingFormatterSpec extends Specification {
    def 'Creating a greeting'() {
    expect: 'The greeting to be correctly capitalized'
    GreetingFormatter.greeting('gradlephant') == 'Hello, Gradlephant'

    }
    }
  7. 最后在顶级项目的根目录运行./gradlew build,到此一个项目依赖一个子项目就完成了

添加一个java 子项目
  1. 执行mkdir java-demo创建一个子项目名为java-demo

  2. 进入java-demo子项目根目录,新建一个build.gradle

    1
    2
    apply plugin : 'java' 
    apply plugin : 'application'
  3. 完善子项目,创建目录mkdir -p java-demo/src/main/java/greeter

  4. 修改顶级项目根项目的settings.gradle,添加include 'java-demo'

  5. 在目录java-demo/src/main/java/greeter新建Greeter.java文件

    1
    2
    3
    4
    5
    6
    7
    8
    package greeter;

    public class Greeter {
    public static void main(String[] args) {
    final String output = GreetingFormatter.greeting(args[0]);
    System.out.println(output);
    }
    }
  6. 进入java-demo子项目根目录,修改build.gradle

    1
    2
    3
    apply plugin : 'java' 
    apply plugin : 'application'
    mainClassName = 'greeter.Greeter'
  7. 最后在顶级项目的根目录运行./gradlew build,会出现依赖错误

    1
    2
    3
    * What went wrong:
    Execution failed for task ':java-demo:compileJava'.
    > Compilation failed; see the compiler error output for details.
  8. 解决,进入java-demo子项目根目录,修改build.gradle

    1
    2
    3
    4
    5
    6
    apply plugin : 'java' 
    apply plugin : 'application'
    mainClassName = 'greeter.Greeter'
    dependencies {
    compile project(':multi-library')
    }
  9. 重新执行./gradlew build,编译成功

  10. 添加test测试编译,进入java-demo子项目根目录,修改build.gradle

1
2
3
4
5
6
7
8
9
10
apply plugin : 'java' 
apply plugin : 'application'
apply plugin : 'groovy'
mainClassName = 'greeter.Greeter'
dependencies {
compile project(':multi-library')
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
exclude module : 'groovy-all'
}
}
  1. 创建测试目录mkdir -p java-demo/src/test/groovy/greeter,添加GreeterSpec.groovy文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //java-demo/src/test/groovy/greeter/GreeterSpec.groovy
    package greeter

    import spock.lang.Specification

    class GreeterSpec extends Specification {

    def 'Calling the entry point'() {

    setup: 'Re-route standard out'
    def buf = new ByteArrayOutputStream(1024)
    System.out = new PrintStream(buf)

    when: 'The entrypoint is executed'
    Greeter.main('gradlephant')

    then: 'The correct greeting is output'
    buf.toString() == "Hello, Gradlephant\n".denormalize()
    }
    }
  2. 单项目编译,执行./gradlew :java-demo:test 其中java-demo为项目名,test为那种编译类型,也可以执行去子项目跟目录执行../gradlew test进行单模块编译

添加文档子项目
  1. 在顶级项目的build.gradle添加插件asciidoctor该插件的作用主要是将文档生成网页文件

    1
    2
    3
    4
    plugins {
    //apply false将插件添加到整个项目中,但不会将其添加到根项目中。
    id 'org.asciidoctor.convert' version '1.5.6' apply false //文档插件
    }
  2. 创建文档项目目录,在顶级项目跟目录,执行mkdir docs

  3. 然后在docs目录新建个build.gradle,在里头添加如下内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    apply plugin : 'org.asciidoctor.convert'  //将插件用于该子项目
    //asciidoctor任务
    asciidoctor {
    sources {
    include 'greeter.adoc' //文档资源文件,需要自己新建
    }
    }
    //将asciidoctor任务添加到构建生命周期中,以便如果为顶级项目执行构建,则也将构建文档。
    build.dependsOn 'asciidoctor'
  4. 修改顶级项目根项目的settings.gradle,添加include 'docs'

  5. 然后新建个文档docs/src/docs/asciidoc/greeter.adoc,没有该目录创建就行,内容随便,后面会把此文件文档转为网页文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    = Greeter Command-line Application

    A simple application demonstrating the flexibility of a Gradle multi-project.

    == Installation

    Unpack the ZIP or TAR file in a suitable location

    == Usage

    [listing]
    ----
    $ cd greeter-1.0
    $ ./bin/greeter gradlephant

    Hello, Gradlephant
    ----
  6. 然后在顶级项目跟目录,运行task任务asciidoctor,执行./gradlew asciidoctor

  7. 会在目录docs/build/asciidoc/html5目录生成网页文件greeter.html

将文档包含到发布的项目
  1. 要将文档包含到发布的项目的目录可以新建task任务即可,修改java-demo项目的配置文件build.gradle增加如下内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    distZip {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
    distTar {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
  2. 然后重新编译文件即可,在顶级项目跟目录执行./gradlew build

  3. 最后会在java-demo//build/distributions目录生成两个greeter-1.0.zipgreeter-1.0.tar,里面包含了编译好了的网页文件

整理顶级构建脚本

在java-demo和muilt-library项目中有相同的配置,这里把他们抽到顶级项目里配置

  1. 在顶级项目的build.gradle里添加公共配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    configure(subprojects.findAll {it.name == 'java-demo' || it.name == 'multi-library'} ) { //指定配置那些项目

    apply plugin : 'groovy'
    dependencies {
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
    exclude module : 'groovy-all'
    }
    }
    }
  2. 删除子项目公有的配置,最终所有build.gradle配置如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    //顶级项目build.gradle
    plugins {
    //apply false将插件添加到整个项目中,但不会将其添加到根项目中。
    id 'org.asciidoctor.convert' version '1.5.6' apply false //文档插件
    }
    allprojects {
    repositories {
    jcenter() //将jcenter仓库配置到所有项目
    }
    }
    subprojects {
    version = '1.0' //设置版本号
    }
    configure(subprojects.findAll {it.name == 'java-demo' || it.name == 'multi-library'} ) {

    apply plugin : 'groovy'

    dependencies {
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4', {
    exclude module : 'groovy-all'
    }
    }
    }
    //----------------------------------------------------------
    //multi-library项目build.gradle
    dependencies {
    compile 'org.codehaus.groovy:groovy:2.4.10'
    }
    //-----------------------------------------------------------
    //java-demo项目build.gradle
    apply plugin : 'java'
    apply plugin : 'application'
    mainClassName = 'greeter.Greeter'

    dependencies {
    compile project(':multi-library')
    }

    distZip {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
    distTar {
    from project(':docs').asciidoctor, {
    into "${project.name}-${version}"
    }
    }
  3. 最后执行./gradlew clean build重新构建

总结

  1. 子项目只需build.gradle配置即可,且子项目不能gradle init

  2. 要父项目包含子项目,需要在setting.gradle设置include '项目名'

  3. 子项目依赖其他子项目只需要设置compile project(':子项目名')

  4. 插件需要在最顶部定义

  5. 运行单模块执行./gradlew :子项目名:构建命令构建命令目前包括test、build、clean

  6. 抽离子项目共有配置到父项目用configure

  7. 常用命令

    1
    gradle :eurekaserver:build //执行子项目eurekaserver构建build命令

安装Gradle

  1. java环境必须
  2. 下载Gradle,其中binary-only为单独的安装包,complete为文档加安装包,然后解压
  3. 在path中添加系统环境变量F:\xuan\gradle-4.7\bin
  4. 执行gradle -v检查是否安装成功

使用Gradle

  1. 进入一个Gradle项目,或者拉取一个 git clone git@github.com:gradle/gradle-build-scan-quickstart.git

Gradle build scans使用

Build Scans是用于开发和维护Gradle构建的重要工具。它为你提供了构建的详细信息,并为你识别构建环境、依赖或性能上存在的问题,同时可以帮你更全面地理解并提升构建过程,也便于与他人的合作。

大概理解就是该插件能把构建过程的数据分享出去,方便让别人查看分析构建信息。

  1. 进入项目跟目录执行构建扫描命令./gradlew build --scan,有可能会提示Do you accept these terms?是否接受许可协议,输入yes即可,成功后日志会输出一个链接类似https://scans.gradle.com/s/z5i6rmnpd4sbu,访问该链接就可以查看构建日志信息了(有的打开也许需要邮箱)。

  2. 上面虽然得到了链接,但是可以直接在build.gradle添加相关配置信息,构建扫描插件build-scan,为了将构建扫码发布到https://gradle.com/terms-of-service需要接受协议

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    plugins {
    id 'com.gradle.build-scan' version '1.13.2' //如果是低版本一定要放到其他插件前面
    }
    //配置扫描发送地址,以及同意协议
    buildScan {
    termsOfServiceUrl = 'https://gradle.com/terms-of-service'
    termsOfServiceAgree = 'yes' //同意协议
    tag 'xuan test' //打标签
    //项目的地址,这里需要是http地址,用git开头的地址编译报错
    link 'GitHub','https://github.com/gradle/gradle-build-scan-quickstart'
    }
  3. 执行gradle build -Dscan运行得到链接,然后访问即可

Creating New Gradle Builds

初始化gradle 项目
1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir gradle-demo #创建项目目录
cd gradle-demo #进入项目目录
gradle init #初始化为gradle项目
#生成如下目录文件
.
├── build.gradle #项目配置脚本
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar #wrapper可执行jar
│ └── gradle-wrapper.properties #wrapper 配置文件
├── gradlew # unix systems(linux)系统下的脚本
├── gradlew.bat # window 下的脚本
└── settings.gradle #配置那些项目参与构建脚本
创建task任务名叫copy
1
2
3
4
task copy(type: Copy, group: "Custom", description: "复制src目录到dest目录") {
from "src" //前提需要有src目录
into "dest" //不需要创建,会自动创建
}

命令行执行./gradlew copy代表执行task里的copy任务

Gradle 应用插件

插件仓库

这里以base插件,base插件功能主要是打包为zip文件

1
2
3
4
5
6
7
8
9
10
plugins {   //这个代码快必须放顶部
id "base"
}
task copy(type: Copy, group: "Custom", description: "复制src目录到dest目录") {
from "src"
into "dest"
}
task zip(type: Zip, group: "Util", description: "压缩src目录文件") {
from "src"
}

执行./gradlew zip,然后在目录 .\build\distributions下就可以看到gradle-demo.zip文件了

常用命令
1
2
3
./gradlew tasks #查看可用的task任务
./gradlew zip --scan #结合scan执行zip,分析执行信息
./gradlew properties #查看可用的配置属性,类似环境变量(配置属性)的

build.gradle可以更改properties变量的值,但是不能新增,例如修改项目描述和版本号

1
2
3
//放在build.gradle文件中,但是不能放在plugins前面,因为plugins这个必须在顶部
description = "该项目为测试学习用"
version = "1.0"

手册

Gradle 命令手册

注意事项

不能在gradle项目的子目录执行gradle init

RecyclerView 基本使用

  1. 添加依赖v7包依赖,版本号和compileSdkVersion一致,不然报错

    1
    2
    implementation 'com.android.support:appcompat-v7:25.0.0'
    implementation 'com.android.support:recyclerview-v7:25.0.0'
  2. 在layout里添加RecyclerView布局的引用

    1
    2
    3
    4
    5
    <android.support.v7.widget.RecyclerView
    android:id="@+id/recyView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
  3. 添加一个item的布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
    android:id="@+id/recyNumberPhone"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="TextView"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

    <TextView
    android:id="@+id/recyNumberName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="TextView"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>
  4. 创建适配器RecyNumberAdapter继承 RecyclerView.Adapter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    public class RecyNumberAdapter extends RecyclerView.Adapter<RecyNumberAdapter.NumberHolder>{
    private Context context; //上下文
    private List<Map<String,String>> mDatas; //数据源

    public RecyNumberAdapter(Context context,List<Map<String,String>> mDatas){
    //构造方法传入数据
    this.context=context;
    this.mDatas=mDatas;
    }

    @Override
    public NumberHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // 填充布局item
    View view = LayoutInflater.from(context).inflate(R.layout.recy_number, null);
    NumberHolder holder = new NumberHolder(view);
    return holder;
    }

    @Override
    public void onBindViewHolder(final NumberHolder holder, final int position) {
    //绑定view
    holder.recyNumberName.setText(String.valueOf(mDatas.get(position).get("name"))); //用户名
    holder.recyNumberPhone.setText(String.valueOf(mDatas.get(position).get("id"))); //电话号码
    }

    @Override
    public int getItemCount() {
    return mDatas.size(); //数据长度
    }
    //类部类
    class NumberHolder extends RecyclerView.ViewHolder{
    //获取item子布局的控件
    private TextView recyNumberPhone;
    private TextView recyNumberName;
    public NumberHolder(View view){
    super(view);
    recyNumberPhone=view.findViewById(R.id.recyNumberPhone);
    recyNumberName=view.findViewById(R.id.recyNumberName);
    }
    }
    }
  5. 调用测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    RecyclerView recyNumberView=findViewById(R.id.personalNumber);
    // 设置布局管理器有横向,表格等等
    GridLayoutManager gridLayoutManager=new GridLayoutManager(this,4);
    recyNumberView.setLayoutManager(gridLayoutManager);
    //测试数据
    List<Map<String,String>> datas=new ArrayList<>();
    Map<String,String> map=new HashMap<>();
    map.put("id","13432861290");
    map.put("name","张三");
    datas.add(map);
    //设置适配器
    recyNumberView.setAdapter(new RecyNumberAdapter(this,datas));
  6. 添加点击事件,在RecyNumberAdapter里添加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    private OnItemClickListener mItemClickListener;
    //item的回调接口
    public interface OnItemClickListener {
    void onItemClick(View view, int Position);
    }
    //定义一个设置点击监听器的方法
    public void setOnItemClickListener(OnItemClickListener itemClickListener) {
    this.mItemClickListener = itemClickListener;
    }
    //在覆写的onBindViewHolder方法中添加
    //如果设置了回调,则设置点击事件
    if (mItemClickListener != null) {
    holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    mItemClickListener.onItemClick(holder.itemView, position);
    }
    });
    }
  7. 调用的时候只需要recyNumberAdapter.setOnItemClickListener即可

dubbo官网/dubbo仓库地址

  1. 环境准备新建一个空的project,分别三个model

    model名称 model类型 说明
    common_interface java类型空项目 用于存放服务提供者和服务消费者的公共接口,避免写两次而已
    consumer springboot空项目 消费者服务依赖common_interface model
    provider springboot空项目 提供者服务依赖common_interface model
  2. 上面项目建立好,model依赖关系加好之后,下面开始引入dubbo框架

  3. 两个springboot项目都引入dubbo依赖这里用的gradle,仓库地址可以去dubbo仓库地址查看

    1
    compile group: 'com.alibaba', name: 'dubbo', version: '2.6.1'
  4. common_interface项目中添加一个接口类

    1
    2
    3
    4
    5
    package exxk.dubbo.commonimpl;

    public interface DemoService {
    String sayHello(String name);
    }
  5. provider项目中实现DemoService接口,在java目录下新建impl包,并添加一个DemoServiceImpl实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package exxk.dubbo.provider.impl;

    import exxk.dubbo.commonimpl.DemoService;

    public class DemoServiceImpl implements DemoService{
    @Override
    public String sayHello(String name) {
    return "hello"+ name;
    }
    }
  6. provider项目中resource目录下添加一个dubbo配置文件dubbo-provider.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?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:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--该提供者服务名称-->
    <dubbo:application name="dubbo-provider"/>
    <!--组播模式的注册中心,推荐用zookeeper-->
    <dubbo:registry address="multicast://224.5.6.7:1234"/>
    <!--暴露的端口服务-->
    <dubbo:protocol name="dubbo" port="20880"/>
    <!--声明暴露服务公共接口类-->
    <dubbo:service interface="exxk.dubbo.commonimpl.DemoService" ref="demoService"/>
    <!--提供者实现类-->
    <bean id="demoService" class="exxk.dubbo.provider.impl.DemoServiceImpl"/>
    </beans>
  7. provider项目中java目录下添加一个dubbo 启动类Provider.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package exxk.dubbo.provider;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class Provider {
    public static void main(String[] args) throws Exception {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
    new String[]{"dubbo-provider.xml"}); //读取dubbo配置文件
    context.start();
    //按任何键推出
    System.in.read();
    }
    }
  8. 上面的服务提供者基本完成,然后启动服务提供者,直接运行Provider.java静态方法即可

  9. consumer项目中resource目录下添加一个dubbo配置文件dubbo-consumer.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?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:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <dubbo:application name="dubbo-consumer"/>
    <!--注册中心地址(多播)-->
    <dubbo:registry address="multicast://224.5.6.7:1234"/>
    <dubbo:reference id="demoService" interface="exxk.dubbo.commonimpl.DemoService"/>
    </beans>
  10. consumer项目中java目录下添加一个dubbo 启动类Consumer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package exxk.dubbo.consumer;

import exxk.dubbo.commonimpl.DemoService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Consumer {
public static void main(String[] args) throws Exception{
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(
new String[]{"dubbo-consumer.xml"});
context.start();
DemoService demoService= (DemoService) context.getBean("demoService");
String hello= demoService.sayHello("world");
System.out.print(hello);
}
}
  1. 启动consumer服务消费者项目,这里用debug模式运行Consumer.java在里面打断点,主要是日志不好找,因此debug

基于springboot优化启动类

在springboot启动类添加dubbo启动,去掉默认的dubbo启动

  1. 最直接的是把dubbo启动类的配置xml内容直接放到application启动类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @SpringBootApplication
    public class ProviderApplication {
    public static void main(String[] args) {
    SpringApplication.run(ProviderApplication.class, args);
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
    new String[]{"dubbo-provider.xml"}); //读取dubbo配置文件
    context.start();
    //同步锁,保持该线程一直运行
    synchronized (Provider.class){
    while(true){
    try {
    Provider.class.wait();
    }catch (Exception e){
    System.out.print("synchronized===:"+e);
    }
    }
    }
    }
    }
  2. 这种当然不优雅,可以直接把xml配置文件配置到注解@ImportResource

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @SpringBootApplication
    public class ProviderApplication {
    public static void main(String[] args) {
    SpringApplication.run(ProviderApplication.class, args);
    //同步锁,保持该线程一直运行
    synchronized (Provider.class){
    while(true){
    try {
    Provider.class.wait();
    }catch (Exception e){
    System.out.print("synchronized===:"+e);
    }
    }
    }
    }
    }
  3. 代码是少了,但是据说,dubbo包含web框架,会让springboot当成web程序运行,这里自定义SpringApplicationBuilder禁用web

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @SpringBootApplication
    public class ProviderApplication {
    public static void main(String[] args) {
    ApplicationContext context= new SpringApplicationBuilder()
    .sources(ProviderApplication.class)
    .web(WebApplicationType.NONE) //禁用web服务
    .run(args);
    //同步锁,保持该线程一直运行
    synchronized (Provider.class){
    while(true){
    try {
    Provider.class.wait();
    }catch (Exception e){
    System.out.print("synchronized===:"+e);
    }
    }
    }
    }
    }
  4. 同步锁线程也换种方式实现,利用同步工具类CountDownLatch,该工具类的大概作用就是有等待指定线程(数)执行完了,再执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @SpringBootApplication
    @ImportResource({"classpath:dubbo-provider.xml"})
    public class ProviderApplication {

    @Bean
    public CountDownLatch closeLatch() {
    return new CountDownLatch(1);
    }

    public static void main(String[] args) throws InterruptedException {
    //SpringApplication.run(ProviderApplication.class, args);
    ApplicationContext context= new SpringApplicationBuilder()
    .sources(ProviderApplication.class)
    .web(WebApplicationType.NONE) //禁用web服务
    .run(args);

    CountDownLatch closeLatch=context.getBean(CountDownLatch.class);
    closeLatch.await(); //等待所有子线程完成
    }
    }
  5. 最后删除旧的启动器,到此大功告成

Spring Boot干货系列总纲 阅读笔记

配置文件解析

默认src/main/resources目录下,两种格式application.propertiesapplication.yml

自定义属性,在配置文件application.properties定义diy.name="hello" ,在使用的地方加上注解

1
2
@Value("${diy.name}")
private String name;

自定义配置类,需要在springboot入口类添加@EnableConfigurationProperties({ConfigBean.class})

1
2
3
4
5
6
@ConfigurationProperties(prefix = "diy")
public class ConfigBean {
private String name;
private String want;
// 省略getter和setter
}

有bugbug。。。。。。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
批量修改文件编码
*/
console.log("开始修改文件编码");
var fs= require("fs");
//---------同步----------------
var files =fs.readdirSync("./");
files.forEach(function (filename){
var stats=fs.statSync(filename);
console.log(filename+"文件状态",stats);
//if(stats.isDirectory()) filename +='/';
//process.
});
//----------异步------------------
fs.readdir("./",function(err,files){
var len=files.length;
var file=null;
for(var i=0;i<len;i++){
file=files[i];
console.log("读取文件",file);
var stats=fs.stat(file);
console.log("文件状态",stats);
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env node
/*
批量修改文件编码
*/
console.log("开始修改文件编码");
var fs = require("fs");
var jschardet = require("jschardet");
var path = "node_modules/jschardet";
readDir(path);
/*
修改文件编码
*/
function readDir(dirPath) {
console.log("目录:",dirPath);
var files = fs.readdirSync(dirPath);
files.forEach(function(file) {
var filepath = dirPath +"/"+file;
var stats = fs.statSync(filepath);
//console.log(filename+"文件状态",stats);
if (stats.isFile()) {
var buff = fs.readFileSync(file);
var info = jschardet.detect(buff);
console.log(filename + "文件编码", info);
} else if (stats.isDirectory()) {
console.log("目录" + filepath);
readDir(filepath);
}
});
}

安装运行

  1. tomcat 下载apache-tomcat-8.5.12-windows-x64然后解压安装

  2. 编辑tomcat/conf/server.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!-- 9301为自定义端口号,默认为8080 -->  
    <Connector port="9301" protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443" />
    <!--复制或者修改host-->
    <Host name="localhost" appBase="webapps"
    unpackWARs="true" autoDeploy="true">
    <!-- 新加context /app为url上下文,app为webapps下的app.war包-->
    <Context path="/app" docBase="app" reloadable="false"
    source="org.eclipse.jst.jee.server:tsj-spring"/>
    <Valve className="org.apache.catalina.valves.AccessLogValve"
    directory="logs" prefix="localhost_access_log" suffix=".txt"
    pattern="%h %l %u %t &quot;%r&quot; %s %b" />
    </Host>
  3. 运行tomcat,window下双击打开bin目录下的startup.bat启动app.war

  4. 访问为ip:9301/app/

tomcat远程自动部署

  1. 安装tomcat8.5.x

  2. 修改tomcat配置文件conf/server.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <?xml version="1.0" encoding="UTF-8"?>
    <Server port="8019" shutdown="SHUTDOWN">
    <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
    <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
    <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
    <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
    <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
    type="org.apache.catalina.UserDatabase"
    description="User database that can be updated and saved"
    factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
    pathname="conf/tomcat-users.xml" />
    </GlobalNamingResources>
    <Service name="Catalina">
    <Connector port="8005" protocol="HTTP/1.1"
    connectionTimeout="20010"
    redirectPort="8454" />
    <Connector port="8021" protocol="AJP/1.3" redirectPort="8454" />

    <Engine name="Catalina" defaultHost="H8005">

    <Realm className="org.apache.catalina.realm.LockOutRealm">
    <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
    resourceName="UserDatabase"/>
    </Realm>

    <Host name="H8005" appBase="webapps"
    unpackWARs="true" autoDeploy="true">

    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
    prefix="localhost_access_log" suffix=".txt"
    pattern="%h %l %u %t &quot;%r&quot; %s %b" />

    </Host>
    </Engine>
    </Service>
    </Server>
  3. 修改conf/tomcat-users.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <tomcat-users xmlns="http://tomcat.apache.org/xml"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
    version="1.0">

    <role rolename="admin-gui"/>
    <role rolename="admin-script"/>
    <role rolename="manager-gui"/>
    <role rolename="manager-script"/>
    <role rolename="manager-jmx"/>
    <role rolename="manager-status"/>
    <user username="admin" password="ideaadmin" roles="manager-gui,manager-script,manager-jmx,manager-status,admin-script,admin-gui"/>

    </tomcat-users>
  4. 启动tomcat执行./bin/catalina.sh start | tail -f ./logs/catalina.out,如果要修改启动内存,启动前提前修改catalina.sh

  5. conf/Catalina/h8005添加manager.xml

    1
    2
    3
    4
    <Context privileged="true" antiResourceLocking="false"
    docBase="${catalina.home}/webapps/manager">
    <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="^.*$" />
    </Context>
  6. 然后打开http://ip:8005/manager,输入用户名`admin`密码`idaeadmin`,进入之后保留**manager**删除其他所有applications

  7. 修改maven的.m2/setting.xml文件

    1
    2
    3
    4
    5
    6
    7
    8
    <servers>
    <server>
    <id>innerCs</id>
    <username>admin</username>
    <password>ideaadmin</password>
    </server>
    ...
    </servers>
  8. 在项目里面的pom.xml添加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <build>
    <finalName>InnerCS</finalName>
    <plugins>
    ...
    <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
    <url>http://ip:8005/manager/text</url>
    <path>/</path>
    <uriEncoding>UTF-8</uriEncoding>
    <server>innerCs</server>
    </configuration>
    </plugin>
    </plugins>
    </build>
  9. 编译Lifecyle->clean->install部署lifecyle->deploy发布到maven私库

  10. 远程第一次部署plugins->tomcat7->deploy,会上传ROOT.war/webapps/并解压运行生成ROOT因为我配置的path为/所以是ROOT

注意事项
  1. 第九步时,如果时maven多模块项目,需要在父项目,添加上传依赖jar的地址

    1
    2
    3
    4
    5
    6
    7
    8
    <!-- 配置maven地址 -->
    <distributionManagement>
    <snapshotRepository>
    <id>nexus-snapshots</id>
    <name>Nexus Snapshot Repository</name>
    <url>http://192.168.101.200:8081/repository/maven-snapshots/</url>
    </snapshotRepository>
    </distributionManagement>
  2. 还需要在maven的setting.xml配置maven的用户名,才有权限上传

    1
    2
    3
    4
    5
    <server>
    <id>nexus-snapshots</id>
    <username>admin</username>
    <password>admin123</password>
    </server>
  3. 多模块项目需要在父级里面进行clean-install-deploy,注意勾选idea maven右侧菜单里面的Profiles,不然父级不知道编译那个子项目

常见问题

  1. tomcat启动时出现java.lang.IllegalArgumentException: Illegal character(s) in message header field: Pragma:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    java.lang.IllegalArgumentException: Illegal character(s) in message header field: Pragma:
    2019-02-20 17:40:47 331 - at sun.net.www.protocol.http.HttpURLConnection.checkMessageHeader(HttpURLConnection.java:511)
    2019-02-20 17:40:47 331 - at sun.net.www.protocol.http.HttpURLConnection.isExternalMessageHeaderAllowed(HttpURLConnection.java:481)
    2019-02-20 17:40:47 331 - at sun.net.www.protocol.http.HttpURLConnection.setRequestProperty(HttpURLConnection.java:2895)
    2019-02-20 17:40:47 331 - at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestProperty(HttpsURLConnectionImpl.java:325)
    2019-02-20 17:40:47 331 - at mmo.common.utils.HttpUtils.sendPost(HttpUtils.java:28)
    2019-02-20 17:40:47 331 - at com.surelive.app.server.service.QQGroupApiService$1.run(QQGroupApiService.java:169)
    2019-02-20 17:40:47 331 - at com.surelive.app.server.entities.ext.QueueThreadHandle.run(QueueThreadHandle.java:52)
    2019-02-20 17:40:47 331 - at com.surelive.app.server.service.QueueThreadPoolServer$1.run(QueueThreadPoolServer.java:26)
    2019-02-20 17:40:47 331 - at java.lang.Thread.run(Thread.java:748)

    解决:执行env检查环境变量中是否有JAVA_HOME,没有设置好这些环境变量

ZSH

zsh (Mac 系统自带,无需安装)。

安装Oh-My-Zsh管理zsh的配置工具 sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

常用功能

配置文件cat ~/.zshrc

命令历史记录功能ctrl+r

历史记录存放在cat ~/.zsh_history

ctrl+r搜索命令历史记录,!!执行上一条命了

补全TAB

命令别名alias

~/.zshrc中添加alias name=command即可

查看所有命令别名alias

插件

git

iterm2 修改配色

Solarized Dark Higher Contrast

在这里找到自己https://github.com/mbadolato/iTerm2-Color-Schemes/tree/master/schemes喜欢的

然后保存文件,双击安装,然后color->color下来框选择自己安装的

item2 安装powerlevel9k主题

1
2
3
git clone https://github.com/bhilburn/powerlevel9k.git ~/.oh-my-zsh/custom/themes/powerlevel9k #下载主题
vim ~/.zshrc #编辑配置文件设置主题ZSH_THEME="powerlevel9k/powerlevel9k",去用户名添加 DEFAULT_USER="your user name"
git clone https://github.com/supermarin/powerline-fonts.git #下载字体

安装字体,双击/Monaco/Monaco for Powerline.otf文件安装字体

参考

https://gist.github.com/qhh0205/5570934d25a627dd9e9629a8ceeb415c