分类: java

  • mybatis中foreach使用

    一、foreach 属性使用

    <foreach collection="list" index="index" item="mchntCd" open="(" close=")" separator=",">
       #{mchntCd}
    </foreach>
    
    1. item:  集合中元素迭代时的别名,该参数为必选,通过别名进行取值
    2. index:在list和数组中,index是元素的序号,在map中,index是元素的key,非必填
    3. open: foreach代码的开始符号,一般是(和close=”)”合用。常用在in(),values()时。非必填
    4. separator:元素之间的分隔符,例如在in()的时候,separator=”,”会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。非必填
    5. close: foreach代码的关闭符号,一般是)和open=”(“合用。常用在in(),values()时。非必填
    6. collection: 要做foreach的对象,作为入参
      1. 传入是集合,也就是接口里面用的  List<String> nameList    那么 使用 collection = “list”
      2. 传入的是数组,接口里面 String[] namestrs ,那么 使用 collection = “array”
      3. 如果传入的是一个实体bean,实体bean里面有一个属性为 list<String> ids 那么collection = “ids ”,如果实体bean中对应ids是一个对象,ids 里面有一个属性为 List<Stirng> usernames,那么collection = “ids.usernames”

    二、代码使用

            1、实体类 list<String>  mchntCds
     mapper接口  —》 list方式
    int queryDiscDerateCount
    (List<String> mchntCds);
    mapper映射xml
    1. <select id=“queryDiscDerateCount” resultType=“Integer”>
    2. select count (*) from t_mchnt_disc_config where mchnt_cd in
    3. <foreach collection=“list” index=“index” item=“mchntCd” open=“(“ close=“)” separator=“,”>
    4. #{mchntCd}
    5. </foreach>
    6. </select>
     
       2、实体类 list<User>  userlist,实体类中有 list 属性
    实体类:
    1. @Data
    2. public class MchntDiscDerateDto {
    3. private String mchntCd = “”;
    4. }
    mapper接口
    
    List<TMchntDerateInfoDto> getDiscDerateList
    (List<MchntDiscDerateDto> discDto);
      mapper映射xml:
    1. <select id=“getDiscDerateList” parameterType=“MchntDiscDerateDto” resultType=“TMchntDerateInfoDto”>
    2. select
    3. t_mchnt_disc_derate_config
    4. where
    5. mchnt_cd in
    6. <foreach collection=“list” index=“index” item=“user” open=“(“ close=“)” separator=“,”>
    7. #{user.mchntCd}
    8. </foreach>
    9. </select>
     
    3、数组  String[] params      用 array
    mapper 接口  
    int queryDiscDerateCount
    (String[] mchntCds);
      mapper映射xml:
    1. <select id=“queryDiscDerateCount” resultType=“Integer”>
    2. select count (*) from t_mchnt_disc_derate_config where mchnt_cd in
    3. <foreach collection=“array” index=“index” item=“mchntCd” open=“(“ close=“)” separator=“,”>
    4. #{mchntCd}
    5. </foreach>
    6. </select>
     
    4、传入的参数是实体类,并且实体中包含数组和集合
    实体类:
    1. @Data
    2. public class UserVo {
    3. private Long id;
    4. private Long supplierId;
    5. private Long[] ids;
    6. private List<Long> clientIdList;
    7. }
    mapper接口
    List<UserVo> queryList
    (UserVo select);
    mapper映射文件xml
    1. <select id=“queryList” resultType=“UserVo” parameterType=“UserVo”>
    2. select *
    3. from bms_bills_memo
    4. <where>
    5. and id in
    6. <foreach collection=“ids” open=“(“ close=“)” item=“id” separator=“,”>
    7. #{id}
    8. </foreach>
    9. and
    10. client_id in
    11. <foreach collection=“clientIdList” separator=“,” item=“detail” open=“(“ close=“)” >
    12. #{detail}
    13. </foreach>
    14. </where>
    15. </select>
     
    5、传入多个list或者array,不使用实体进行封装。用注解@Params, collection使用到Param中定义的别名
    mapper接口
    List<UserVo> queryList
    (@Param("idArray") Long[] array, @Param("clientIdList") List<Long> list);
    mapper映射文件xml
    1. <select id=“queryList” resultType=“UserVo”>
    2. select *
    3. from t_user_inf
    4. <where>
    5. and id in
    6. <foreach collection=“idArray” open=“(“ close=“)” item=“id” separator=“,”>
    7. #{id}
    8. </foreach>
    9. and
    10. client_id in
    11. <foreach collection=“clientIdList” separator=“,” item=“detail” open=“(“ close=“)” >
    12. #{detail}
    13. </foreach>
    14. </where>
    15. </select>

     

    6、map参数
    当我们传入的参数为 Map<String,Objject>的时候,那么能不能正常使用 foreach呢,答案是肯定的,因为对象也是类似于map结构啊
    1. /**
    2. * map 获取数据
    3. * @param map
    4. * @return
    5. */
    6. List<SysUser> getUserByIds (Map<String,Object> map);
    1. // xml
    2. <select id=“getUserByIds” resultMap=“BaseResultMap”>
    3. select
    4. <include refid=“Base_Column_List” />
    5. from t_sys_user
    6. where status = #{status}
    7. and id in
    8. <foreach collection=“ids” item=“id” open=“(“ close=“)” separator=“,”>
    9. #{id}
    10. </foreach>
    11. </select>

    实际调用:

    1. @Test
    2. public void testMapUsers() {
    3. Map<String,Object> params = new HashMap<>();
    4. params.put(“status”, “1”);
    5. params.put(“ids”, Arrays.asList(1,2,3,4,5,6,7,8));
    6. List<SysUser> all = sysUserDao.getUserByIds(params);
    7. try {
    8. System.out.println(new JsonMapper().writeValueAsString(all));
    9. } catch (JsonProcessingException e) {
    10. e.printStackTrace();
    11. }
    12. }

    调用结果:

    三、总结

    1、mapper 接口中添加 @Param注解的场合,list,array将会失效;

    2、使用了 @Param注解 collection的内容需要使用Param中的别名来指定你需要用到的list或者array

  • IDEA中JS文件中文乱码

    521f7e8e3ee6fc0e8776946b15e1102f e33dce9c87ad4a54872f1ecdb9d4b35b

    开始我以为是导入的js文件没有设置编码的原因然后我加上charset=UTF-8,但是没有起作用,后我又以为是jsp文件编码的原因,于是我又加上了pageEncoding="utf-8",任然没有起作用。

    几次反思后我觉得可能问题出现在我用的开发工具IDEA上,网上查阅资料后找到问题了。

    一、设置全局和项目编码

    222b878f23f59693e1b35e09ab4e7765 83b8c1c582d3e083ec804ebd1a262967

    二、设置Tomcat启动项目用到的VM options

    f48c268e7f043df8b7c1c6259eafd5af 83c394bbefcc59f91102305b4e4e3654

    修改完后重启项目

  • 道设计模式面试题总结(含答案解析和思维导图)

    Q1:设计模式有哪些原则?

    开闭原则:OOP 中最基础的原则,指一个软件实体(类、模块、方法等)应该对扩展开放,对修改关闭。强调用抽象构建框架,用实现扩展细节,提高代码的可复用性和可维护性。

    单一职责原则:一个类、接口或方法只负责一个职责,降低代码复杂度以及变更引起的风险。

    依赖倒置原则:程序应该依赖于抽象类或接口,而不是具体的实现类。

    接口隔离原则:将不同功能定义在不同接口中实现接口隔离,避免了类依赖它不需要的接口,减少了接口之间依赖的冗余性和复杂性。

    里氏替换原则:开闭原则的补充,规定了任何父类可以出现的地方子类都一定可以出现,可以约束继承泛滥,加强程序健壮性。

    迪米特原则:也叫最少知道原则,每个模块对其他模块都要尽可能少地了解和依赖,降低代码耦合度。

    合成/聚合原则:尽量使用组合(has-a)/聚合(contains-a)而不是继承(is-a)达到软件复用的目的,避免滥用继承带来的方法污染和方法爆炸,方法污染指父类的行为通过继承传递给子类,但子类并不具备执行此行为的能力;方法爆炸指继承树不断扩大,底层类拥有的方法过于繁杂,导致很容易选择错误。


    Q2:设计模式的分类,你知道哪些设计模式?

    创建型: 在创建对象的同时隐藏创建逻辑,不使用 new 直接实例化对象,程序在判断需要创建哪些对象时更灵活。包括工厂/抽象工厂/单例/建造者/原型模式。

    结构型: 通过类和接口间的继承和引用实现创建复杂结构的对象。包括适配器/桥接模式/过滤器/组合/装饰器/外观/享元/代理模式。

    行为型: 通过类之间不同通信方式实现不同行为。包括责任链/命名/解释器/迭代器/中介者/备忘录/观察者/状态/策略/模板/访问者模式。


    Q3:说一说简单工厂模式

    简单工厂模式指由一个工厂对象来创建实例,客户端不需要关注创建逻辑,只需提供传入工厂的参数。

    适用于工厂类负责创建对象较少的情况,缺点是如果要增加新产品,就需要修改工厂类的判断逻辑,违背开闭原则,且产品多的话会使工厂类比较复杂。

    Calendar 抽象类的 getInstance 方法,调用 createCalendar 方法根据不同的地区参数创建不同的日历对象。

    Spring 中的 BeanFactory 使用简单工厂模式,根据传入一个唯一的标识来获得 Bean 对象。


    Q4:说一说工厂方法模式

    工厂方法模式指定义一个创建对象的接口,让接口的实现类决定创建哪种对象,让类的实例化推迟到子类中进行。

    客户端只需关心对应工厂而无需关心创建细节,主要解决了产品扩展的问题,在简单工厂模式中如果产品种类变多,工厂的职责会越来越多,不便于维护。

    Collection 接口这个抽象工厂中定义了一个抽象的 iterator 工厂方法,返回一个 Iterator 类的抽象产品。该方法通过 ArrayList 、HashMap 等具体工厂实现,返回 Itr、KeyIterator 等具体产品。

    Spring 的 FactoryBean 接口的 getObject 方法也是工厂方法。


    Q5:抽象工厂模式了解吗?

    抽象工厂模式指提供一个创建一系列相关或相互依赖对象的接口,无需指定它们的具体类。

    客户端不依赖于产品类实例如何被创建和实现的细节,主要用于系统的产品有多于一个的产品族,而系统只消费其中某一个产品族产品的情况。抽象工厂模式的缺点是不方便扩展产品族,并且增加了系统的抽象性和理解难度。

    java.sql.Connection 接口就是一个抽象工厂,其中包括很多抽象产品如 Statement、Blob、Savepoint 等。


    Q6:单例模式的特点是什么?

    单例模式属于创建型模式,一个单例类在任何情况下都只存在一个实例,构造方法必须是私有的、由自己创建一个静态变量存储实例,对外提供一个静态公有方法获取实例。

    优点是内存中只有一个实例,减少了开销,尤其是频繁创建和销毁实例的情况下并且可以避免对资源的多重占用。缺点是没有抽象层,难以扩展,与单一职责原则冲突。

    Spring 的 ApplicationContext 创建的 Bean 实例都是单例对象,还有 ServletContext、数据库连接池等也都是单例模式。

    Q7:单例模式有哪些实现?

    饿汉式:在类加载时就初始化创建单例对象,线程安全,但不管是否使用都创建对象可能会浪费内存。

    public class HungrySingleton {
        private HungrySingleton(){}
    
        private static HungrySingleton instance = new HungrySingleton();
    
        public static HungrySingleton getInstance() {
            return instance;
        }
    }

    懒汉式:在外部调用时才会加载,线程不安全,可以加锁保证线程安全但效率低。

    public class LazySingleton {
        private LazySingleton(){}
    
        private static LazySingleton instance;
    
        public static LazySingleton getInstance() {
            if(instance == null) {
                instance = new LazySingleton();
            }
            return instance;
        }
    }

    双重检查锁:使用 volatile 以及多重检查来减小锁范围,提升效率。

    public class DoubleCheckSingleton {
        private DoubleCheckSingleton(){}
    
        private volatile static DoubleCheckSingleton instance;
    
        public static DoubleCheckSingleton getInstance() {
            if(instance == null) {
                synchronized (DoubleCheckSingleton.class) {
                    if (instance == null) {
                        instance = new DoubleCheckSingleton();
                    }
                }
            }
            return instance;
        }
    }

    静态内部类:同时解决饿汉式的内存浪费问题和懒汉式的线程安全问题。

    public class StaticSingleton {
        private StaticSingleton(){}
    
        public static StaticSingleton getInstance() {
            return StaticClass.instance;
        }
    
        private static class StaticClass {
            private static final StaticSingleton instance = new StaticSingleton();
        }
    }

    枚举:《Effective Java》提倡的方式,不仅能避免线程安全问题,还能防止反序列化重新创建新的对象,绝对防止多次实例化,也能防止反射破解单例的问题。

    public enum EnumSingleton {
        INSTANCE;
    }

    Q8:讲一讲代理模式

    代理模式属于结构型模式,为其他对象提供一种代理以控制对这个对象的访问。优点是可以增强目标对象的功能,降低代码耦合度,扩展性好。缺点是在客户端和目标对象之间增加代理对象会导致请求处理速度变慢,增加系统复杂度。

    Spring 利用动态代理实现 AOP,如果 Bean 实现了接口就使用 JDK 代理,否则使用 CGLib 代理。

    静态代理:代理对象持有被代理对象的引用,调用代理对象方法时也会调用被代理对象的方法,但是会在被代理对象方法的前后增加其他逻辑。需要手动完成,在程序运行前就已经存在代理类的字节码文件,代理类和被代理类的关系在运行前就已经确定了。 缺点是一个代理类只能为一个目标服务,如果要服务多种类型会增加工作量。

    动态代理:动态代理在程序运行时通过反射创建具体的代理类,代理类和被代理类的关系在运行前是不确定的。动态代理的适用性更强,主要分为 JDK 动态代理和 CGLib 动态代理。

    • JDK 动态代理:通过 Proxy 类的 newInstance 方法获取一个动态代理对象,需要传入三个参数,被代理对象的类加载器、被代理对象实现的接口,以及一个 InvocationHandler 调用处理器来指明具体的逻辑,相比静态代理的优势是接口中声明的所有方法都被转移到 InvocationHandler 的 invoke 方法集中处理。
    • CGLib 动态代理:JDK 动态代理要求实现被代理对象的接口,而 CGLib 要求继承被代理对象,如果一个类是 final 类则不能使用 CGLib 代理。两种代理都在运行期生成字节码,JDK 动态代理直接写字节码,而 CGLib 动态代理使用 ASM 框架写字节码,ASM 的目的是生成、转换和分析以字节数组表示的已编译 Java 类。 JDK 动态代理调用代理方法通过反射机制实现,而 GCLib 动态代理通过 FastClass 机制直接调用方法,它为代理类和被代理类各生成一个类,该类为代理类和被代理类的方法分配一个 int 参数,调用方法时可以直接定位,因此调用效率更高。

    Q9:讲一讲装饰器模式

    装饰器模式属于结构型模式,在不改变原有对象的基础上将功能附加到对象,相比继承可以更加灵活地扩展原有对象的功能。

    装饰器模式适合的场景:在不想增加很多子类的前提下扩展一个类的功能。

    java.io 包中,InputStream 字节输入流通过装饰器 BufferedInputStream 增强为缓冲字节输入流。


    Q10:装饰器模式和动态代理的区别?

    装饰器模式的关注点在于给对象动态添加方法,而动态代理更注重对象的访问控制。动态代理通常会在代理类中创建被代理对象的实例,而装饰器模式会将装饰者作为构造方法的参数。


    Q11:讲一讲适配器模式

    适配器模式属于结构型模式,它作为两个不兼容接口之间的桥梁,结合了两个独立接口的功能,将一个类的接口转换成另外一个接口使得原本由于接口不兼容而不能一起工作的类可以一起工作。

    缺点是过多使用适配器会让系统非常混乱,不易整体把握。

    java.io 包中,InputStream 字节输入流通过适配器 InputStreamReader 转换为 Reader 字符输入流。

    Spring MVC 中的 HandlerAdapter,由于 handler 有很多种形式,包括 Controller、HttpRequestHandler、Servlet 等,但调用方式又是确定的,因此需要适配器来进行处理,根据适配规则调用 handle 方法。

    Arrays.asList 方法,将数组转换为对应的集合(注意不能使用修改集合的方法,因为返回的 ArrayList 是 Arrays 的一个内部类)。


    Q12:适配器模式和和装饰器模式以及代理模式的区别?

    适配器模式没有层级关系,适配器和被适配者没有必然连续,满足 has-a 的关系,解决不兼容的问题,是一种后置考虑。

    装饰器模式具有层级关系,装饰器与被装饰者实现同一个接口,满足 is-a 的关系,注重覆盖和扩展,是一种前置考虑。

    适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。


    Q13:讲一讲策略模式

    策略模式属于行为型模式,定义了一系列算法并封装起来,之间可以互相替换。策略模式主要解决在有多种算法相似的情况下,使用 if/else 所带来的难以维护。

    优点是算法可以自由切换,可以避免使用多重条件判断并且扩展性良好,缺点是策略类会增多并且所有策略类都需要对外暴露。

    在集合框架中,经常需要通过构造方法传入一个比较器 Comparator 进行比较排序。Comparator 就是一个抽象策略,一个类通过实现该接口并重写 compare 方法成为具体策略类。

    创建线程池时,需要传入拒绝策略,当创建新线程使当前运行的线程数超过 maximumPoolSize 时会使用相应的拒绝策略处理。


    Q14:讲一讲模板模式

    模板模式属于行为型模式,使子类可以在不改变算法结构的情况下重新定义算法的某些步骤,适用于抽取子类重复代码到公共父类。

    优点是可以封装固定不变的部分,扩展可变的部分。缺点是每一个不同实现都需要一个子类维护,会增加类的数量。

    为防止恶意操作,一般模板方法都以 final 修饰。

    HttpServlet 定义了一套处理 HTTP 请求的模板,service 方法为模板方法,定义了处理HTTP请求的基本流程,doXXX 等方法为基本方法,根据请求方法的类型做相应的处理,子类可重写这些方法。


    Q15:讲一讲观察者模式

    观察者模式属于行为型模式,也叫发布订阅模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。主要解决一个对象状态改变给其他对象通知的问题,缺点是如果被观察者对象有很多的直接和间接观察者的话通知很耗时, 如果存在循环依赖的话可能导致系统崩溃,另外观察者无法知道目标对象具体是怎么发生变化的。

    ServletContextListener 能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用。当 Servlet 容器启动 Web 应用时调用 contextInitialized 方法,终止时调用 contextDestroyed 方法。

  • dubbo 设置注册到注册中心的IP地址为公网IP

    场景
    某些情况下(例如公共测试环境 xx云上ECS 部署了dubbo提供者),
    我们需要将dubbo提供者应用 注册到注册中心的地址为公网ip地址。

    这样方便公司内网或者其他云上应用调用该dubbo提供者的接口服务。

    测试
    dubbo 版本 2.7.8

    查看 dubbo 官方文档,一开始以为 修改属性 dubbo.protocol.host

    # 服务提供者协议配置。对应的配置类: org.apache.dubbo.config.ProtocolConfig。
    # 同时,如果需要支持多协议,可以声明多个 标签,并在 中通过 protocol 属性指定使用的协议。
    protocol:
    name: dubbo
    port: 20207
    host: 8.17.29.89
    1
    2
    3
    4
    5
    6
    上面的 8.17.29.89 是 xx云 ECS 绑定的 弹性公网ip , 然而启动报错:

    org.apache.dubbo.rpc.RpcException: Fail to start server(url: dubbo://8.17.29.89:20207/com.middol.zentao.rpc.jar.ZenTaoAggregationService?anyhost=false&application=zentao-rpc-api&bind.ip=192.168.6.51&bind.port=20207&channel.readonly.sent=true&codec=dubbo&deprecated=false&document=%E7%A6%85%E9%81%93rpc%E6%8E%A5%E5%8F%A3&dubbo=2.0.2&dynamic=true&generic=false&heartbeat=60000&interface=com.middol.zentao.rpc.jar.ZenTaoAggregationService&logger=slf4j&metadata-type=remote&methods=taskInfoList,getById,getUser,bugInfoList,getZenTaoEmployeesLogs,getProductStatistics,getPersonStatistics&pid=21676&qos.accept.foreign.ip=false&qos.enable=true&qos.port=33307&release=2.7.8&revision=1.0-SNAPSHOT&side=provider&timestamp=1627035267274&version=1.0) Failed to bind NettyServer on /192.168.6.51:20207, cause: Cannot assign requested address: bind
    at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.createServer(DubboProtocol.java:348) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.openServer(DubboProtocol.java:320) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.export(DubboProtocol.java:303) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper.export(ProtocolListenerWrapper.java:64) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.export(ProtocolFilterWrapper.java:155) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.qos.protocol.QosProtocolWrapper.export(QosProtocolWrapper.java:66) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.Protocol$Adaptive.export(Protocol$Adaptive.java) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.registry.integration.RegistryProtocol.lambda$doLocalExport$2(RegistryProtocol.java:255) ~[dubbo-2.7.8.jar:2.7.8]
    at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_151]
    at org.apache.dubbo.registry.integration.RegistryProtocol.doLocalExport(RegistryProtocol.java:253) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.registry.integration.RegistryProtocol.export(RegistryProtocol.java:205) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper.export(ProtocolListenerWrapper.java:62) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper.export(ProtocolFilterWrapper.java:153) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.qos.protocol.QosProtocolWrapper.export(QosProtocolWrapper.java:64) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.Protocol$Adaptive.export(Protocol$Adaptive.java) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol(ServiceConfig.java:492) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:325) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:300) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:206) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.bootstrap.DubboBootstrap.lambda$exportServices$15(DubboBootstrap.java:1103) ~[dubbo-2.7.8.jar:2.7.8]
    at java.util.HashMap$Values.forEach(HashMap.java:981) ~[na:1.8.0_151]
    at org.apache.dubbo.config.bootstrap.DubboBootstrap.exportServices(DubboBootstrap.java:1090) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:901) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener.onContextRefreshedEvent(DubboBootstrapApplicationListener.java:59) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener.onApplicationContextEvent(DubboBootstrapApplicationListener.java:52) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.config.spring.context.OneTimeExecutionApplicationContextEventListener.onApplicationEvent(OneTimeExecutionApplicationContextEventListener.java:40) ~[dubbo-2.7.8.jar:2.7.8]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:898) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554) ~[spring-context-5.2.12.RELEASE.jar:5.2.12.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.3.8.RELEASE.jar:2.3.8.RELEASE]
    at com.middol.zentao.rpc.Application.main(Application.java:37) [classes/:na]
    Caused by: org.apache.dubbo.remoting.RemotingException: Failed to bind NettyServer on /192.168.6.51:20207, cause: Cannot assign requested address: bind
    at org.apache.dubbo.remoting.transport.AbstractServer.(AbstractServer.java:77) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.remoting.transport.netty4.NettyServer.(NettyServer.java:77) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.remoting.transport.netty4.NettyTransporter.bind(NettyTransporter.java:35) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.remoting.Transporter$Adaptive.bind(Transporter$Adaptive.java) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.remoting.Transporters.bind(Transporters.java:56) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger.bind(HeaderExchanger.java:44) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.remoting.exchange.Exchangers.bind(Exchangers.java:70) ~[dubbo-2.7.8.jar:2.7.8]
    at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.createServer(DubboProtocol.java:346) ~[dubbo-2.7.8.jar:2.7.8]
    … 40 common frames omitted
    Caused by: java.net.BindException: Cannot assign requested address: bind
    at sun.nio.ch.Net.bind0(Native Method) ~[na:1.8.0_151]

    查看官方文档,debug 源码,知道 host的含义:

    在 Dubbo 中, Provider 启动时主要做两个事情,
    一是启动 server
    二是向注册中心注册服务。
    启动 server 时需要绑定 socket,
    向注册中心注册服务时也需要发送 socket 唯一标识服务地址

    报错无法启动 server Cannot assign requested address: bind, 其实是socket无法启动,socket端口外网无法连接, 理由是 如果服务端套接字绑定在它上面,你的客户端程序就只能在本机访问。

    这里面 暂不讨论源码,总之配置文件中 (dubbo.protocol 或 dubbo.provider 的 host)的host属性,如果要配置 必须配置本机的ip (内网ip 或者 127.0.0.1 或者 不配dubbo自己获取)

    解决
    网上 或者 文档中有几个方法,修改hosts之类的, 我个人解决方法推荐:

    设置 java 系统参数( -Dxxx=value) -DDUBBO_IP_TO_REGISTRY=“8.17.29.89”
    如果是 springboot 可以这样:

    java -jar myDubboRpc-api.jar -DDUBBO_IP_TO_REGISTRY=”8.17.29.89″
    1
    当然 也可以事先 将 DUBBO_IP_TO_REGISTRY 这个参数设置到系统环境变量里面。

    如果是docker 方式,请参考 : https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-docker

    其实就是docker 启动时候指定环境变量 -e DUBBO_IP_TO_REGISTRY = “8.17.29.89”
    ————————————————
    版权声明:本文为CSDN博主「小时候的阳光」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/gzt19881123/article/details/119042064

  • java中逗号分隔的字符串和List相互转换

    1、将逗号分隔的字符串转换为List

    String str = "a,b,c"; 
    
    List<String> result = Arrays.asList(str.split(","));

    2、将List转换为逗号分隔的字符串

    (1) 利用Guava的Joiner

    List<String> list = new ArrayList<String>(); 
    list.add("a"); 
    list.add("b"); 
    list.add("c"); 
    
    String str = Joiner.on(",").join(list); 

    (2)利用Apache Commons的StringUtils

    List<String> list = new ArrayList<String>(); 
    list.add("a"); 
    list.add("b"); 
    list.add("c"); 
    
    String str = StringUtils.join(list.toArray(), ",");