Skip to content

Commit dccc806

Browse files
author
biancheng
committed
java 生态
1 parent 279bf6b commit dccc806

File tree

13 files changed

+527
-0
lines changed

13 files changed

+527
-0
lines changed

java生态学习三.md

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# 初识Spring Boot
2+
> 没用过任何java的框架做过web开发,因此要问Sping Boot的优劣到底在哪,我也说不上,自己封装了`tomcat`,开箱即用?
3+
4+
## 入口
5+
`Spring Boot`程序的入口并非业务代码中的定义了`main函数`的类,而是`Spring Boot`自己定义的`JarLauncher`类,这个也就是`MANIFEST.MF`中的`Main-Class`。而业务中的`main函数`则是通过`getMainClass()``MANIFEST.MF`查找`Start-Class`找到然后通过反射调用的。
6+
```
7+
public void run() throws Exception {
8+
Class mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
9+
Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class});
10+
mainMethod.invoke((Object)null, new Object[]{this.args});
11+
}
12+
```
13+
`IDEA`创建`Spring Boot`项目会默认生成一个入口类
14+
```
15+
@SpringBootApplication
16+
public class DemoApplication {
17+
public static void main(String[] args) {
18+
SpringApplication.run(DemoApplication.class, args);
19+
}
20+
}
21+
```
22+
其中`Spring Boot`被人喜欢的就是自动化配置,而这点光是从入口类上就可见一斑。
23+
`@SpringBootApplication`注解类中会调用到`Sping Boot`的核心注解类`@EnableAutoConfiguration`,此类可以帮助`Spring Boot`应用将所有符合条件的`@Configuration`都加载到当前应用创建并使用的`IoC`容器中。
24+
`@EnableAutoConfiguration`依靠的也是`AutoConfigurationImportSelector``SpringFactoriesLoader`才能产生此效果。
25+
落实到具体的配置文件是如下代码,这会被`SpringFactoriesLoader.loadFactoryNames`调用。
26+
```
27+
public static final String
28+
FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
29+
```
30+
> 再通俗说就是把`spring.factories`中需要自动配置的类的全名全都放入了`ImportSelector`,然后用时即取。
31+
32+
## 控制层
33+
怎么称呼呢?路由?大概就是这么个意思。
34+
```
35+
@RestController
36+
@EnableAutoConfiguration
37+
public class hello {
38+
@RequestMapping(value = {"/hello","/say"},method = RequestMethod.GET)
39+
public String say(){
40+
return "hello,this is a demo";
41+
}
42+
}
43+
```
44+
`@RestController`注解类负责格式化错误输出成`json`,其实还是封装了一层`@Controller`,而且默认的解析框架是`jackson`
45+
`@RequestMapping`是一个用来处理地址映射的注解类,有六个参数,常用其中三个。
46+
```
47+
@RequestMapping(value = {"/hello","/say"},method = {RequestMethod.GET},headers = {})
48+
```
49+
上面是比较标准的写法,实际如果是单独路径的话(多路径是或关系),可以简化写法
50+
```
51+
@RequestMapping("/hello");
52+
```
53+
`@PathVariable`URL变量设置,这样访问`/hello/1`就可以得到结果了。
54+
```
55+
@RequestMapping(value = {"/hello/{id}"},method = {RequestMethod.GET})
56+
public String say(@PathVariable("id") Integer id){
57+
if(id==1) {
58+
return "hello,this is a demo";
59+
}else {
60+
return "id=1";
61+
}
62+
}
63+
```
64+
`@RequestParam`参数设置,就是`get`的传参
65+
```
66+
@RequestMapping(value = {"/hello/{id}"},method = {RequestMethod.GET})
67+
public String say(@PathVariable("id") Integer id, @RequestParam Integer aa,@RequestParam String name){
68+
if(id==1) {
69+
return "hello,this is a demo and id:"+aa+"and name:"+name;
70+
}else {
71+
return "id=1";
72+
}
73+
}
74+
```
75+
> 如果没传入的话可以使用`required=false`+`defaultValue=value`作为`@RequestParam`的参数来设置默认。
76+
77+
## 模块
78+
如果说`auto-configuration`是亮点的话,那`actuator`就不逊于它,这是`Spring Boot`的自省和监控模块,可以对整个应用进行配置查看和相关功能统计等。
79+
开启所有的`endpoint`
80+
```
81+
management.endpoints.web.exposure.include=*
82+
```
83+
至于安全问题,看一圈,有但是很比较难说,还是配置不当吧。
84+
85+
# 参考资料
86+
* [Spring Boot项目的真实程序入口](https://blog.csdn.net/Fly2Leo/article/details/78612604)
87+
* [看源码,我为什么建议你先从 SpringBoot 开始](https://www.xttblog.com/?p=4016)
88+
* [@Controller@RestController的区别?](https://blog.csdn.net/gg12365gg/article/details/51345601)
89+
* [springboot之@RequestMapping](https://blog.csdn.net/weixin_36775115/article/details/79541981)
90+
* [顶(0) 踩(0)
91+
SpringBoot应用监控Actuator使用的安全隐患](https://xz.aliyun.com/t/2233)
92+

java生态学习二.md

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# MQ中间件 -- kafka
2+
* 为什么要用到MQ中间件
3+
* kafka的优劣
4+
## 为什么要用到MQ中间件
5+
> `Message Queuing`消息队列
6+
7+
1. 解耦
8+
9+
传统模式下,一个系统接入到另一个系统中,都是通过代码耦合来解决,因此每多一个新系统接入,就要修改一下代码,在这个基础上,产生了api的概念,对接的系统之间商量出相同的数据格式对接即可,同时还可以采用中间件的模式,也就是主系统将所有的数据都写入到一个消息队列中去,需要消息的系统则自己去消息队列中订阅,就像报刊发布一样。
10+
11+
2. 异步
12+
13+
在不同的服务之间有可能会出现处理相同消息的情况,但是由于服务迭代的问题,消息传递的情况很有可能是`A-B-C`这样的,因此如果`C`想要处理数据就必须要等待`B`先处理完把消息传过来,这无疑是低效的,因此`A`完全可以把消息写入一个中间件中,需要处理相同消息的系统主动来消费从而打到异步运行。
14+
15+
3. 削峰
16+
17+
请求并发过大时候,所有的请求都是直接查询的数据库,很容易导致数据库的连接异常,因此可以将所有的请求都写入消息队列里,然后系统根据数据库的并发限制来拉取请求,以此达到短暂的高峰期积压。
18+
19+
然而消息队列带来的负面影响也是存在的,比如系统可用性的问题,多增加一个服务就是多增加一份风险,如果系统之间都通过消息队列来传输数据,如果消息队列挂了,那么所有的系统都将异常。同时还提高了系统复杂性,因为消费消息就要考虑到一致性问题以及如何保证消息不被重复消费,如何保证消息传输可靠,如何做消息丢失的召回。
20+
21+
## 消息队列模式
22+
现在的消息队列主要应用有三种模式:
23+
1. `pub/sub模式`,也就是包含了`Topic(主题)``Publisher(发布者)``Subscriber(订阅者)`,以`topic`为节点,可以有多个`发布者`,同时也可以有多个`订阅者`
24+
2. `p2p模式`,包含`发送者``消息队列``接收者`,一个消息只有一个消费者。
25+
3. `push/pull模式`,也就是现在常用的模式,服务端主动推送消息/客户端主动发起消息请求。
26+
27+
## kafka
28+
`MQ中间件`有多种,比如`ActiveMQ``RabbitMQ``kafka`等,展示一个性能对比表
29+
30+
![55734022.png](java生态学习二_files/55734022.png)
31+
32+
就以`kafka`为例子,看下`kafka`的架构。
33+
34+
![56512760.png](java生态学习二_files/56512760.png)
35+
36+
一个`kafka`节点就是一个`broker`,多个组成一个`kafka`集群,`Topic`是消息归类的标识,任何一条消息都要指定`topic``producer``consumer`是从`broker``push/pull`的数据,一条消息可以发送到多个不同的`ConsumerGroup`,但是一个`group`中只有一个`Consumer`可以消费该条信息,而一个`topic`可以分成多个`partition`,其中每个`partition`内部有序。
37+
38+
具体表现是什么呢?
39+
1. 相同`group`的不同`consumer`获取的数据加起来是一个`topic`发布的数据
40+
2. 如果`consumer`数量大于`partition`的话,就会有`consumer`收不到信息
41+
42+
一个`producer`发布数据
43+
```
44+
kafka-console-producer.sh --broker-list kafka.domain.com:9092 --topic TOPIC_NAME
45+
```
46+
而一个`consumer`消费数据
47+
```
48+
kafka-console-consumer.sh --bootstrap-server kafka.domain.com:9092 --topic TOPIC_NAME --consumer-property group.id=kafka
49+
```
50+
51+
# 实时分析器 -- flink
52+
> 这段时间一直在做这个,坑点太多,不如简明扼要
53+
54+
## 可以处理的数据
55+
1. `DataStream`
56+
2. `Table&sql`
57+
58+
层级结构上如图:
59+
60+
![58523413.png](java生态学习二_files/58523413.png)
61+
62+
越上层越慢,但是封装的不错,因此也就越简单。但是坑点也在,就是`SQL`是在``的基础上封装的,因此表是实时表,因此就算你用了虚表,那么原来的字段也还是没有的。
63+
> 最常见的问题就是`SQL`中的`group by`如果后面没有分组的字段,那么这个字段就会丢失无法`select`
64+
65+
## 窗口
66+
最常用的聚合,坑点在于得自己处理`窗口数据`,而且更大的坑点在于`时间窗口`默认是`ProcessingTime`,因此需要手动设置`EventTime`的标志位,这就需要用到`waterMark`
67+
```
68+
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
69+
```
70+
处理时间
71+
```
72+
DataStream<Tuple5<Long,String,String,String,String>> waterMarkStream = dataStream.assignTimestampsAndWatermarks(new AssignerWithPeriodicWatermarks<T>() {
73+
Long currentMaxTimestamp = 0L;
74+
//允许最大乱序时间:10s
75+
final Long maxOutofOrderness = 10000L;
76+
@Nullable
77+
@Override
78+
public Watermark getCurrentWatermark() {
79+
return new Watermark(currentMaxTimestamp-maxOutofOrderness);
80+
}
81+
@Override
82+
public long extractTimestamp(element, long previousElementTimestamp) {
83+
long timestamp = element.f0;
84+
currentMaxTimestamp = Math.max(timestamp,currentMaxTimestamp);
85+
return timestamp;
86+
}
87+
});
88+
```
89+
提前聚合的`keyby()`,这个个人感觉并不实用,但是涉及到`window``No-Key-Window`,最常见的区别在于
90+
```
91+
window()和windowAll()
92+
```
93+
一个是先分组再聚合,另一个是全量聚合。
94+
## `map()``flatMap()`
95+
`map()`能做的`flatMap()`都可以,因此用`flatMap()`就行了,作用就是把基础的`DataStream`再清洗一遍。
96+
## 执行和输出
97+
输出流的信息的话只需要选取要输出的``后面加`print`,如`dataStream.print()`,而整个实时分析器的触发则是在`env.excute()`
98+
99+
## 作用
100+
如名实时分析处理消息,不同于`hadoop`这样的定时全量分析,能够做到实时分析。具体案例就是实时推荐。
101+
比如在淘宝搜索食品,此时的推荐商品是电器,如果是全量分析,很有可能在第二天才会推荐食品,而如果是实时分析,则会在第一时间把推荐换成食品。
102+
103+
能处理流就尽量处理流,不要搞`Table&Sql`,虽然更简单,但是坑也多。
104+
105+
# 结语
106+
刚接触不久,坑很多,还在填。
107+
108+
# 参考资料
109+
* [flink api](http://flink.iteblog.com/index.html)
67 KB
Loading
66.6 KB
Loading
39.1 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
public class SimpleConsumer {
2+
//set get
3+
private static String BOOTSTRAP_SERVER="kafka.domain.com:9092";
4+
private static String TOPIC_NAME="topic";
5+
private static String GROUP_ID="group_id";
6+
7+
public static void main(String[] args) throws Exception{
8+
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
9+
env.enableCheckpointing(3000);
10+
11+
12+
//set EventTime,the default is ProcessingTime
13+
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
14+
15+
//get
16+
Properties sourceKafkaProperties = new Properties();
17+
sourceKafkaProperties.setProperty("bootstrap.servers",BOOTSTRAP_SERVER);
18+
sourceKafkaProperties.setProperty("group.id",GROUP_ID);
19+
20+
//compress data
21+
sourceKafkaProperties.put("compression.type", "gzip");
22+
String jaasTemplate = "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"username\" password=\"password\";";
23+
sourceKafkaProperties.put("security.protocol", "SASL_PLAINTEXT");
24+
sourceKafkaProperties.put("sasl.mechanism", "PLAIN");
25+
sourceKafkaProperties.put("sasl.jaas.config", jaasTemplate);
26+
27+
28+
FlinkKafkaConsumer010<String> consumer010 = new FlinkKafkaConsumer010(TOPIC_NAME,new SimpleStringSchema(),sourceKafkaProperties);
29+
30+
31+
32+
//解析数据
33+
DataStream<T> dataStream=env
34+
//DataStream<Long> dataStream=env
35+
.addSource(consumer010)
36+
.flatMap(new myFunction());
37+
38+
//抽取timestamp设置watermark
39+
DataStream<T> waterMarkStream = dataStream.assignTimestampsAndWatermarks(new AssignerWithPeriodicWatermarks<T>() {
40+
41+
Long currentMaxTimestamp = 0L;
42+
//允许最大乱序时间:10s
43+
final Long maxOutofOrderness = 10000L;
44+
45+
@Nullable
46+
@Override
47+
public Watermark getCurrentWatermark() {
48+
return new Watermark(currentMaxTimestamp-maxOutofOrderness);
49+
}
50+
51+
@Override
52+
public long extractTimestamp(T element, long previousElementTimestamp) {
53+
long timestamp = element.f0;
54+
currentMaxTimestamp = Math.max(timestamp,currentMaxTimestamp);
55+
56+
return timestamp;
57+
}
58+
});
59+
60+
61+
62+
DataStream<T> windowDatta = waterMarkStream
63+
.timeWindowAll(Time.minutes(1))
64+
.apply(new AllWindowFunction<T>, T, TimeWindow>() {
65+
@Override
66+
public void apply(TimeWindow window, Iterable<T> values, Collector<T> out) throws Exception {
67+
T l;
68+
out.collect(l);
69+
}
70+
});
71+
72+
windowDatta.print();
73+
74+
env.execute("kafka start");
75+
}
76+
}

java生态学习四.md

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Spring Boot连接mysql
2+
`Spring Boot`连接`mysql`可以用`jdbcTemplate`,这是整合好的工具包,特别的方便。不过也踩了个坑。
3+
4+
## 配置
5+
想要用到连接,就先配置好,就和python的导入模块一样
6+
```
7+
<dependency>
8+
<groupId>mysql</groupId>
9+
<artifactId>mysql-connector-java</artifactId>
10+
</dependency>
11+
<dependency>
12+
<groupId>org.springframework.boot</groupId>
13+
<artifactId>spring-boot-starter-jdbc</artifactId>
14+
</dependency>
15+
```
16+
`application.properties`中添加连接`mysql`的配置
17+
```
18+
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
19+
spring.datasource.username=root
20+
spring.datasource.password=password
21+
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
22+
spring.datasource.max-idle=10
23+
spring.datasource.max-wait=10000
24+
spring.datasource.min-idle=5
25+
spring.datasource.initial-size=5
26+
```
27+
`jdbc`连接到具体的某一个库名。
28+
> 运行起来可能会爆个小错误,Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.这个不影响项目的运行,就是说`com.mysql.jdbc.Driver`不用了,改用`com.mysql.cj.jdbc.Driver`了,自己改了也行
29+
30+
这就结束了,其余什么都不用配,然而代码里面,还是需要有个注意的。因为是使用的`JdbcTemplate`,不是直接就能用的,要先预定义下
31+
```
32+
@Resource
33+
private JdbcTemplate jdbcTemplate;
34+
```
35+
我一开始直接就调用`JdbcTemplate.queryForList`疯狂出错。查询函数有多个,我选用的是`queryForList`因为会返回一个`LIst`。当然也可以写`query`,然后需要传入自定义的函数。
36+
## demo
37+
一个demo
38+
```
39+
package com.example.demo;
40+
41+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
42+
import org.springframework.jdbc.core.JdbcTemplate;
43+
import org.springframework.web.bind.annotation.*;
44+
45+
import javax.annotation.Resource;
46+
import java.util.List;
47+
import java.util.Map;
48+
49+
@RestController
50+
@EnableAutoConfiguration
51+
public class hello {
52+
53+
@Resource
54+
private JdbcTemplate jdbcTemplate;
55+
//输出指定年份所有的信息
56+
@RequestMapping(value = {"/hello"},method = {RequestMethod.GET})
57+
public String say(@RequestParam(value = "year",required = false,defaultValue = "0") Integer year){
58+
if(year==0) {
59+
return "请输入正确的年份";
60+
}else {
61+
String sql = "select * from sales where year="+year;
62+
List<Map<String,Object>> list =jdbcTemplate.queryForList(sql);
63+
64+
return list.toString();
65+
}
66+
}
67+
}
68+
```
69+
`mybatis`本质上还是对`jdbc`的封装,它的优势在于:
70+
1. 集中管理
71+
所有的`sql`都在同一个`xml`文件中,方便管理
72+
2. 动态生成sql
73+
可以在`xml`中写条件判断,从而生成不同的`sql语句`
74+
```
75+
<select id="getCountByInfo" parameterType="User" resultType="int">
76+
select count(*) from user
77+
<where>
78+
<if test="nickname!=null">
79+
and nickname = #{nickname}
80+
</if>
81+
<if test="email!=null">
82+
and email = #{email}
83+
</if>
84+
</where>
85+
</select>
86+
```
87+
劣势在于相比于`jdbc`更慢,因为`jdbc`更底层。

0 commit comments

Comments
 (0)