精华内容
下载资源
问答
  • 既然是对象创建时要执行的方法,那么只要在new对象时,知道其执行的构造方法是什么,就可以在执行这个方法的时候给对象进行属性赋值。 构造方法的格式: 修饰符 构造方法名(参数列表) { } 构造方法的体现: ...

    目录

    第一章 构造方法

    1.1构造方法介绍

    1.2构造方法调用和内存图解

    1.3默认构造方法和细节

    1.4构造方法和一般方法区别

    1.5总结

    第二章 this关键字

    2.1this调用构造方法

    2.2 this的原理图解

    第三章 super关键字

    3.1 子父类中构造方法的调用

    3.2 子类对象创建过程的细节

    3.3 super应用

    第四章 综合案例---完整的员工类

    4.1 案例介绍

    4.2 代码实现


    第一章 构造方法

     

    1.1构造方法介绍

    那什么是构造方法呢?从字面上理解即为构建创造时用的方法,即就是对象创建时要执行的方法

    既然是对象创建时要执行的方法,那么只要在new对象时,知道其执行的构造方法是什么,就可以在执行这个方法的时候给对象进行属性赋值。

    构造方法的格式:

    修饰符 构造方法名(参数列表)

    {

    }

    构造方法的体现:

    构造方法没有返回值类型。也不需要写返回值。因为它是为构建对象的,对象创建完,方法就执行结束。

    构造方法名称必须和类名保持一致。

    构造方法没有具体的返回值。

    自动生成get与set方法:alt+shift+s 

    package cn.itcast.demo01;
    /*
     *  自定义的Person类.成员变量,name age
     *  要求在 new Person的同时,就指定好name,age的值
     *  实现功能,利用方法去实现, 构造方法,构造器 Constructor
     *  作用: 在new 的同时对成员变量赋值, 给对象的属性初始化赋值  new Person 对属性 name,age赋值
     *  
     *  构造方法的定义格式
     *    权限  方法名(参数列表){
     *    }
     *    方法的名字,必须和类的名字完全一致
     *    构造方法不允许写返回值类型  , void 也不能写
     *    
     *    构造方法在什么时候,运行呢, 在new 的时候,自动执行
     *    只运行一次,仅此而已
     *    
     *    每个class必须拥有构造方法,构造方法不写也有
     *    编译的时候,javac, 会自动检查类中是否有构造方法
     *    如果有,就这样的
     *    如果没有,编译器就会自动添加一个构造方法
     *      编译器自动添加的构造方法: public Person(){}
     *    自己手写了构造方法,编译的时候,不会自动添加构造方法!
     */
    public class Person {
    	private String name;
    	private int age;
    	
    	//定义出Person类的构造方法
    	public  Person(String name,int age){
    		this.name = name;
    		this.age = age;
    		//System.out.println("我是一个空参数构造方法");
    	}
    	
    	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;
    	}
    	
    	
    }
    
    package cn.itcast.demo01;
    /*
     *  new 对象的时候,就是在调用对象的构造方法
     *   new Person(); 调用的是类中的空参数构造方法
     *   new Person("张三",20); 调用类中的有参数构造方法
     */
    public class Test {
    	public static void main(String[] args) {
    		Person p = new Person("张三",20);		
    		//对象p 调用方法getName,getAge
    		System.out.println(p.getName());
    		System.out.println(p.getAge());
    		
    	}
    }
    

     

    1.2构造方法调用和内存图解

    new对象的时候,就是在调用对象的构造方法。

    如果自己未定义构造方法,编译器会自动添加一个构造方法。若自己手动写了构造方法,编译时不会自动添加构造方法。

    内存图解:

    main函数进栈,Person p = new Person("张三",20);进入堆内存,并为其成员变量初始化为空, Person对象调用自己的构造方法,构造方法进栈内存运行。

    Person对象将内存地址传递给this关键字。构造方法运行结束了,整个对象才算建立完成。

     

    1.3默认构造方法和细节

    在之前学习的过程中,描述事物时,并没有显示指定构造方法,当在编译Java文件时,编译器会自动给class文件中添加默认的构造方法。如果在描述类时,我们显示指定了构造方法,那么,当在编译Java源文件时,编译器就不会再给class文件中添加默认构造方法。

    class  Person {
    
        //如果没有显示指定构造方法,编译会在编译时自动添加默认的构造方法
    
        //Person(){}  //空参数的默认构造方法
    
    }

    当描述的事物在创建其对象时就要明确属性的值,这时就需要在定义类的时候书写带参数的构造方法。

    若创建对象时不需要明确具体的数据,这时可以不用书写构造方法(不书写也有默认的构造方法)。

    构造方法的细节:

    一个类中可以有多个构造方法,多个构造方法是以重载的形式存在的

    构造方法是可以被private修饰的,作用:其他程序无法创建该类的对象。

     

    1.4构造方法和一般方法区别

    到目前为止,学习两种方法,分别为构造方法和一般方法(get、set方法),那么他们之间有什么异同呢?

    构造方法在对象创建时就执行了,而且只执行一次。

    一般方法是在对象创建后,需要使用时才被对象调用,并可以被多次调用。

    有了构造方法之后可以对对象的属性进行初始化,那么还需要对应的set和get方法吗?

    需要相应的set和get方法,因为对象在创建之后需要修改和访问相应的属性值时,在这时只能通过set或者get方法来操作。

    package cn.itcast.demo02;
    /*
     *   构造方法的重载特性
     *     参数列表不同
     */
    public class Person {
    	private String name;
    	private int age;
    	
    	//写空参数构造方法
    	public Person(){
    		
    	}
    	
    	//写带有两个参数的构造方法
    	public Person(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;
    	}
    	
    	
    }
    
    package cn.itcast.demo02;
    
    public class Test {
    	public static void main(String[] args) {
    		//创建Person类的对象
    		//就是在调用他的构造方法
    		
    		//1. 调用空参数构造方法,创建对象
    		Person p1 = new Person();
    		p1.setAge(18);
    		p1.setName("旺财");
    		System.out.println(p1.getName()); 
    		System.out.println(p1.getAge()); 
    		
    		//2. 调用有2个参数的构造方法,创建对象
    		Person p2 = new Person("小强", 17);
    		System.out.println(p2.getName());
    		System.out.println(p2.getAge());
    		
    	}
    }
    

     

    1.5总结

    继承中的构造方法注意事项:

        1.如果我们手动给出了构造方法,编译器不会在给我们提供默认的空参数构造方法

               如果我们没写任何的构造方法,编译器提供给我们一个空参数构造方法

        2.在构造方法中,默认的第一条语句为 super();

           它是用来访问父类中的空参数构造方法,进行父类成员的初始化操作

        3.当父类中没有空参数构造方法的时候,怎么办?

                a: 通过 super(参数) 访问父类有参数的构造方法

                b: 通过 this(参数) 访问本类中其他构造方法

                   注意:[本类中的其他构造方法已经能够正常访问父类构造方法]

         4.super(参数) 与 this(参数) 不能同时在构造方法中存在

     

    第二章 this关键字

    方法之间是可以通过方法名相互调用的,那么构造方法之间能不能相互调用呢?若可以,怎么调用呢?

     

    2.1this调用构造方法

    构造方法之间的调用,可以通过this关键字来完成。

    构造方法调用格式:

    • this(参数列表);
    • 且this()必须放在构造方法的第一行
    package cn.itcast.demo03;
    /*
     *   this可以在构造方法之间进行调用
     *   this.的方式,区分局部变量和成员变量同名情况
     *   this在构造方法之间的调用,语法 this()
     */
    public class Person {
    	private String name;
    	private int age;
    	
    	public Person(){
    		//调用了有参数的构造方法
    		//参数李四,20传递给了变量name,age
    		this("李四",20);
    	}
    	/*
    	 *  构造方法,传递String,int
    	 *  在创建对象的同时为成员变量赋值
    	 */
    	public Person(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;
    	}
    	
    	
    }
    
    package cn.itcast.demo03;
    
    public class Test {
    	public static void main(String[] args) {
    		//创建Person的对象,调用的是空参数的构造方法
    		//运行的结果 null 0
    		Person p = new Person();
    		
    		System.out.println(p.getName());
    		System.out.println(p.getAge());
    	}
    }
    

     

    2.2 this的原理图解

    内存图解释:

    main方法先入栈,执行new Person(),new Person()进入堆内存,并为其分配内存地址,随后为成员变量赋默认值,调用无参的构造方法。

    此时Person()入栈,执行其内部语句,调用this(“李四”,20),此时含参数的构造方法入栈执行。

    赋值结束后,含参数的构造方法出栈,随后无参的构造方法出栈。执行结束。

     

     

    第三章 super关键字

     

    3.1 子父类中构造方法的调用

    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语句,指定要访问的父类有参数构造方法。

    内存图解释:

    父类先进方法区,子类再进方法区,并且子类通过super找到父类的存储地址。

    super为父类存储的内存地址。

    先有子类的堆内存空间,将其划分为两部分,一部分留给父类,另一部分留给自己。父类的成员变量,跟随子类的对象进入堆内存。

     

    3.2 子类对象创建过程的细节

    super()也必须为构造方法的第一行(this()也必须是第一行)

    如果父类的构造方法有参,则子类的构造函数中必须super()显示调用,否则会报错。

    因为编译器默认添加的是无参的super()

    如果子类的构造方法第一行写了this调用了本类其他构造方法,那么super调用父类的语句还有吗?

    这时是没有的,因为this()或者super(),只能定义在构造方法的第一行,因为初始化动作要先执行。

    父类构造方法中是否有隐式的super呢?

    也是有的。记住:只要是构造方法默认第一行都是super();

    父类的父类是谁呢?super调用的到底是谁的构造方法呢?

    Java体系在设计,定义了一个所有对象的父类Object

    注意:

    类中的构造方法默认第一行都有隐式的super()语句,在访问父类中的空参数构造方法。所以父类的构造方法既可以给自己的对象初始化,也可以给自己的子类对象初始化。

    如果默认的隐式super()语句在父类中没有对应的构造方法,那么必须在构造方法中通过this或者super的形式明确要调用的构造方法。

     

    package day12.demo2;
    /*
     *   手动写一个父类Person类的构造方法,加入int类型参数
     *   保存,子类就报错
     */
    public class Person {
    	public Person(int a) {
    		
    	}
    	public Person(double d) {
    		
    	}
    }
    
    package day12.demo2;
    /*
    *  子类构造方法的报错原因: 找不到父类的空参数构造器
    *  子类中,没有手写构造,编译器添加默认的空参数
    *  public Student(){
    *     super();
    *  }
    *  编译成功,必须手动编写构造方法,请你在super中加入参数
    *  
    *  注意: 子类中所有的构造方法,无论重载多少个,第一行必须是super()
    *  如果父类有多个构造方法,子类任意调用一个就可以
    *  super()语句必须是构造方法第一行代码
    */
    public class Student extends Person{
    	public Student() {
    		super(0.1);
    	}
    	public Student(String s) {
    		super(1);
    	}
    }
    
    package day12.demo2;
    
    public class Test {
    	public static void main(String[] args) {
    		new Student();
    	}
    }
    

    构造方法第一行,写this()还是super()?
        两者 不能同时存在,任选其一,要保证子类的所有构造方法调用到父类的构造方法即可。
         小结论: 无论如何,子类的所有构造方法,都要直接或者间接调用到父类构造方法。
         子类的构造方法,什么都不写时,默认的构造方法第一行为super();

    public class Person {
    	public Person(int a) {
    		
    	}
    	
    }
    
    /*
    	构造方法第一行,写this()还是super()
    	不能同时存在,任选其一,保证子类的所有构造方法调用到父类的构造方法即可
    	
    	小结论: 无论如何,子类的所有构造方法,直接,间接必须调用到父类构造方法
    	子类的构造方法,什么都不写,默认的构造方法第一行 super();
    */
    public class Student extends Person{
    	public Student() {
    		this("lalala");
    	}
    	public Student(String s) {
    		super(1);
    	}
    }
    
    
    public class Test {
    	public static void main(String[] args) {
    		new Student();
    	}
    }
    

     

    3.3 super应用

    练习:描述学生和工人这两个类,将他们的共性name和age抽取出来存放在父类中,并提供相应的get和set方法,同时需要在创建学生和工人对象就必须明确姓名和年龄。

    package day12.demo4;
    /*
     *  Student类和Worker有相同成员变量,name age
     *  继承的思想,共性抽取,形成父类
     *  Person,抽取出来父类
     *  成员变量,私有修饰
     *  同时需要在创建学生和工人对象就必须明确姓名和年龄
     *  new Student, new Worker 姓名,年龄明确了
     */
    public class Person {
    	private String name;
    	private int age;
    	public Person(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;
    	}
    	
    }
    
    package day12.demo4;
    
    public class Student extends Person{
    	public Student(String name, int age) {
    		super(name,age);
    		
    	}
    }
    
    package day12.demo4;
    
    public class Worker extends Person{
    public Worker(String name, int age) {
    	super(name,age);
    	
    }
    }
    package day12.demo4;
    
    public class Test {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Worker w = new Worker("光头强",20);
    		System.out.println(w.getName());
    		System.out.println(w.getAge());
    		
    		Student s = new Student("肥波",10);
    		System.out.println(s.getName());
    		System.out.println(s.getAge());
    	}
    
    }
    

     

    第四章 综合案例---完整的员工类

     

    4.1 案例介绍

    某IT公司有多名员工,按照员工负责的工作不同,进行了部门的划分(研发部员工、维护部员工)。研发部根据所需研发的内容不同,又分为JavaEE工程师、Android工程师;维护部根据所需维护的内容不同,又分为网络维护工程师、硬件维护工程师。

    公司的每名员工都有他们自己的员工编号、姓名,并要做它们所负责的工作。

    工作内容

    1. JavaEE工程师:员工号为xxx的 xxx员工,正在研发淘宝网站
    2. Android工程师:员工号为xxx的 xxx员工,正在研发淘宝手机客户端软件
    3. 网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
    4. 硬件维护工程师:员工号为xxx的 xxx员工,正在修复打印机

    请根据描述,完成员工体系中所有类的定义,并指定类之间的继承关系。进行XX工程师类的对象创建,完成工作方法的调用。

     

    4.2 代码实现

    package day12.demo5;
    /*
     *  员工类:
     *    共性的抽取
     *    姓名,编号,工作方法(抽象)
     */
    public abstract class Employee {
    	private String name;
    	private String id;
    	public Employee(String name, String id) {
    		this.name = name;
    		this.id = id;
    	}
    	public abstract void work();
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	
    
    }
    
    public abstract class Developer extends Employee{
    	public Developer(String name, String id) {
    		super(name,id);
    
    }
    }
    public class JavaEE extends Developer{
    	public JavaEE(String name, String id) {
    		super(name,id);
    	}
    	public void work() {
    		System.out.println(super.getName()+"..."+super.getId()+"在开发淘宝");
    		
    		
    	}
    }
    
    package day12.demo5;
    
    public abstract class Maintainer extends Employee{
    	public Maintainer(String name, String id) {
    		super(name,id);
    	}
    	
    
    }
    
    package day12.demo5;
    
    public class Net extends Maintainer{
    	public Net(String name, String id) {
    		super(name,id);
    	}
    	public void work() {
    		System.out.println(super.getName()+"..."+super.getId()+"正在检测网络是否畅通");
    		
    		
    	}
    }
    package day12.demo5;
    
    public class Test {
    	public static void main(String[] args) {
    		
    	JavaEE ee = new JavaEE("张三","开发部001");
    	ee.work();
    	
    	Net net = new Net("李四","维护部001");
    	net.work();
    	
    	}
    }
    

     

    展开全文
  • Nacos服务调用图解

    2021-08-19 18:50:47
    服务调用方案图解 这张图描述了远程服务调用的几中方式: 第一种:服务比较少,例如就两个服务,一个服务消费,一个服务提供,就不需要注册中心,不需要负载均衡. 第二种:并发比较大,服务服务比较多,我们需要管理服务,就...

    目录

     Nacos

    nacos概述

     构建Nacos服务

    下载与安装 

    初始化配置

    服务启动与访问

     常见报错

            MySQL的版本问题

            Nacos服务启动问题

    服务注册与调用入门

    生产者服务创建及注册

     消费者服务发现及调用

     服务负载均衡设计及实现

    面试分析

    微服务项目结构分析​

    服务调用案例分析​

    服务调用方案图解​



    •  Nacos

    • nacos概述

            Nacos(DynamicNaming and Configuration Service)是一个应用于服务注册与发现、配置管理的平台。它孵化于阿里巴巴,成长于十年双十一的洪峰考验,沉淀了简单易用、稳定可靠、性能卓越的核心竞争力.官网地址:https://nacos.io/zh-cn/docs/quick-start.html

    •  构建Nacos服务

    1. 检查环境变量(JAVA_HOME)
    2. 确保Mysql版本为5.7以上(MariaDB 10.5以上)
    • 下载与安装 

    1. Nacos下载

            https://github.com/alibaba/nacos/releases

    2. 解压Nacos(注意:不要出现中文目录)

    • 初始化配置

    1.  打开/conf/application.properties里打开默认配置,并基于你当前环境配置要连接的数据库,连接数据库时使用的用户名和密码(假如前面有"#"要将其去掉):

      ### If use MySQL as datasource:
      spring.datasource.platform=mysql
      
      ### Count of DB:
      db.num=1
      
      ### Connect URL of DB:
      db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
      db.user.0=root
      db.password.0=root
    2. 登录mysql,执行:source d:/nacos-mysql.sql

    • 服务启动与访问

    1. 启动Nacos服务

    • Linux/Unix/Mac启动命令(standalone代表着单机模式运行,非集群模式):

            ./startup.sh -m standalone

    • Windows启动命令(standalone代表着单机模式运行,非集群模式):

            startup.cmd -m standalone

    说明:

    1)执行执行令时要么配置环境变量,要么直接在nacos/bin目录下去执行.
    2)nacos启动时需要本地环境变量中配置了JAVA_HOME(对应jdk的安装目录),
    3)一定要确保你连接的数据库(nacos_config)是存在的.
    4)假如所有的配置都正确,还连不上,检查一下你有几个数据库(mysql,…)

    2.访问Nacos服务

    打开浏览器,输入http://localhost:8848/nacos地址,出现如下登陆页面:

    其中,默认账号密码为nacos/nacos.

    •  常见报错

            MySQL的版本问题

    当我们在执行一些SQL脚本时(例如 nacos-mysql.sql文件),假如出现如下错误,请升级你的mysql(建议mysql5.7以上或MariaDB 10.5.11)

            Nacos服务启动问题

    问题1:

    问题2:

    • 服务注册与调用入门

    创建两个项目Module分别为服务提供者和服务消费者,两者都要注册到NacosServer中(这个server本质上就是一个web服务,端口默认为8848),然后服务提供者可以为服务消费者提供远端调用服务(例如支付服务为服务提供方,订单服务为服务消费方),如图所示:

    • 生产者服务创建及注册

    1. 创建服务提供者工程(module名为sca-provider),继承parent工程(01-sca),其pom.xml文件内容如下: 

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <parent>
              <artifactId>01-sca</artifactId>
              <groupId>com.jt</groupId>
              <version>1.0-SNAPSHOT</version>
          </parent>
          <modelVersion>4.0.0</modelVersion>
          <artifactId>sca-provider</artifactId>
          <dependencies>
              <!--Web服务-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <!--服务的注册和发现(我们要讲服务注册到nacos)-->
              <dependency>
                  <groupId>com.alibaba.cloud</groupId>
                  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
              </dependency>
          </dependencies>
      </project>

      2.创建并修改配置文件application.yml(或者application.properties),实现服务注册,关键代码如下:

      server:
         port: 8081
      spring:
        application:
          name: sca-provider
        cloud:
          nacos:
            discovery:
              server-addr: localhost:8848

      注意:服务名不要使用下划线(“_”),应使用横杠(“-”),这是规则。

    3.创建启动类,并定义处理请求的控制层对象和方法,关键代码如下:

    package com.cy;
    
    @SpringBootApplication
    public class ProviderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ScaProviderApplication.class, args);
        }
    
        /**定义Controller对象(这个对象在spring mvc中给他的定义是handler),
         * 基于此对象处理客户端的请求*/
        @RestController
        public class ProviderController{
            //@Value默认读取项目配置文件中配置的内容
            //8080为没有读到server.port的值时,给定的默认值
            @Value("${server.port:8080}")
            private String server;
            //http://localhost:8081/provider/echo/tedu
            @GetMapping("/provider/echo/{msg}")
            public String doRestEcho1(@PathVariable String msg){
                return server+" say hello "+msg;
            }
        }
      }

     4.启动启动类,然后刷先nacos服务,检测是否服务注册成功,如图所示:

    5.打开浏览器,输入http://localhost:8081/provider/echo/msa,然后进行访问。 

    •  消费者服务发现及调用

    1.创建服务消费者(module名为sca-consumer),继承parent工程(01-sca),其pom.xml文件内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>01-sca</artifactId>
            <groupId>com.jt</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <artifactId>sca-consumer</artifactId>
        
       <dependencies>
        <!--Web服务-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--服务的注册和发现(我们要讲服务注册到nacos)-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        </dependencies>
    </project>

    2.修改配置文件application.yml,关键代码如下:

    server:
      port: 8090
    spring:
      application:
        name: sca-consumer
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #从哪里去查找服务

     3.创建启动类并实现服务消费,关键代码如下:

    package com.cy;
    @SpringBootApplication
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class,args);
        }
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
        @RestController
        public class ConsumerController{
    
            @Value("${spring.application.name}")
            private String appName;
            @Autowired
            private RestTemplate restTemplate;
            @GetMapping("/consumer/doRestEcho1")
            public String doRestEcho01(){
                String url = "http://localhost:8081/provider/echo/"+appName;
                System.out.println("request url:"+url);
               return restTemplate.getForObject(url, String.class);
            }
        }
    }

     4.动消费者服务,并在浏览器输入http://localhost:8090/consumer/doRestEcho1地址进行访问,假如访问成功会出现,如图所示效果:

    •  服务负载均衡设计及实现

     1.手动写负载均衡

            配置启动多个启动类,修改并发运行选项:

     

    修改sca-provider的配置文件端口,分别以8081,8082端口方式进行启动。

    server:
      port: 8081
    spring:
      application:
        name: sca-provider
      cloud:
        nacos:
          server-addr: localhost:8848
     @GetMapping("/consumer/echo/{msg}")
            public String doRestEcho1(@PathVariable String msg) {
                //手动自己写负载均衡(随机调用服务列表中的服务对象)
                //调用谁? sca-provider中的一个url
                String url1 = "http://localhost:8081/provider/echo/"+msg;
                String url2 = "http://localhost:8080/provider/echo/"+msg;
                String url3 = "http://localhost:8082/provider/echo/"+msg;
                String urls[] = new String[]{url1,url2,url3};
                //随机获取一个小于urls数组长度的整数
                int n = new Random().nextInt(urls.length);//手动式的负载均衡
                //如何调用?
                return restTemplate.getForObject(urls[n],String.class);
    //            return server + "Say hello" + msg;
            }
    

     启动sca-consumer项目模块,打开浏览器,输入如下网址进行反复服务访问:

    http://localhost:8090/consumer/echo/tedu

    然后会发现sca-provider的两个服务都可以处理sca-consumer的请求.

    2.基于loadBalancerClient方式获取服务实例

        @Bean
        @LoadBalanced//这个注解在描述RestTemplate对象时,系统底层会对RestTemplate对象的请求进行拦截
        public RestTemplate loadBalanceRestTemplate(){
            return new RestTemplate();
        }
    
     @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    
        @Bean
        @LoadBalanced//这个注解在描述RestTemplate对象时,系统底层会对RestTemplate对象的请求进行拦截
        public RestTemplate loadBalanceRestTemplate(){
            return new RestTemplate();
        }
    
        @RestController
        public class ConsumerController{
    
            @Autowired
            private RestTemplate restTemplate;
    
            /**
             * @Autowired注解描述属性时,会告诉spring框架,要优先按照属性类型进行对象的查找和注入,假如
             * 此类型的对象存在多个,此时还会按照属性名进行查找和对比,有相同的直接注入(DI),没有相同则报错
             * 也可以在属性山添加@Qualifier("bean的名字")注解,指定要注入的具体对象
             * */
    
            @Autowired
            private RestTemplate loadBalanceRestTemplate;
    
            //负载均衡客服端对象(基于此对象可以从nacos中获取服务列表,并且可以基于一定的算法从列表获取一个服务实例)
            @Autowired
            private LoadBalancerClient loadBalancerClient;
    
            @Value("${server.port:8080}")
            private String server;
    
    
    
    
                //负载均衡方式调用
                @GetMapping("/consumer/echo2/{msg}")
                public String doRestEcho2(@PathVariable String msg){
                //基于loadBalancerClient方式获取服务实例
                String serviceId = "sca-provider";//这个名字要在nacos的服务列表中
                ServiceInstance choose = loadBalancerClient.choose(serviceId);
                String ip = choose.getHost();
                int port = choose.getPort();
    //            String url = "http://" + ip + ":" + port + "/provider/echo/"+msg;
                String url = String.format("http://%s:%s/provider/echo/%s",ip,port,msg);
                return restTemplate.getForObject(url,String.class);
            }

    3. 使用拦截器的方式

        @Bean
        @LoadBalanced//这个注解在描述RestTemplate对象时,系统底层会对RestTemplate对象的请求进行拦截
        public RestTemplate loadBalanceRestTemplate(){
            return new RestTemplate();
        }
    
    
    
            @GetMapping("/consumer/echo3/{msg}")
            public String doRestEcho3(@PathVariable String msg) {
                String url = String.format("http://sca-provider/provider/echo/%s",msg);
                return loadBalanceRestTemplate.getForObject(url,String.class );
            }
        }
    }

    面试分析

    • 为什么要将服务注册到nacos?(为了更好的查找这些服务)
    • 在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
    • 对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
    • 服务启动时如何找到服务启动注册配置类?(NacosNamingService)
    • 服务消费方是如何调用服务提供方的服务的?(RestTemplate)

           

    • @Bean注解的作用?(一般用于配置类内部,描述相关方法,用于告诉spring此方法的返回值要交给spring管理,bean的名字默认为方法名,假如需要指定名字可以@Bean(“bean的名字”),最多的应用场景是整合第三方的资源-对象)
    • @Autowired注解的作用?(此注解用于描述属性,构造方法,set方法等,用于告诉spring框架,按找一定的规则为属性进行DI操作,默认按属性,方法参数类型查找对应的对象,假如只找到一个,则直接注入,类型多个时还会按照属性名或方法参数名进行值的注入,假如名字也不同,就出报错.)
    • Nacos中的负责均衡底层是如何实现的?(通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务)
    • Ribbon 是什么?(Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法)
    • Ribbon 可以解决什么问题? (基于负载均衡策略进行服务调用, 所有策略都会实现IRule接口)
    • Ribbon 内置的负载策略都有哪些?(8种,可以通过查看IRule接口的实现类进行分析)
    • @LoadBalanced的作用是什么?(描述RestTemplate对象,用于告诉Spring框架,在使用RestTempalte进行服务调用时,这个调用过程会被一个拦截器进行拦截,然后在拦截器内部,启动负载均衡策略。)
    • 我们可以自己定义负载均衡策略吗?(可以,基于IRule接口进行策略定义,也可以参考NacosRule进行实现)

    微服务项目结构分析

    服务调用案例分析

    服务调用方案图解

     这张图描述了远程服务调用的几中方式:
    第一种:服务比较少,例如就两个服务,一个服务消费,一个服务提供,就不需要注册中心,不需要负载均衡.
    第二种:并发比较大,服务服务比较多,我们需要管理服务,就需要注册中心,我们还需要服务间的负载均衡.但代码编写的复杂多相对高一些,我们需要自己获取ip,获取端口,拼接字符串等.
    第三种:我们要基于第二种进行代码简化,底层提供了一种拦截器,把基于服务名获取服务实例的过程在拦截器中做了封装,简化了代码的开发.但是加了拦截器多少会在性能少有一点损耗.
    第四种方式主要是从代码结构上做一个挑战,我们前面三种基于RestTemplate进行服务调用,本身属于一种远程服务调用业务,能够将这种业务写到一个业务对象中,Feign方式就诞生了,它主要对代码结构的一种优化.
     

    展开全文
  • 有很多初学者看到一些资料中提到“方法传递对象时,传递的是对象的引用(pass-by-reference)”,这让他们又很混乱,其实对象传递的是复制引用对象的值,也可以理解为存放引用原始对象引用的指针值,如果你觉得比较难...

    针对如上问题,先说结论,java 调用方法时,参数传递的是值。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。有很多初学者看到一些资料中提到“方法传递对象时,传递的是对象的引用(pass-by-reference)”,这让他们又很混乱,其实对象传递的是复制引用对象的值,也可以理解为存放引用原始对象引用的指针值,如果你觉得比较难理解,看下面的图解。

    方法传递对象类型

    public class NationDemo {

    public static void main(String[] args) {

    Nation usa = new Nation("usa");

    Nation america = usa;

    // we pass the object to foo

    foo(usa);

    // usa variable is still pointing to the "usa" when foo(...) returns

    System.out.println(usa.getName().equals("usa")); // true

    System.out.println(usa.getName().equals("china")); // false

    System.out.println(usa == america); // true

    }

    public static void foo(Nation nation) {

    System.out.println(nation.getName().equals("usa")); // true

    // change nation inside of foo() to point to a new Nation instance "china"

    nation = new Nation("china");

    System.out.println(nation.getName().equals("china")); // true

    }

    static class Nation {

    private String name;

    public Nation(String name) {

    this.name = name;

    }

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    }

    }

    6426c4315d548ec90eb7808fadfa881d.png

    上图直观解释了方法传递对象时,传递的是存放对象地址的值,传递的参数 nation 为复制 usa 变量存放的指向 Nation(0x1234) 的对象,后在方法中存放的地址变为另一个对象 Nation(0x5678),方法调用结束后,usa 变量引用的对象内容没有任何变动。从图上也可以看出,变量参数都是存放在栈(stack)空间(属于私有线程栈),类实例即对象是存放在堆(heap)空间上的(共享空间)。

    方法传递基本类型

    public class CallByPrimitiveTypeValueDemo {

    public static void main(String[] args) {

    boolean bool = true;

    char c = 'a';

    byte b = 1;

    short s = 11;

    int i = 101;

    long l = 1001L;

    float f = 10001f;

    double d = 100001d;

    bar(bool, c, b, s, i, l, f, d);

    System.out.println(bool);

    System.out.println(c);

    System.out.println(b);

    System.out.println(s);

    System.out.println(i);

    System.out.println(l);

    System.out.println(f);

    System.out.println(d);

    }

    public static void bar(boolean bool, char c, byte b, short s, int i, long l, float f, double d) {

    bool = false;

    c = 'b';

    b = 2;

    s = 12;

    i = 102;

    l = 1002L;

    f = 10002f;

    d = 100002d;

    }

    }

    方法传递基本类型比对象参数更好理解,方法中传递的是基本类型的值,且都发生在栈空间内。

    展开全文
  • 一 this调用构造方法构造方法之间的调用,可以通过this关键字来完成。格式:this(参数列表);构造方法调用举例:classPerson {//Person的成员属性private intage;privateString name;//无参数的构造方法Person() {}...

    一 this调用构造方法

    构造方法之间的调用,可以通过this关键字来完成。

    格式:

    this(参数列表);

    构造方法的调用举例:

    classPerson {//Person的成员属性

    private intage;privateString name;//无参数的构造方法

    Person() {

    }//给姓名初始化的构造方法

    Person(String nm) {

    name=nm;

    }//给姓名和年龄初始化的构造方法

    Person(String nm, inta) {//由于已经存在给姓名进行初始化的构造方法 name = nm;因此只需要调用即可//调用其他构造方法,需要通过this关键字来调用

    this(nm);//给年龄初始化

    age =a;

    }

    }

    二 this的原理图解

    例如:

    classPerson {private intage;privateString name;

    Person() {

    }

    Person(String nm) {

    name=nm;

    }

    Person(String nm,inta) {this(nm);

    age=a;

    }

    }classPersonDemo {public static voidmain(String[] args) {

    Person p= new Person("张三", 23);

    }

    }

    内存图解:

    8ab1759f5813086155fdeec0b83b5726.png

    1、先执行main方法,main方法压栈,执行其中的new Person(“张三”,23);

    2、堆内存中开辟空间,并为其分配内存地址0x33,,紧接着成员变量默认初始化(name=null age = 0);

    3、拥有两个参数的构造方法(Person(String nm , int a))压栈,在这个构造方法中有一个隐式的this,

    因为构造方法是给对象初始化的,那个对象调用到这个构造方法,this就指向堆中的那个对象。

    4、由于Person(String nm , int a)构造方法中使用了this(nm);构造方法Person(String nm)就会压栈,

    并将“张三”传递给nm。在Person(String nm , int a)构造方法中同样也有隐式的this,this的值同样也为

    0x33,这时会执行其中name = nm,即把“张三”赋值给成员的name。当赋值结束后Person(String nm , int a)

    构造方法弹栈。

    5、程序继续执行构造方法(Person(String nm , int a)中的age = a;这时会将23赋值给成员属性age。

    赋值结束构造方法(Person(String nm , int a)弹栈。

    6、当构造方法(Person(String nm , int a)弹栈结束后,Person对象在内存中创建完成,并将0x33赋值

    给main方法中的p引用变量。

    注意事项:

    this所在的方法,this就代表哪个对象。

    调用其他构造方法的语句必须定义在构造方法的第一行,原因是初始化动作要最先执行。

    三 成员变量和局部变量同名问题

    以在成员变量名前面加上this.来区别成员变量和局部变量

    例如:

    classPerson {private intage;privateString name;//给姓名和年龄初始化的构造方法

    Person(String name, intage) {//当需要访问成员变量是,只需要在成员变量前面加上this.即可

    this.name =name;this.age =age;

    }public voidspeak() {

    System.out.println("name=" + this.name + ",age=" + this.age);

    }

    }classPersonDemo {public static voidmain(String[] args) {

    Person p= new Person("张三", 23);

    p.speak();

    }

    }

    四 this的应用

    例如:在Person类中定义功能,判断两个人是否是同龄人

    classPerson {private intage;privateString name;//给姓名和年龄初始化的构造方法

    Person(String name, intage) {//当需要访问成员变量是,只需要在成员变量前面加上this.即可

    this.name =name;this.age =age;

    }public voidspeak() {

    System.out.println("name=" + this.name + ",age=" + this.age);

    }//判断是否为同龄人

    public booleanequalsAge(Person p) {//使用当前调用该equalsAge方法对象的age和传递进来p的age进行比较//由于无法确定具体是哪一个对象调用equalsAge方法,这里就可以使用this来代替

    /** if(this.age == p.age) { return true; } return false;*/

    return this.age =p.age;

    }

    }

    展开全文
  • 最近,我在用java写代码过程中遇到了这么个情况:通过调用 方法 来修改 值,有时候能成功,有时候却失败,让我百思不得其解。于是,这篇博文诞生了,与大家一起分享一下我的使用心得。 基础知识 想要搞清楚这个...
  • 本文实例讲述了java中对象数组的使用方法。分享给大家供大家参考,具体如下:一 点睛对象可以用数组来存放,通过下面两个步骤来实现。1 声明以类为数据类型的数组变量,并用new分配内存空间给数组。2 用new产生新的...
  • 子类实例对象地址赋值给父类类型引用变量。多态的体现。多态中成员方法的特点分析:【子类有,父类没有】编译失败!!!worker.startWork(); 为什么编译不通过呢?提示:找不到符号。因为引用变量worker是Person...
  • 曾经实现过将matlab函数编译成dll供Cpp调用,这篇文章的目的是对新增的面向对象的的扩展mwArray进行讲解,matlab很容易和C/C++联合起来使用。以前做过matlab7与c++的混合编程:将matlab函数编译成dll给C++调用,从而...
  • JavaScript学习(四十三)—构造方法创建对象图解和注意事项 一、构造放法创建对象 之所以用构造放法创建对象就是为了解决工厂模式不能识别对象类型的问题。构造放法也可以被称为构造器,他的本质也是一个函数,...
  • 前面几篇博文分别介绍了JAVA的Class文件格式、JVM的类加载机制和JVM的内存模型,这里就索性把java对象的创建过程一并说完,这样java对象的整个创建过程就基本上说明白了(当然你要有基础才能真正看明白)。经常有人问...
  • 1.JNIEnv对象对于本地函数JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj){cout<...如,创建Java类得对象调用Java对象方法,获取Java对象的属性等。JNIEnv的...
  • 1. JNIEnv对象对于本地函数JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj){cout<...如,创建Java类得对象调用Java对象方法,获取Java对象的属性等。JNIEnv...
  • Java对象在内存中的存储结构图解Java对象在内存中的存储结构图解public class TestStudent {public static void main(String[] args) {int n = 10; //栈存储int m = 10; //栈存储Student stu = new Student();//属性...
  • 同时在SparkContent初始化中将创建DAGScheduler和TASKScheduler、SparkEnv对象等,由于选择的是Yarn-Client模式,程序会选择YarnClientClusterScheduler和YarnClientSchedulerBackend; ResourceManager收到请求后,...
  • python教程_小白入门2021/3/17 学习目标 P 164 类方法和静态方法 P 165 图解静态方法和类方法 P 166 单例设计模式 P 167 练习
  •  关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属于某个对象的。也就是说,既然属于类,就可以不靠创建对象调用了 1.2 定义和使用格式  当 static 修饰...
  • 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。动态获取类中信息,就是java反射 。可以理解为对类的解剖。反射机制图解说明:先...
  • 调用map集合方法entrySet()将集合中的映射关系对象,存储到Set集合(Set >) 2.遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象 3.通过键值对(Entry)对象方法 getKet, getValue,获取Entry对象...
  • 小的总结:再来看这条语句:Person worker = new Worker(): 多态,父类引用指向子类对象。跟这句代码的作用是一样的,Worker w = new Worker(); Person worker = w; 就是子类的引用传给父类类型的引用。向上转型,...
  • 方法声明过程中往往我们需要声明很多方法,并进行方法名标识符的定义,但是有时多个方法功能相似,参数不同这个时候就可以使用方法的重载,将多个方法名称标识符设置相同(不用起很多名字了) 1.3 重载实例 重载的...
  • 1 - 方法的重载(over load)/** 1-方法的重载(over load)* ①概念:在同一个类中,允许存在...调用时,根据方法参数列表的不同来区别。** ③总结:"两同一不同" 即同一个类,相同的方法名。参数列表不同:参数个数不...
  • 一、面向对象思想 1.1 面向对象思想概述 概述 Java语言是一种面向对象...它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。 举例 洗衣服: 面向过程:把衣服脱下来–&g
  • 对于类方法(也就是静态方法),方法参数从下标 0 开始,对于对象方法,位置0保留为 this。 有下面这些局部变量: 1、boolean 2、byte 3、char 4、long 5、short 6、int 7、float 8、double 9、reference(对象引用...
  • 基本要点:程序中储存的所有数据都是对象(可变对象:值可以修改 不可变对象:值不可修改)每个对象都有一个身份、一个类型、一个值例:>>> a1 = 'abc'>>> type(a1)str创建一个字符串对象,其身份是...
  • python 类与对象解析

    2021-03-06 20:20:02
    类成员:# 字段- 普通字段,保存在对象中,执行只能通过对象访问- 静态字段,保存在类中, 执行 可以通过对象访问 也可以通过类访问# 方法- 普通方法,保存在类中,由对象调用,self=》对象- 静态方法,保存在类中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,446
精华内容 12,978
关键字:

对象调用方法图解