SpringBoot 事件发布监听机制使用、分析、注意点 (一篇到位)

2023-11-13

前言

这一篇从应用角度来跟大伙讲讲 这个 spring 事件监听机制 ,顺便涉及到那些我认为大家应该一块了解的,我也会展开说说。

文章内容(包括不限于) :

1. 对比观察者模式

2. 应用场景的分析

3. 事件的创建 编码介绍

4. 事件如何 发出

5. 事件如何 被接收处理 

6. 同步方式、异步方式 的整合

7. 使用注解方式和不使用注解

8. 多事件监听器执行顺序的设置

9. 源码浅析

10. 一些跑题杂谈

ps:上面列的这些,在本文章里面没有严格的顺序, 我控制不住自己的跑题。

我介绍码字的同时,就当作是跟大伙聊天一样,所以有些话可能比较小白文,不喜勿喷。

正文

第一开头我就想吐槽,

其实文章的标题是有误的, 应该是 Spring的容器的事件发布监听机制。

但是为什么我要这样起标题呢,鉴于我最近一些日子去给一些学弟讲一些也是有关ssm的或者说是spring的一些知识, 他们好像有点抵触这些 他们认为的 ‘老知识’,反而我把PPT标题或者课题改一下,是springboot开头,他们会变得兴趣大一些。 

我在想, 要是想让初学者也能玩明白这个事件发布监听机制 ,我认为很有必要先去普及一下 观察者模式,当然我也不会非常深入去介绍观察者模式(可能也没得有很深入的东西)

那么我就画一张图,先给大伙了解下  观察者模式(看起来乱,但是井井有序) :

大家可以结合这段小白文描述去 了解观察者模式 :

1.  观察者 和 被观察者  是  1 对 多 方式  。(小华被 好几个人 盯着)

2.  观察者 需要让 被观察者 知道 自己是参与观察他的人 。 (小华其实提供了登记列表途径, 小蓝、小黄、小橙 其实都有通过这个途径 留下了自己的联系号码 update方法)

3.  被观察者 小华,有台大哥大手机(notify方法 )专门打给 这些观察者 。  (小华的业务方法里面会 调用 这个notify方法)

4.  大哥大 从登记列表 里面  循环一个个地通知了 小蓝、小黄、小橙 , 他们接到通知,就开始调用自己的业务方法 进行处理。
 

看到这,再看一副更加简单的描述图,这一下子已经从深入到浅出了:
 

 

接下来,有了观察者设计模式的一定了解之后,我们直接再看一张浅出图 ,spring事件发布监听机制的图:

其实,大家一直都说的观察者设计 模式, 很多情况就是被叫做 发布-订阅设计模式。

但是你说它们是不是完全一致嘛, 不完全 ,但是实现的模式讲真是一致的。

一个主动变化的人 ,一个 等待通知跟着 做出变化的人 。

而对于 所谓的调度中心,只是把这两者的交流交互给 抽离出来罢了。

甚至很多框架里面对于这个调度中心的设计实现都是隐藏的,我们甚至没有感觉到有这个调度中心的存在 。

因为怎么去处理 这两者的一来一回的微妙依赖关系, 不同的人也许也是有不同的设计思路的。

(甚至我们理解玩观察者模式的流程细节,我们自己也可尝试地去 实现 我们自己的一个观察者模式/发布订阅模式,不基于java提供的观察者相关类 ,不基于spring提供的事件发布订阅 等,自己可以做个小挑战,当然大牛已经设计封装出来的东西,肯定是非常优秀的了,有没有必要自己再重造轮子,大家心里有自己的答案 )。

啰唆了很多, 我们一起从业务示例场景去更近一步 玩一下 spring的 事件发布监听机制 。

业务场景:

这是一个游戏公司,我们这个示例需求 是 有关于充值相关的 增强用户体验的 需求。

玩家给 游戏账号充值买礼包了 , 我们需要在充钱成功后,

通过短信 给玩家的手机发送一个通知, 给他 通知一下,让他知道钱花了。 

产品 说 你快去设计一下做吧。

开发小明 找到 原先的 充值方法 ,在后面加了个发短信

写完,提测,上线 :

    public void recharge(){

        //充值氪金处理............

        //然后
        sendSms(String phone);
    }


不到2天, 玩家开始反馈,短信很多收不到,被手机拦截了,麻烦,但是又想知道充值的信息;

账号是绑定过邮箱的,能不能也发个邮件。

产品 :  加个发邮件 。 

开发小明  又去改代码了,找到了  充值方法  里面在发短信后面,加了个发邮件 。

开发写完,提测,上线 :

    public void recharge(){

        //充值氪金处理............

        //然后
        sendSms(String phone);
        sendEmail(String email);
    }


第二天,产品又说,玩家充钱欲望不够, 我们给他们说了,买不同礼包,赠送的积分不同,越贵的,送的积分多多。 积分后面可以兑换 小礼品。 

产品 :  加积分!

开发小明  又去改代码了,找到了 充值方法   里面在发邮件 后面 又加了 个 加积分。

    public void recharge(){

        //充值氪金处理............

        //然后
        sendSms(String phone);
        sendEmail(String email);
        addScore(Integer accountId);
    }

上面说的场景 是非常常见的, 需求出现一步步叠加是很正常的。 

开发因为需求变化,频繁改代码,其实也是很正常的。 

但是怎么改, 这一点, 是讲究的, 是根据我们设计的考虑而去决定 改动的方式的 。

上面这个业务场景例子,可以看到, 小明一直去改。

但是改在哪? 改的是充值的方法 。 

充值变了吗? 其实没变 。 变的是充值后 的一些 业务。

所以本身 小明在写设计这个充值接口的时候,把充值后的一些额外业务都混在一块,

已经 有违 单一职责的原则了。

而频繁去改 充值接口 ,因为别的业务去改 充值接口方法 ,

那么 也有违 充值接口方法的  开闭原则。

而且,这还好全是小明自己一个人写的代码 ,如果说不单是小明一个人,充值接口是 小花写的。

你改自己的充值后的需求,天天改人家小花的充值接口实现代码。

小花都天天提心吊胆的, 生怕被你 改多了几行,每次上线发版,项目经理说,这次有关的版本上线有关人员需要留下来, 有 负责充值的小花, 负责 充值后提升用户体验的 小明。

你说,小花什么感受,直接就EMO了。

这时候,可能有很多看官已经想到了解决方案了 ,就是 让小明写一个 充值后调用的方法(里面囊括 发短信、发邮件、加积分等等甚至应对以后的扩展), 小花那边 充值之后 只需要调用一下 这个方法即可。

也就是:

    public void recharge(){
        //充值氪金处理............

        //然后
        afterRecharge();
    }


    public void afterRecharge(){
        
        sendSms(String phone);
        sendEmail(String email);
        addScore(Integer accountId);
    }

乍一看好像ok的, 但是其实还是未能完全解耦。 

如果业务扩展起来了,

小明认为 发短信、发邮箱 属于调用消息中心的方法, 应该分出一个sendNotice方法;

然后加积分、加经验等游戏账号体系相关的, 应该 分出一个 xxx 方法 。

这两部分已经分开设计了,小花只需要分别调用就可以,没必要在外面套一层。因为这两个方法之间也不存在任何相关连。短信不发,积分也是要加的。

但是小花可能就不同意了,不止小花,可能调用 afterRecharge 方法的人,还有小曼,小路,小玲等等。 这么多人,很难一个个让他们改。

可能例子举的比较极端,放大了问题点。 

其实这就是 解耦彻底的问题。 如果我们使用事件发布监听机制, 可以更优美地去应对这些场景。

事件发布监听机制 :

充值完 , 发布一个事件 。

小明自己去监听这个 充值完的事件, 写自己的 订阅者, 不管是写一个还是多个,可以自己拿捏。

单独发短信一个 监听器 A ;

单独发邮件一个 监听器 B;

单独 处理加积分等 一个监听器 C;

甚至把 AB 整合一个监听器, C单独一个 。

可以说是 开发自由,后面产品怎么提这些充值后的业务需求, 小花都不几乎不用参与。

就找小明就行, 小明也舒服 。

因为他 实现了 以增量的设计方式去 应对 这些变化多端的 需求 。

ok,事不宜迟,啰唆了这么多, 我们看看spring事件发布订阅的代码的简单实现:

(如果你是为了想找实现例子的,看到这估计也不容易,大多数应该早就退出了) 

1. 创建充值事件,充值成功就发布这个事件 :

RechargeChangeEvent.java 

里面包含充值的礼包活动id ;

包含用户游戏账号一些相关的信息(举例就随便写个User类了);

/**
 * @Author JCccc
 * @Description
 * @Date 2020/10/12 9:08
 */
public class RechargeChangeEvent extends ApplicationEvent {

    private Integer giftActivityId;

    private User user;


    public RechargeChangeEvent(Object source, Integer giftActivityId,User user) {
        super(source);
        this.giftActivityId = giftActivityId;
        this.user = user;
    }

    public Integer getGiftActivityId() {
        return giftActivityId;
    }

    public void setGiftActivityId(Integer giftActivityId) {
        this.giftActivityId = giftActivityId;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

稍作讲解:

2. 发短信 监听器   :

SmsListener.java

/**
 * @Author JCccc
 * @Description
 * @Date 2020/10/12 9:08
 */
@Component
public class SmsListener implements SmsService, ApplicationListener<RechargeChangeEvent> {
    @Override
    public void sendSms(String phone) {
        System.out.println("发送短信 成功");
    }

    @Override
    public void onApplicationEvent(RechargeChangeEvent event) {
        System.out.println("-------------------------------");
        Integer giftActivityId = event.getGiftActivityId();

        System.out.println("参与礼包活动id "+giftActivityId+" ,处理短信相关业务 , 获取短信签名等。。。。");

        String phone = event.getUser().getPhone();
        sendSms(phone);

    }
}

稍作讲解: 

 ps: @Component 记得别忘记了,这实现的,继承的用的都是spring里面的。我们自己的自定义监听器那肯定也得丢里头了。 当然图里面的多实现不是一定要这么写的,如果你的监听业务非常特殊,完全可以单独封装一个方法写在对应监听器里面。

3. 发邮件 监听器 

EmailListener.java

@Component
public class EmailListener implements EmailService, ApplicationListener<RechargeChangeEvent> {
    @Override
    public void sendEmail(String email) {
        System.out.println("发送邮件 成功");
    }

  
    @Override
    public void onApplicationEvent(RechargeChangeEvent event) {
        System.out.println("-------------------------------");

        try {
            sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Integer giftActivityId = event.getGiftActivityId();
        System.out.println("参与礼包活动id "+giftActivityId+" ,处理邮件相关业务 , 进行 A BC等。。。。");
        String email = event.getUser().getEmail();
        sendEmail(email);

    }
}

4. 扩展一些额外的监听器 ,例如加积分、加经验等等 。

上面两个都是采用的 代码实现方式,实现了 ApplicationListener ,那么我们也同时搞点不一样的,我们用注解 @EventListener 玩一下。

可以看到用注解,代码实现非常简洁, 明名上面也不需要强制重写 onApplicationEvent ,

直接自己明名,更加贴切合理,通过事件来给注解标识一下,监听器对应的哪个事件即可。

我支持注解! 从简!

@Component
public class XxxxxListener {

    @EventListener
    public void doXxxxx(RechargeChangeEvent event) {
        System.out.println("-------------------------------");
        Integer giftActivityId = event.getGiftActivityId();
        User user = event.getUser();
        System.out.println("处理Xxxxx业务");
        System.out.println("Xxxxx 成功");
    }
    
}

5. 最后写个模拟接口实现方法,也就是充值方法,里面会发布一个 充值事件:
 

@Service
public class RechargeServiceImpl implements RechargeService {
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void recharge(Integer giftActivityId, User user) {
        System.out.println("给用户"+user.getPhone() +"充值成功;使用的充值礼包系列id :"+giftActivityId);
        // 发布事件通知
        applicationContext.publishEvent(new RechargeChangeEvent(this,giftActivityId,user));
    }
}

6.我们也模拟一个接口,调用充值方法 :
 

7. 使用postman调用一下,看看效果:

可以看到打印顺序,监听器里面的相关代码都成功执行 : 

 

好了 ,spring的 事件发布监听机制的一些使用,到这里也是讲完了 。

但是还没完 !

大家注意到我的打印输出的截图没? 

1. 发邮件那么久, 还真等这么久。

为什么先发邮件,我能先发短信吗?  我能先加积分么? 大家都是监听器,凭什么你先,我就想要固定哪个先,可以? 

2 .再看看我如果在发邮件那里抛个异常:


 可以看到,这spring默认的事件发布监听,是同步机制, 一个出错,后面跟着泡汤!

出现了两个问题(使用需求) :

1.  自定义监听器监听到事件之后,执行的顺序 .

2. 默认同步要会用, 但是我们 也想用 异步 .

解决第一个问题   顺序 问题 :
 

我们把原先自定义继承的监听器 ApplicationListener<RechargeChangeEvent>  换成  SmartApplicationListener :

具体代码 示例 , EmailListener.java :
 

@Component
public class EmailListener implements EmailService, SmartApplicationListener{
    @Override
    public void sendEmail(String email) {
        System.out.println("发送邮件 成功");
    }
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType){
        return eventType == RechargeChangeEvent.class;
    }

    @Override
    public boolean supportsSourceType(Class<?> sourceType){
        return true;
    }
    @Override
    public int getOrder(){
        return -1;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event){
        RechargeChangeEvent rechargeChangeEvent= (RechargeChangeEvent) event;
        System.out.println("-------------------------------");
        try {
            sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Integer giftActivityId = rechargeChangeEvent.getGiftActivityId();
        System.out.println("参与礼包活动id "+giftActivityId+" ,处理邮件相关业务 , 进行 A BC等。。。。");
        String email = rechargeChangeEvent.getUser().getEmail();
        sendEmail(email);
        System.out.println("监听到用户注册,给新用户发送首条站内短消息" + event.toString());
    }

}

可以看到有一个 getOrder 方法 ,邮件监听器我们设置的是   -1  ;

同样 ,SmsListener.java 也改成使用  SmartApplicationListener :

@Component
public class SmsListener implements SmsService, SmartApplicationListener {
    @Override
    public void sendSms(String phone) {
        System.out.println("发送短信 成功");
    }
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType){
        return eventType == RechargeChangeEvent.class;
    }
    @Override
    public boolean supportsSourceType(Class<?> sourceType){
        return true;
    }
    
    @Override
    public int getOrder(){
        return -2;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event){
        RechargeChangeEvent rechargeChangeEvent= (RechargeChangeEvent) event;
        System.out.println("-------------------------------");
        Integer giftActivityId = rechargeChangeEvent.getGiftActivityId();
        System.out.println("参与礼包活动id "+giftActivityId+" ,处理短信相关业务 , 获取短信签名等。。。。");
        String phone = rechargeChangeEvent.getUser().getPhone();
        sendSms(phone);
    }

}

 getOrder 方法 ,我们设置的是   -2   ;

这个order ,谁数值小就执行顺序排越前面。 

ok,我们执行一下, 按照我们设置的顺序,发短信监听器是 -2 ,应该先执行 :

顺序的问题我们已经解决了,但是有没有觉得改动好大,完全换了一个监听器,然后还重写好几个方法,很麻烦 。

所以我们来用第二种方式解决 ,使用注解  @Order() 和  @EventListener

 注解的方式永远是极简的,强烈推荐! 

看看极简使用注解是怎么玩的 :

 

 可以看到,邮件监听设置的顺序 是 -10 , 短信是 -5  :

解决第二个问题   异步 问题 :

其实非常非常简单,基于注解方式 ,我们想要监听器都是多线程异步执行,我们只需要再叠加使用一个注解 @Async , 就像这样:

ps :对于异步注解使用还没了解过的,可以先看看这篇 ,因为使用上是由一些注意点的SpringBoot 最简单的使用异步线程案例 @Async_默默不代表沉默-CSDN博客


 

这样我们启动一下:
 

 这时候会出现一个关于代理的错误:

Either pull the method up to an interface or switch to CGLIB proxies by enforcing proxy-target-class mode in your configuration.

这里又要扯远了,其实是因为我们使用注解 @Async 导致的。 其实在使用一些其他注解也会有遇到这种情况。

可以看到我们的 代码写的情况 :

 

 EmailService 接口的实现类是 EmailListener ;

然后deal方法 加了 注解方法  EventListener和Async 注解的方法;

但是其实EmailService 接口里面是没这个方法的。

此时 EmailListener  被spring使用jdk代码方式生成的类,在收集 注解相关的方法时,是去类的接口中寻找deal方法,找不到,所以就报错了。

在此,分析问题先打住 ,有结论,解决思路有3小种 :

1.我们这个监听器就不要实现接口了。

2. 我们把这个被注解标记的方法 deal 也变成接口里面有的 。

3. 监听器这几个类的代理方式变成CGLIB ,这样代理的类里面是能找到方法的。

上面三种方式好像都可以 。

实践:

1.我们这个监听器就不要实现接口了:

 

 可以看看每次初始化的时候,spring帮我们选择的代理方式(用到注解、aop的类):

(这种情况都已经不实现接口,也只能是CGLIB代理了)

这种情形,我们把项目运行起来,调一下模拟接口,可以看到异步调用成功: 

 所以这种方式也是成功可行的!

2.我们把这个被注解标记的方法 deal 也变成接口里面有的 

 

 

 这样就明目张胆的的符合规矩了,所以运行发现成功了, 我们的三个监听器都是异步的了:
 

 特意在发短信的监听处理方法里面跑错,并不会影响其他监听器方法,异步线程机制执行:

 所以这种方式也是成功可行的!

3. 保持实现接口的方式, 直接就按照错误提示,我就用 CGLIB代理方式去生成监听器的代理类,不就解决了么:

其实这个@Async也提供了这种手段,也就是开启 proxyTargetClass, 在被初始化收集时,生成的代理类会采取CGLIB方式。

其实就是因为我们想通过这种方式使用异步,然后@Async 使用时,用到了 @EnableAsync ,

而@EnableAsync 里面的代理方式  proxyTargetClass默认是false ,就是导致代理方式改成了JDK代理,然后就出现我们的报错。

所以我们要去解决,只需要设置为true。

可以看源码:

指示是否创建基于子类(CGLIB)的代理,而不是到标准的基于Java接口的代理。

仅当{@link#mode}设置为{@link AdviceMode#PROXY}时适用。

默认值为 false。

注意,将此属性设置为 true 将影响所有 Spring管理的bean需要代理,而不仅仅是那些用@Async标记的bean。

例如,使用Spring的@Transactional注释标记的其他bean将同时升级到子类代理。这种方法没有任何好处在实践中产生负面影响,除非有人明确期望一种类型的代理。

 运行项目,可以看到成功使用CGLIB代理方式:
 

 同样,这样也是异步生效的,跑错的方法不会影响其他异步线程的执行:

本来还想继续讲一下 这个spring事件发布监听中,所谓的 调度中心在哪里呈现? 是怎么样实现监听机制的?  监听者是 pull模式 还是 push模式?  

该篇篇幅太长了,这几个点需要结合源码一块分析,那就留到下一篇吧。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot 事件发布监听机制使用、分析、注意点 (一篇到位) 的相关文章

  • Java NIO Pipe 与 BlockingQueue

    我刚刚发现它只有一个 NIO 工具 即 Java NIO Pipe 它是为在线程之间传递数据而设计的 与通过队列 例如 ArrayBlockingQueue 传递的更传统的消息相比 使用此机制是否有任何优势 通常 将数据传递给另一个线程进行
  • 使用 REST API 实现属性/字段级安全

    我正在为支持多租户授权模型的 REST API 构建概念验证 该模型不仅控制用户可以访问哪些对象 还控制对象中的字段 此模型的目标是确保租户管理员只能修改其租户并且只能查看允许的对象属性 我有一个正在开发的现有代码库 可在以下位置公开获取
  • Zuul不转发请求到其他微服务

    我正在使用 Spring Boot 微服务 我已经配置了 eureka zuul 代理和另一个微服务 帐户 如果我直接从帐户拨打电话 则工作正常 帐户和 zuul 服务器都显示在 eureka 上 当我尝试使用 zuul 代理进行访问时 它
  • Java 扫描仪问题 (JFrame)

    我正在尝试使用扫描仪来编辑塔防游戏的级别 但是 它不会将级别 图块图像 更新为自定义文件的级别 0 是草 1 是石头 1 是什么都没有 等等 我发现了错误 但如何修复它 我需要添加 更改什么才能消除这个错误 java lang NullPo
  • Android - 检测电容式触摸屏上的触摸压力?

    我听说过 MotionEvent e float press e getPressure 但这只会在没有触摸时返回 0 当我的手指触摸屏幕时返回 1 是否可以找到手指在触摸电容屏上施加的压力值 或者我的预感是否正确 即这只适用于电阻屏幕 M
  • Java 区域设置区分大小写

    我有以下代码来显示当前区域设置 System out println Locale getDefault System out println new Locale en US 上面给出的输出如下 en US en us 如何构造一个 Lo
  • 如何通过双击图标来执行JAVA程序?

    我写了一个java程序 现在我想在没有 IDE Eclipse 等的情况下打开我的控制台 java 应用程序 只需双击桌面上的可执行版本即可 我已将 java 项目导出为 Runnable JAR 文件 但无法打开 当我尝试使用cmd打开应
  • 在 Spring 中使用事务时创建提交后

    由于某些原因 我使用 Spring PlatformTransactionManager 手动执行事务提交和回滚 我需要做的是设置一个钩子 以便在提交事务后发生提交后操作 通过查看 void commit TransactionStatus
  • 可以使用注解进行代码注入吗?

    我意识到这可能是一个已经被提出和回答的问题 但请耐心等待 我想知道是否可以使用注释将代码注入到类编译时 典型的示例是为对象的成员生成 getter 和 setter 这并不完全是我所需要的 但它可以说明基本思想 现在在互联网上我得到的基本答
  • 高负载应用程序的数据库可扩展性?

    我见过一些应用程序拥有集群 Web 服务器 例如 10 到 20 个服务器 以具有可扩展性 可以在其中分发 在网络服务器之间加载 但我总是看到所有网络服务器都使用单个数据库 现在考虑任何电子商务或铁路 Web 应用程序 其中有数百万用户在任
  • Java Swing 自定义形状(2D 图形)

    我需要绘制自定义形状 现在 当用户单击面板上的几个点时 我使用多边形创建一个形状 public void mouseClicked MouseEvent e polygon addPoint e getX e getY repaint 但我
  • 有没有办法在@Service上使用@ControllerAdvice

    我有一个项目需求 但我没有任何需求 Controller or RestController但我需要为我的服务层提供一个全局异常处理程序 所以我需要配置 ControllerAdvice on Service 请告诉我是否还有其他方法可以做
  • 如何用Java捕获音频数据

    我想访问我的麦克风用 Java 录制的音频数据 我该怎么做呢 我的目标是保存录制的音频数据并同时向用户播放 如果您不需要 JMF 中的任何附加功能 我会避免使用它 因为开发已经停止 最后一个版本是 2004 年 它与 Java 6 存在兼容
  • 无法安装 JDK 9,因为“另一个 Java 安装正在进行中”

    我已经在 Windows 10 x64 上使用 JDK 9 一段时间了 但是当我去安装最新的早期版本 b174 时 我首先卸载了以前的版本 像往常一样 然后运行新的安装程序 它失败并显示一个消息框 显示 另一个 Java 安装正在进行中 您
  • 为什么对象可以改变类变量的值?

    由甲骨文提供定义 http docs oracle com javase tutorial java javaOO classvars html 有时 您希望拥有所有对象共有的变量 这是通过 static 修饰符来完成的 声明中带有 sta
  • Android 自定义相机 - 在矩形内裁剪图像

    我有一个自定义相机应用程序 它有一个居中的矩形视图 如下所示 当我拍照时 我想忽略矩形之外的所有内容 该视图与我的 XML 视图中的 Camera Preview 或 SurfaceView 没有任何联系 如下所示
  • 在 Android 版 ORMLite 中加入类会引发 SQL 异常:找不到外部类,反之亦然

    我正在尝试使用 QueryBuilder 为两个不同的类创建一个联接查询 一个Product类和一个Coupon类 引用 Product 属性 storeId public class Coupon DatabaseField column
  • java银行程序帐户ID不上去?

    每次创建银行帐户时 帐户 ID 都应增加 1 但每次我尝试提取 Id 时 我只会得到帐户 ID 为 0 任何建议 因为我完全按照我学习的书中的方式进行操作而且它仍然没有更新 帐户构造函数 public class BankAccount p
  • 寻找基于循环固定大小数组的双端队列

    我正在寻找一个Deque其具有以下特点 它有固定的大小 如果我在头 尾添加元素 则另一端的元素会丢失 它是基于数组的 所以我可以在恒定时间内访问随机元素 我可以在前面或末尾添加元素 双端队列 我检查了Deque的实施JCF但我没有找到任何合
  • JVM锯齿状空闲进程

    我目前正在进行一项涉及 JVM 及其内存使用工作原理的研究 我不明白的是 JVM在空闲时用什么填充它的内存 只是为了在堆几乎达到时释放它 为什么使用的内存不只有一条平线 顺便说一句 这个 java 应用程序托管在 glassfish 上 但

随机推荐

  • bugfree pdo mysql扩展模块_windows平台bugfree3.0.3搭建心得(nginx+php+mysql+bugfree+RunHiddenConsole)...

    之前没做过windows服务器管理 我的认识还停在个人用户操作系统的认知上 这次搭建bugfree环境 挺多麻烦的 在安装之前 我百度的bugfree搭建大多是使用xampp集成环境的安装方法 然后我就照做 下载xampp 然后安装到系统c
  • C语言实现两数相加的三种方法

    笔试题里面看到的 总结一下 分享给需要的小伙伴 一 原始办法 这种方法最直观明了 int add int x int y return x y 二 利用printf的返回值 这个操作鲜为人知 include
  • linux域名解析

    linux域名解析 首先确保你的电脑可以连上网 服务端和客户端能够连通 1 本地解析 优先级高 在服务端中 ping www baidu com 找出ip 在客户端中的浏览器中搜索ip地址就可以上网 但是ip地址记起来非常不方便 所以这里用
  • 网贷风控体系之-风控模型

    网贷风控体系之 风控模型 大数据风控模型主要分为两类 反欺诈模型 交叉验证 聚类分析 黑灰名单 二元好坏模型 准入阶段 授信额度期限利率模型 评分卡模型 LR XGBoost 贷中阶段 风险变化评估 风险预警 贷后阶段 催收时机 催收方法
  • TVM:源码编译安装

    TVM Linux源码编译安装 笔者环境 OS Ubuntu 18 04 CMake 3 10 2 gcc 7 5 0 cuda 11 1 编译安装过程总览 本文将简介 tvm 的编译安装过程 包含两个步骤 通过C 代码构建共享库 设置相关
  • Android - BlueTooth BLE 之 Central 与 Peripheral

    一 前言 Andorid 5 0 之前是无法进行 外围设备开发的 在Android 5 0 API 21 android bluetooth le包下 新增加 Scaner相关类和 Advertiser 相关类 目前最后使用Scanner相
  • 49天精通Java,第5天,Java控制台输入输出语句

    目录 一 控制台输出 二 读取输入 三 格式化输出 1 类型转换字符 2 代码实例
  • 搭建github服务器_【教程篇】使用GitHub+Hexo搭建个人静态博客

    嗨 大家好 你们的万金油管家小e又来了 这次就教大家一些利用GitHub和Hexo本地服务器搭建个人博客的教程 可能教程要好几期 那么这期就先从最最基础的GitHub的注册 以及本地环境的搭建 GitHub仓库的建立等等开始 近年来很多人都
  • 十大应用安全威胁

    常见应用安全威胁 OWASP TOP 10 2013 注入 失效的身份认证和会话管理 跨站脚本攻击 XSS 不安全的直接对象引用 安全配置错误 敏感信息泄露 功能级访问控制缺失 跨站请求伪造 CSRF 使用含有已知漏洞的组件 未验证的重定向
  • 【MyBatis】MyBatis 二级缓存全详解

    1 概述 转载 MyBatis 二级缓存全详解 上一篇文章中我们介绍到了 MyBatis 一级缓存其实就是 SqlSession 级别的缓存 什么是 SqlSession 级别的缓存呢 一级缓存的本质是什么呢 以及一级缓存失效的原因 我希望
  • Ubuntu扩展存储合理分配swap分区

    文章目录 前言 1 为Ubuntu扩存 外部存储 1 1修改存储 1 2 初始化分配的磁盘 2 为Ubuntu调整swap分区大小 总结 前言 我们在Ubuntu上运行某些大型游戏或者编译一些工程代码的时候 往往会遇到内存或外部存储不够导致
  • mac 本地运行 http-proxy-middleware ,请求超时

    const http require http customer target http 10 10 111 192 8080 target http user jinfu baohan com changeOrigin true 是否启用
  • JS如何将变量作为一个对象的Key

    JS如何将变量作为一个对象的Key var lastWord last word var a first word hello lastWord world a first word hello a lastWord world a las
  • Mysql进阶优化篇06——分组查询优化、分页查询优化、覆盖索引

    前 言 作者简介 半旧518 长跑型选手 立志坚持写10年博客 专注于java后端 专栏简介 mysql基础 进阶 主要讲解mysql数据库sql刷题 进阶知识 包括索引 数据库调优 分库分表等 文章简介 本文将介绍JOIN语句的底层原理
  • Java中通过反射+自定义注解判断对象中部分属性是否为空,返回为空字段的名称或自定义含义

    场景 若依管理系统前后端分离版基于ElementUI和SpringBoot怎样实现Excel导入和导出 若依管理系统前后端分离版基于ElementUI和SpringBoot怎样实现Excel导入和导出 霸道流氓气质的博客 CSDN博客 在上
  • 【爬虫】python复原网站前端密码加密

    爬虫 python复原网站前端密码加密 前言 前几天学完了尚硅谷的爬虫课程 这几天刚好有一门课出成绩了 我们学校的教务处的查分系统手机无法正常打开 好像只有ios设备用不了 学校的一些学长弄了一个公众号 在公众号里面手机可以很方便的查到分数
  • SMTP服务器地址及端口

    在开发过程中有些场景会用到发送邮件的功能 根据客户需求不同会使用到各种类型的邮箱服务 发送邮件的方法都大同小异 差异大的就是各个邮箱服务的地址及端口 找起来比较麻烦 整理到部分比较常用的可根据需要获取 部分自建的邮箱的SMTP是自定义的 需
  • ARP协议和攻击原理

    转自 https blog 51cto com 13570193 2083332 ARP 在TCP IP协议栈中 最不安全的协议莫过于ARP了 我们经常听到的网络扫描 内网渗透 流量欺骗等等 他们基本上都与ARP有关系 甚至可以说 他们的底
  • 我的ACM生涯——迷失

    自从EC打铁归来已经一星期了了 这一周我都在颓废 似乎又回到以前的自己 没想到 我在集训队呆了2年 还是菜的真实 虽然把所有的原因 都归结到菜上 的确是个逃避问题正解的办法 我决定写点什么总结 算是一个收尾 先来做个回忆 还记得第一次看到自
  • SpringBoot 事件发布监听机制使用、分析、注意点 (一篇到位)

    前言 这一篇从应用角度来跟大伙讲讲 这个 spring 事件监听机制 顺便涉及到那些我认为大家应该一块了解的 我也会展开说说 文章内容 包括不限于 1 对比观察者模式 2 应用场景的分析 3 事件的创建 编码介绍 4 事件如何 发出 5 事