ApplicationEvent
和Listener
是Spring中的一个事件监听、订阅实现(实现原理是观察者设计模式),为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。
事件
spring事件由三部分组成:事件(ApplicationEvent)、监听器(ApplicationListener)和事件发布操作。
ApplicationEvent
所有要发布的事件都需要继承ApplicationEvent。
public class CreateMsgEvent extends ApplicationEvent {
public CreateMsgEvent(Object source) {
super(source);
}
public MsgEventData getMsg(){
Preconditions.checkState(source!=null);
return (MsgEventData)this.source;
}
}
@Data
public class MsgEventData {
private String msg;
}
@EventListener
@EventListener是在spring4.2中引入的,可替代早期的ApplicationListener接口,实现事件侦听。
@Service
public class EventListener {
private static final Logger _logger = LoggerFactory.getLogger(EventListener.class);
@org.springframework.context.event.EventListener
public void onSynMsgEvent(CreateMsgEvent event){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
_logger.info("onSynMsgEvent: {}", event);
}
@Async
@org.springframework.context.event.EventListener
public void onAsynMsgEvent(CreateMsgEvent event){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
_logger.info("onAsynMsgEvent: {}", event);
}
}
默认情况下,侦听是同步的,即只有侦听函数处理完成返回后;发布事件的接口才会返回。通过增加@Async注解可实现异步侦听。
@Async
springboot中@EnableAsync与@Async注解配合使用,即可实现异步调用:
- 在方法上标注@Async注解,指示该方法需加入线程池以实现异步运行;
- 需要@EnableAsync配合使用,异步才生效:若未启用异步,则@Async不启作用。
在启动类上标注@EnableAsync注解,以启用@Async异步注解:
@EnableAsync
@SpringBootApplication
public class StudyApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(StudyApplication.class, args);
}
}
发布
ApplicationEventPublisher把事件发布给每个侦听器:
- 同步侦听:只有侦听器执行完返回后,publishEvent才完成;
- 异步侦听:发布后即可返回;
@RestController
@RequestMapping("test")
public class TestController {
private static final Logger _logger = LoggerFactory.getLogger(TestController.class);
@Autowired
ApplicationEventPublisher publisher;
@GetMapping("testEvent")
public String testEvent(HttpServletRequest request, String msg){
MsgEventData msgData = new MsgEventData();
msgData.setMsg(msg);
_logger.info("To publish");
publisher.publishEvent(new CreateMsgEvent(msgData));
_logger.info("Published");
return msg;
}
}
发布给以上一个同步、一个异步侦听器后输出结果为:
To publish
>>onSynMsgEvent
onSynMsgEvent: [source=MsgEventData(msg=safs)]
Published
>>onAsynMsgEvent
onAsynMsgEvent: [source=MsgEventData(msg=safs)]
guava
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。
Preconditions
Preconditions 提供了判断条件是否合法的静态方法,如果不符合要求会抛出异常(类似断言)。
方法声明 | 描述 | 检查失败时抛出的异常 |
---|---|---|
checkArgument(boolean) | 检查boolean是否为true,用来检查传递给方法的参数 | IllegalArgumentException |
checkNotNull(T) | 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull | NullPointerException |
checkState(boolean) | 用来检查对象的某些状态。 | IllegalStateException |
checkElementIndex(int index, int size) | 检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size | IndexOutOfBoundsException |
checkPositionIndex(int index, int size) | 检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size | IndexOutOfBoundsException |
checkPositionIndexes(int start, int end, int size) | 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效 | IndexOutOfBoundsException |
Jointer
用分隔符将多个**字符串(或数组元素)**连接成一个字符串:
- on(String):静态工厂方法,生成一个新的 Joiner 对象,参数为连接符;
- skipNulls():如果元素为空,则跳过;
- useForNull(String):如果元素为空,则用这个字符串代替;
- join(数组/链表):要连接的数组/链表;
- appendTo(String,数组/链表):在第一个参数后面新加上 拼接后的字符串;
- withKeyValueSeparator(String):得到 MapJoiner,Map键、值的连接符;
@GetMapping("testGuava")
public void testGuava(){
List<String> lstTest = Arrays.asList("aa", "bb", "cc", null, "dd");
System.out.println(Joiner.on("; ").useForNull("<null>").join(lstTest)); // aa; bb; cc; <null>; dd
Map map = ImmutableMap.of("k1", "v1", "k2", "v2");
System.out.println(Joiner.on("; ").withKeyValueSeparator("=").join(map)); // k1=v1; k2=v2
}
Splitter
Splitter 将一个字符串按照分隔符生成字符串集合:
- on(String):静态工厂方法,生成一个新的 Splitter 对象,参数为分隔符;
- trimResults():结果去除子串中的空格;
- omitEmptyStrings():去除空子串;
- split(String):拆分字符串;
- withKeyValueSeparator(String):得到 MapSplitter,拆分成Map的键、值。注意,这个对被拆分字符串格式有严格要求,否则会抛出异常
String strList = "aa; bb; cc; <null>; dd";
System.out.println(Splitter.on(";").trimResults().split(strList)); // [aa, bb, cc, <null>, dd]
String strMap = "k1=v1; k2=v2";
System.out.println(Splitter.on(";").trimResults().withKeyValueSeparator("=").split(strMap)); // {k1=v1, k2=v2}
Strings
Strings 类主要提供了对字符串的一些操作:
- nullToEmpty(String string) :null字符串转空字符串;
- emptyToNull(String string):空字符串转null字符串;
- isNullOrEmpty(String string):判断字符串为null或空字符串;
- padStart(String string, int minLength, char padChar):如果string的长度小于minLeng,在string前添加padChar,直到字符串长度为minLeng。
集合
可变集合接口 | JDK/Guava | 不可变版本 |
---|---|---|
Collection | JDK | ImmutableCollection |
List | JDK | ImmutableList |
Set | JDK | ImmutableSet |
SortedSet/NavigableSet | JDK | ImmutableSortedSet |
Map | JDK | ImmutableMap |
SortedMap | JDK | ImmutableSortedMap |
Multiset | Guava | ImmutableMultiset |
SortedMultiset | Guava | ImmutableSortedMultiset |
Multimap | Guava | ImmutableMultimap |
ListMultimap | Guava | ImmutableListMultimap |
SetMultimap | Guava | ImmutableSetMultimap |
BiMap | Guava | ImmutableBiMap |
ClassToInstanceMap | Guava | ImmutableClassToInstanceMap |
Table | Guava | ImmutableTable |