首页
3D照片墙
统计
留言
Search
1
1.OAuth 的简单理解
116 阅读
2
多个拦截器的执行顺序
106 阅读
3
基于Annotation方式的声明式事务
102 阅读
4
6.设计模式汇总
101 阅读
5
Unity 依赖注入
98 阅读
Java
JDBC
Spring
Spring MVC
SpringBoot
SpringCloud
MybatisPlus
Mybatis
Maven
SpringSecurity
JVM
java注解与反射
Java JUC并发编程
SSM
.NET
IdentityServer4
EF
.Net Core
AbpVNext + DDD
.NET MVC Api
前端
Jquery&JavaScript
uniapp
VUE
Echars
Vue底层原理
Python
Django
软考笔记
软件设计师
1.计算机组成与体系结构
10.面向对象技术
11.UML类图建模
12.面向对象程序设计
13.数据结构
14.算法基础
16.知识产权标准化
17.程序设计语言
2.操作系统
3.数据库
4.数据库设计
5.计算机网络
6.信息安全
7.系统开发基础
8.项目管理
9.数据流图
架构设计
CQRS架构
DDD架构
数据库技术
SQL锁
SqlServer
Oracle 主从备份
Oracle RAC集群
Mysql
云原生/容器技术
kubernetes
Docker
数据结构与算法
常用中间件
Redis
RabbitMQ 消息队列
ElasticSearch
其他
PHP
OAuth 2.0
WebSocket
ArkTs Harmony 开发
运维
Search
标签搜索
排序算法
vue
算法
遍历
docker
线性
数组
dom
synchronized
数据库
xml语言
log4j
bigint
静态函数
静态方法
哈夫曼树
const
冒泡排序
商标设计
命令模式
Bi8bo
累计撰写
304
篇文章
累计收到
6
条评论
首页
栏目
Java
JDBC
Spring
Spring MVC
SpringBoot
SpringCloud
MybatisPlus
Mybatis
Maven
SpringSecurity
JVM
java注解与反射
Java JUC并发编程
SSM
.NET
IdentityServer4
EF
.Net Core
AbpVNext + DDD
.NET MVC Api
前端
Jquery&JavaScript
uniapp
VUE
Echars
Vue底层原理
Python
Django
软考笔记
软件设计师
1.计算机组成与体系结构
10.面向对象技术
11.UML类图建模
12.面向对象程序设计
13.数据结构
14.算法基础
16.知识产权标准化
17.程序设计语言
2.操作系统
3.数据库
4.数据库设计
5.计算机网络
6.信息安全
7.系统开发基础
8.项目管理
9.数据流图
架构设计
CQRS架构
DDD架构
数据库技术
SQL锁
SqlServer
Oracle 主从备份
Oracle RAC集群
Mysql
云原生/容器技术
kubernetes
Docker
数据结构与算法
常用中间件
Redis
RabbitMQ 消息队列
ElasticSearch
其他
PHP
OAuth 2.0
WebSocket
ArkTs Harmony 开发
运维
页面
3D照片墙
统计
留言
搜索到
304
篇与
的结果
2022-07-29
基本概念 - 领域设计:领域事件
本文探讨如下问题: 什么是领域事件 领域事件的用途 何时使用领域事件 基于Spring事件的实现 什么是领域事件 在EDA风格与Reactor模式一文中,我们从观察者模式聊到了EDA架构风格,然后聊了Reactor架构模式,最后以redis为例聊了Event-driven programming编程模式。 这些内容都是技术层面的,其共性是通过事件来进行解耦,提高系统的性能、扩展性、伸缩性、可运维性和灵活性。 而领域事件顾名思义也是通过事件来进行解耦,只是它是设计层面的技术。用于解耦领域设计中的组件: 聚合与聚合之间的解耦。聚合请参考 限界上下文之间的解耦。限界上小文后面再聊 何时使用领域事件? 在《领域驱动设计》的第七章,举了一个货运的例子。其中有个HandlingEvent,这就是一个事件对象。当货物被装货、卸货、密封、存放以及其他活动时就会创建一个HandlingEvent。 ](https://p3-tt.byteimg.com/origin/pgc-image/a0fd500cbd8a478d887fc0db03ff2ca7?from=pc)) 在这个例子中,是由人在货物被处理时,使用系统输入了一条HandlingEvent记录下来而已!而如果当发生了一个HandlingEvent后,需要后续的处理(比如发送通知给相关人员),该怎么办呢?这就是领域事件所要解决的问题! 在《领域驱动设计》中并没有提到领域事件,领域事件是其后出现的。 实际上,当出现类似如下关键词汇时,都可以考虑使用领域事件: 当...... 如果发生...... 当......的时候,请通知我 发生......时 下面通过Spring的事件来实现上例中的具体流程。 Spring事件实例代码 新建HandlingEvent类,继承ApplicationEvent,表示这是一个事件 public class HandlingEvent extends ApplicationEvent { private String actionName; public VisitEvent(Object source,String actionName) { super(source); this.actionName = actionName; } } 编写事件发布类EventPublisher,实现ApplicationEventPublisherAware,用于注入ApplicationEventPublisher,通过publishEvent方法来发布事件 Spring默认是同步事件,如果需要异步事件,需要添加EnableAsync注解 @Service @EnableAsync public class EventPublisher implements ApplicationEventPublisherAware { private ApplicationEventPublisher publisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; } public void publish(ApplicationEvent event) { publisher.publishEvent(event); } } 编写监听类,只需要在监听方法上添加eventListener注解,参数为需要监听的事件类即可 如果需要异步处理,添加Async注解 可以通过Async的value属性来选择线程池。 推荐选择自定义线程池,默认线程池没有限制线程数量,可能导致OOM @Component public class HandlingListener { @EventListener@Async("eventThread") public void processHandlingEvent(HandlingEvent event) {// 处理事件} 调用EventPublisher的publish方法,即可进行事件的发布 eventPublisher.publish(new HandlingEvent(this, "move")); 整体的流程如下: EventPublisher添加HandlingEvent HandlingListener监听到了HandlingEvent,执行对应的方法 我们看下Spring中如何实现这个流程的。 Spring事件实现 ](https://p1-tt.byteimg.com/origin/pgc-image/e460ab9325de4dca8233d8b916cfc932?from=pc)) Spring启动时,EventListenerMethodProcessor会将标识了EventListener注解的方法添加到Context中。这里就是HandlingListener中的processHandlingEvent方法 for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); ApplicationListener<?> applicationListener =factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); } context.addApplicationListener(applicationListener);break; } } } AbstractApplicationContext实现了ApplicationContext接口,其中维护了扫描到的ApplicationListener @Override public void addApplicationListener(ApplicationListener<?> listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } this.applicationListeners.add(listener); } 在EventPublisher发布事件时,触发ApplicationEventPublisher的publishEvent方法 ApplicationContext接口继承了ApplicationEventPublisher接口,最终触发AbstractApplicationContext的publishEvent方法,将事件广播出去 ApplicationContext接口为什么要继承ApplicationEventPublisher接口?因为Spring中定义了几个默认的事件ContextRefreshedEvent,ContextStartedEvent,ContextStoppedEvent,ContextClosedEvent,RequestHandledEvent,而ApplicationContext就是这些事件的布者。 less复制代码protected void publishEvent(Object event, @Nullable ResolvableType eventType) { ...... else { getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); // 广播事件 } ..... } 最终触发SimpleApplicationEventMulticaster的multicastEvent方法 @Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(() -> invokeListener(listener, event)); }else { invokeListener(listener, event); } } } 获取ApplicationListener,然后使用Executor去执行listener 参考资料 Spring源码 《领域驱动设计:软件核心复杂性应对之道》 《实现领域驱动设计》 作者:一瑜一琂 链接:https://juejin.cn/post/6895181027820601357 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2022年07月29日
13 阅读
0 评论
33 点赞
2022-07-26
association 一对一
resultMap中association的各个属性的含义: property:映射实体类的字段或属性。 colum:数据库的列名或者列标签别名。 javaTyp:完整java类名或别名。 jdbcType支持的JDBC类型列表列出的JDBC类型。这个属性只在insert,update或delete的时候针对允许空的列有用。 resultMap: 一个可以映射联合嵌套结果集到一个适合的对象视图上的ResultMap。这是一个替代的方式去调用另一个select语句。 https://blog.csdn.net/vvhesj/article/details/47130547
2022年07月26日
92 阅读
0 评论
81 点赞
2022-07-25
1.1 三种标准注解
@Deprecated 已过期,表示方法是不被建议使用的 @Override 重写,标识覆盖它的父类的方法 @SuppressWarnings 压制警告,抑制警告 解释: Deprecated 注解 可以修饰类、方法、变量,在java源码中被@Deprecated修饰的类、方法、变量等表示不建议使用的,可能会出现错误的,可能以后会被删除的类、方法等,如果现在使用,则在以后使用了这些类、方法的程序在更新新的JDK、jar包等就会出错,不再提供支持。 个人程序中的类、方法、变量用@Deprecated修饰同样是不希望自己和别人在以后的时间再次使用此类、方法。当编译器编译时遇到了使用@Deprecated修饰的类、方法、变量时会提示相应的警告信息。 Override 注解 指明被注解的方法需要覆写超类中的方法,如果某个方法使用了该注解,却没有覆写超类中的方法(如大小写写错了,或者参数错了,或者是子类自己定义的方法),编译器就会生成一个错误。 在子类中重写父类或接口的方法,@Overide并不是必须的。但是还是建议使用这个注解,在某些情况下,假设你修改了父类的方法的名字,那么之前重写的子类方法将不再属于重写,如果没有@Overide,你将不会察觉到这个子类的方法。有了这个注解修饰,编译器则会提示你这些信息。 Suppresswarnings 注解 @SuppressWarnings用来抑制编译器生成警告信息,可以修饰的元素为类,方法,方法参数,属性,局部变量。它可以达到抑制编译器编译时产生警告的目的,使用@SuppressWarnings注解,采用就近原则,比如一个方法出现警告,尽量使用@SuppressWarnings注解这个方法,而不是注解方法所在的类。所属范围越小越好,因为范围大了,不利于发现该类下其他方法的警告信息。 但是很不建议使用@SuppressWarnings注解,使用此注解,开发人员看不到编译时编译器提示的相应的警告,不能选择更好、更新的类、方法或者不能编写更规范的编码。同时后期更新JDK、jar包等源码时,使用@SuppressWarnings注解的代码可能受新的JDK、jar包代码的支持,出现错误,仍然需要修改。
2022年07月25日
77 阅读
0 评论
86 点赞
2022-07-24
Maven 插件
maven-compiler-plugin 插件是一个 Maven 插件,用来编译项目代码; 作用: maven如果我们不告诉它我们的代码要使用什么样的 jdk 版本编译的话,它就会用 maven-compiler-plugin 默认的 jdk 版本来进行处理,这样就容易出现版本不匹配,以至于可能导致编译不通过的问题。 maven 的默认编译使用的 jdk 版本有时候不通用,使用 maven-compiler-plugin 插件可以指定项目源码的 jdk 版本,编译后的 jdk 版本,以及编码。 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>
2022年07月24日
47 阅读
0 评论
6 点赞
2022-07-24
订阅模式 代码
一 . 简单整合 添加RabbitMQ依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> 配置application.yml spring: rabbitmq: host: 127.0.0.1 port: 5672 username: test password: 123456 virtual-host: / 新建RabbitMQConfig package com.example.config; import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMQConfig { // 测试队列名称 private String testQueueName = test_queue; // 测试交换机名称 private String testExchangeName = test_exchange; // RoutingKey private String testRoutingKey = test_routing_key; /** 创建队列 */ @Bean public Queue testQueue() { return new Queue(testQueueName); } /** 创建交换机 */ @Bean public TopicExchange testExchange() { return new TopicExchange(testExchangeName); } /** 通过routingKey把队列与交换机绑定起来 */ @Bean public Binding testBinding() { return BindingBuilder.bind(testQueue()).to(testExchange()).with(testRoutingKey); } } 新建生产者(producer) package com.example.producer; import com.alibaba.fastjson.JSONObject; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageBuilder; import org.springframework.amqp.core.MessageDeliveryMode; import org.springframework.amqp.core.MessageProperties; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class TestProducer { @Autowired private RabbitTemplate rabbitTemplate; public void send(String queueName) { JSONObject jsonObject = new JSONObject(); jsonObject.put(email, 756840349@qq.com); jsonObject.put(timestamp, System.currentTimeMillis()); String jsonString = jsonObject.toJSONString(); // 生产者发送消息的时候需要设置消息id Message message = MessageBuilder.withBody(jsonString.getBytes()) .setDeliveryMode(MessageDeliveryMode.PERSISTENT) .setContentType(MessageProperties.CONTENT_TYPE_JSON).setContentEncoding(utf-8) .build(); rabbitTemplate.convertAndSend(queueName, message); } } 新建消费者(consumer) package com.example.listener; import com.alibaba.fastjson.JSONObject; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class FanoutSmsConsumer { @RabbitListener(queues = test_queue) public void consumeMessage(Message message) throws Exception{ String msg = new String(message.getBody(), UTF-8); JSONObject jsonObject = JSONObject.parseObject(msg); System.out.println(消费消息: + jsonObject); } } 编写controller测试 package com.example.controller; import com.example.producer.FanoutProducer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ProducerController { @Autowired private TestProducer TestProducer; @RequestMapping(/sendMsg) public String sendFanout() { fanoutProducer.send(test_queue); return success; } } 浏览器访问localhost:8080/sendMsg,会返回success,并且控制台监听器会打印消息:
2022年07月24日
66 阅读
0 评论
73 点赞
1
...
46
47
48
...
61