Kotlin-遇到的问题
参考文献
Kotlin项目中使用SpringBoot Aop切面报错Caused by: java.lang.IllegalArgumentException: Cannot subclass final class com.holelin.controller.XXXController
-
环境依赖
-
Gradle
-
Kotlin
-
SpringBoot 2.2.2.RELEASE
1
2
3
4
5
6// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter
implementation "org.springframework.boot:spring-boot-starter:$springboot_version"
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
implementation "org.springframework.boot:spring-boot-starter-web:$springboot_version"
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop
implementation "org.springframework.boot:spring-boot-starter-aop:$springboot_version" -
Spring Kafka 2.4.3.RELEASE
1
2// https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka
implementation 'org.springframework.kafka:spring-kafka:2.4.3.RELEASE'
-
-
注解
1
2
3
4
annotation class LoginRequired{
} -
切面类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.aspectj.lang.annotation.Pointcut
import org.springframework.stereotype.Component
import javax.servlet.http.HttpServletRequest
open class LoginRequiredInterceptor {
fun pointCut(){
}
fun before(){
println("before ..")
}
} -
注解使用类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import com.holelin.annotations.LoginRequired
import com.holelin.mq.kafka.KafkaProducer
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
class KafkaController {
private lateinit var kafkaProducer: KafkaProducer
fun sendMessage() {
kafkaProducer.sendMessage()
}
}-
辅助类
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
35import cn.hutool.core.date.DateTime
import cn.hutool.json.JSONUtil
import com.github.javafaker.Faker
import com.holelin.domain.AccessRecord
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.kafka.core.KafkaTemplate
import org.springframework.stereotype.Component
class KafkaProducer {
private lateinit var kafkaTemplate: KafkaTemplate<String, String>
private val testTopic: String = "UserInfo"
fun sendMessage() {
var accessRecord = AccessRecord()
var faker = Faker()
println(faker.address().toString())
println(faker.artist().toString())
accessRecord.apply {
this.ip = "192.168.0.1"
this.accessTime = DateTime.now()
this.param = JSONUtil.parseObj(faker.ancient()).toString()
this.url = "/kafka/send"
this.requestMethod = "POST"
this.username = "holelin"
this.response = JSONUtil.parseObj(faker.address()).toString()
this.accessServiceName = "kotlin-demo"
}
var send = kafkaTemplate.send(testTopic, JSONUtil.toJsonStr(accessRecord))
send.addCallback({ result -> println(result) }, { ex -> println(ex) })
}
}
-
错误信息
1 | Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class com.holelin.controller.KafkaController: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class com.holelin.controller.KafkaController |
AOP切面不正常的原因
-
需要AOP拦截的类是否是final的,final类不可使用CGLIB来代理。
-
是否在给BEAN配AOP的时候强制使用CGLIB,如果是则可指定proxyTargetClass属性以让spring强制代理目标类。
-
类是否被多次代理了,如果类被多次代理过,则第二次进行代理的时候拿到的是第一次代理后的对象,这个对象是个final形式的,所以会出现这个错误。
当前错误原因
KafkaController
为final
类
解决方法
-
给
KafkaController
类前加open
关键字1
2
3
4
5
6
7
8
9
10
11
12
open class KafkaController {
private lateinit var kafkaProducer: KafkaProducer
fun sendMessage() {
kafkaProducer.sendMessage()
}
} -
此时出现第二个问题自动注入的
KafkaProducer
为null
-
处理办法使用Kotlin官方插件:All-open compiler plugin
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
55buildscript {
ext{
dcm4che_version = '5.21.0'
springboot_version= '2.2.2.RELEASE'
hutool_version="5.7.7"
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:1.5.21"
}
}
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.4.32'
id "org.jetbrains.kotlin.plugin.spring" version "1.5.21"
}
group 'org.example'
version '1.0-SNAPSHOT'
apply plugin: "kotlin-spring"
repositories {
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://raw.github.com/nroduit/mvn-repo/master/'}
maven { url 'https://www.dcm4che.org/maven2/'}
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib"
//SpringBoot
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter
implementation "org.springframework.boot:spring-boot-starter:$springboot_version"
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
implementation "org.springframework.boot:spring-boot-starter-web:$springboot_version"
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor
implementation "org.springframework.boot:spring-boot-configuration-processor:2.2.2.RELEASE"
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator
implementation "org.springframework.boot:spring-boot-starter-actuator:$springboot_version"
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop
implementation "org.springframework.boot:spring-boot-starter-aop:$springboot_version"
// https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka
implementation 'org.springframework.kafka:spring-kafka:2.4.3.RELEASE'
}
compileKotlin {
kotlinOptions.jvmTarget = "11"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "11"
}
Kotlin List转Map
1 | val colors: List<Color> = listOf( |
Kotlin Collection
VS Kotlin Sequence
VS Java Stream
集合中函数式API
- Kolin 的集合分为可变集合(mutable collection)和不可变集合(immutable collection)。不可变集合是 List、Set、Map,它们是只读类型,不能对集合进行修改。可变集合是 MutableList、MutableSet、MutableMap,它们是支持读写的类型,能够对集合进行修改的操作。
filter
1 | listOf(5, 12, 8, 33) // 创建list集合 |
map
1 | listOf("java","kotlin","scala","groovy") |
flatMap
- 遍历所有的元素,为每一个创建一个集合,最后把所有的集合放在一个集合中。
1 | val newList = listOf(5, 12, 8, 33) |
Sequence
- 序列(Sequence)是 Kotlin 标准库提供的另一种容器类型。序列与集合有相同的函数 API,却采用不同的实现方式。
- Kotlin 的 Sequence 更类似于 Java 8 的 Stream,二者都是延迟执行。Kotlin 的集合转换成 Sequence 只需使用
asSequence()
方法。
1 | listOf(5, 12, 8, 33) |
- 使用 Sequence 有助于避免不必要的临时分配开销,并且可以显着提高复杂处理 PipeLines 的性能。
Sequence VS Stream
-
Sequence 和 Stream 都使用的是惰性求值。
在编程语言理论中,惰性求值(英语:Lazy Evaluation),又译为惰性计算、懒惰求值,也称为传需求调用(call-by-need),是一个计算机编程中的一个概念,目的是要最小化计算机要做的工作。它有两个相关而又有区别的含意,可以表示为“延迟求值”和“最小化求值”。除可以得到性能的提升外,惰性计算的最重要的好处是它可以构造一个无限的数据类型。
特性对比 | Sequence | Stream |
---|---|---|
autoboxing |
会发生自动装箱 | 对于原始类型可以避免自动装箱 |
parallelism |
不支持 | 支持 |
跨平台 | 支持 Kotlin/JVM、Kotlin/JS、Kotlin/Native 等多平台 | 只能在 Kotlin/JVM 平台使用,并且 jvm 版本需要>=8 |
易用性 | 更简洁、支持更多的功能 | 使用 Collectors 进行终端操作会使 Stream 更加冗长。 |
性能 | 大多数终端操作符是 inline 函数 | 对于值可能不存在的情况,Sequence 支持可为空的类型,而 Stream 会创建 Optional包装器。因此会多一步的对象创建 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 HoleLin's Blog!