0%

SpringBoot编写自己的starter

SpringBoot是约定优于配置产物,其核心就是所对应的starter,只要在配置文件中填写所需要的参数,就能够实现自动配置。

用阿里云ONS为例,编写一个自定义starter用于发送消息。

开始

新建一个maven模块,增加对应库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

<groupId>com.zxcvbnmzsedr</groupId>
<artifactId>ons-module</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>1.3.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.aliyun.openservices</groupId>
<artifactId>ons-client</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
</dependencies>

几个核心类:

  • OnsClient: 注解,方法返回值直接发送到阿里云
  • OnsClientAspect: 注解的AOP实现
  • OnsAutoConfiguration: 整个项目的配置
  • OnsProperties: 用于提取配置文件

OnsClient:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnsClient {
/**
* 阿里云的topicId
*/
String topicId();

/**
* 指定tags
*/
String tags();

/**
* producerId
*/
String producerId();
}

OnsClientAspect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Component
@Aspect
public class OnsClientAspect {
private Logger logger = LoggerFactory.getLogger(OnsAutoConfiguration.class);
@Autowired
private Map<String,Producer> onsProducer;
@Pointcut("@annotation(com.zxcvbnmzsedr.ons.annotation.OnsClient)")
private void cut() { }

@Around(value = "cut()&& @annotation(onsClient)")
public Object aroundMethod(ProceedingJoinPoint point, OnsClient onsClient) {
Object result = null;
String producerId = onsClient.producerId();
String tags = onsClient.tags();
Producer producer = onsProducer.get(producerId);
try {
producer.start();
result = point.proceed();
Message message = new Message(onsClient.topicId(),tags, JSON.toJSONBytes(result));
SendResult sendResult = producer.send(message);
assert sendResult != null;
logger.info("messageId"+sendResult.getMessageId());
} catch (ONSClientException e){
logger.error(e.getMessage());
} catch (Throwable e) {
logger.error(e.getMessage());
} finally {
producer.shutdown();
}
return result;
}
}

OnsAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
@EnableConfigurationProperties(OnsProperties.class)
public class OnsAutoConfiguration {
@Autowired
private OnsProperties onsProperties;

@Bean
public Map<String,Producer> onsProducer(){
Map<String,Producer> producerMap = new HashMap<String, Producer>();
for(String producer:onsProperties.getProducerIds()){
ProducerBean producerBean = new ProducerBean();
Properties properties = new Properties();
properties.put(PropertyKeyConst.ProducerId, producer);
properties.put(PropertyKeyConst.AccessKey, onsProperties.getAccessKey());
properties.put(PropertyKeyConst.SecretKey, onsProperties.getAccessKeySecret());
properties.put(PropertyKeyConst.ONSAddr, onsProperties.getOnsAddr());
producerBean.setProperties(properties);
producerMap.put(producer,producerBean);
}
return producerMap;
}

@Bean
public OnsClientAspect onsClientAspect(){
return new OnsClientAspect();
}
}

OnsProperties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@ConfigurationProperties(prefix = "ons")
public class OnsProperties {

private String accessKey;

private String accessKeySecret;

private String onsAddr;

private String[] producerIds;

private String producerId;
@PostConstruct
public void init() {
this.producerIds = producerId.split(",");
}

public String[] getProducerIds() {
return producerIds;
}

public void setProducerIds(String[] producerIds) {
this.producerIds = producerIds;
}

public String getProducerId() {
return producerId;
}

public void setProducerId(String producerId) {
this.producerId = producerId;
}

public String getAccessKey() {
return accessKey;
}

public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}

public String getAccessKeySecret() {
return accessKeySecret;
}

public void setAccessKeySecret(String accessKeySecret) {
this.accessKeySecret = accessKeySecret;
}

public String getOnsAddr() {
return onsAddr;
}

public void setOnsAddr(String onsAddr) {
this.onsAddr = onsAddr;
}
}

src/main/resources目录下新建META-INF文件夹,然后新建spring.factories文件

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zxcvbnmzsedr.ons.autoconfigure.OnsAutoConfiguration

把这几项配置起来就能使用了

使用方法

在pom文件引用ons模块

1
2
3
4
5
<dependency>
<groupId>com.zxcvbnmzsedr</groupId>
<artifactId>ons-module</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

配置文件application.yml

1
2
3
4
5
6
ons:
accessKey: XXX
accessKeySecret: XXX
onsAddr: XXX
# 如果有多个生产者,使用逗号隔开
producerId: XXX,XXX,XXX

在使用时候会把返回值直接序列化成json直接发送到ONS上,
需要指定topicId,producerId,tags

1
2
3
4
5
@OnsClient(topicId = "XXX",producerId = "XXX",tags = "XXX")
public String test(){

return "ddd";
}

代码在github上,https://github.com/zxcvbnmzsedr/ons-module