Skip to content

Commit

Permalink
refactor: migrate custom annotations and undertow pool config and Aft…
Browse files Browse the repository at this point in the history
…erInitRunner to kotlin
  • Loading branch information
AkagiYui committed Apr 20, 2024
1 parent bc25d0e commit 933dfb4
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 202 deletions.
39 changes: 0 additions & 39 deletions src/main/java/com/akagiyui/drive/component/AfterInitRunner.java

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

35 changes: 35 additions & 0 deletions src/main/kotlin/com/akagiyui/drive/component/AfterInitRunner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.akagiyui.drive.component

import com.akagiyui.common.delegate.LoggerDelegate
import com.akagiyui.drive.service.ConfigService
import com.akagiyui.drive.task.InitializeTasks
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.ApplicationRunner
import org.springframework.stereotype.Component

/**
* 应用启动事件
*
* @author AkagiYui
*/
@Component
class AfterInitRunner @Autowired constructor(
private val configService: ConfigService,
private val initializeTasks: InitializeTasks,
) : ApplicationRunner {
private val log by LoggerDelegate()

override fun run(args: ApplicationArguments?) {
log.debug("====================== ApplicationStarted ======================")
// 初始化检查
if (!configService.isInitialized()) {
initializeTasks.preCheck()
initializeTasks.initConfig()
initializeTasks.addRoleAndUser()
configService.setInitialized(true)
log.info("Initialize success")
}
log.debug("==================== ApplicationInitialized ====================")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.akagiyui.drive.component.limiter

import com.akagiyui.common.delegate.LoggerDelegate
import com.akagiyui.common.exception.TooManyRequestsException
import com.google.common.collect.Maps
import com.google.common.util.concurrent.RateLimiter
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.reflect.MethodSignature
import org.springframework.stereotype.Component

/**
* 限流 AOP
* @author AkagiYui
*/
@Suppress("UnstableApiUsage")
@Aspect
@Component
class FrequencyLimitAspect {
private val log by LoggerDelegate()

/**
* 限流器字典
* map的key为 Limit.key
*/

private val limitMap: MutableMap<String, RateLimiter> = Maps.newConcurrentMap()

@Around("@annotation(Limit)")
@Throws(Throwable::class)
fun around(joinPoint: ProceedingJoinPoint): Any {
// 获取方法签名
val signature = joinPoint.signature as MethodSignature
val method = signature.method
// 获取 Limit 注解
val limit = method.getAnnotation(Limit::class.java)
if (limit != null) {
val key = limit.key
// 验证缓存是否有命中 key
val rateLimiter = if (!limitMap.containsKey(key)) {
// 创建令牌桶
val rateLimiter = RateLimiter.create(limit.permitsPerSecond)
limitMap[key] = rateLimiter
log.debug("Created RateLimiter: {}", limitMap[key])
rateLimiter // 减少一次访问
} else {
limitMap[key] as RateLimiter
}
// 获取令牌
val acquire = rateLimiter.tryAcquire(limit.timeout, limit.timeunit)
// 拿不到令牌,抛出异常
if (!acquire) {
log.debug("Too many requests: {}", key)
throw TooManyRequestsException()
}
}
return joinPoint.proceed()
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.akagiyui.drive.component.limiter;
package com.akagiyui.drive.component.limiter

import java.util.concurrent.TimeUnit

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
* 限流注解
Expand All @@ -13,28 +13,28 @@
* 注解生命周期:运行时
* @author AkagiYui
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface Limit {
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Limit(
/**
* 资源的key,唯一
* 作用:不同的接口,不同的流量控制
*/
String key() default "";
val key: String = "",

/**
* 每秒放入令牌桶的token数量
*/
double permitsPerSecond();
val permitsPerSecond: Double,

/**
* 获取令牌最大等待时间
*/
long timeout();
val timeout: Long = 0,

/**
* 等待时间单位(例:分钟/秒/毫秒) 默认:毫秒
*/
TimeUnit timeunit() default TimeUnit.MILLISECONDS;
}
val timeunit: TimeUnit = TimeUnit.MILLISECONDS,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.akagiyui.drive.component.permission

import com.akagiyui.common.ResponseEnum
import com.akagiyui.common.exception.CustomException
import com.akagiyui.drive.model.Permission
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Component

/**
* 权限校验切面
*
* @author AkagiYui
*/
@Aspect
@Component
class PermissionCheckAspect {

@Before("@annotation(requiredPermission)")
@PreAuthorize("isAuthenticated()")
fun checkPermission(requiredPermission: RequirePermission) {
// 获取当前用户的权限
val authentication = SecurityContextHolder.getContext().authentication
val userDetails = authentication.principal as UserDetails
val authorities: Set<Permission> = userDetails.authorities.map { Permission.valueOf(it.authority) }.toSet()

// 获取注解中的权限
val permissions = requiredPermission.value
val permissionList: Set<Permission> = permissions.toSet()

// 校验权限
if (!authorities.containsAll(permissionList)) {
throw CustomException(ResponseEnum.UNAUTHORIZED)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.akagiyui.drive.component.permission

import com.akagiyui.drive.model.Permission

/**
* 权限校验注解
*
* @author AkagiYui
*/
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class RequirePermission(
val value: Array<Permission> = [],
)
Loading

0 comments on commit 933dfb4

Please sign in to comment.