当前位置: 首页 > 知识库问答 >
问题:

如何使用静态编程语言在Spring Boot中处理自定义注释?

百里伟
2023-03-14

上下文:我想在Spring Boot中创建一个自定义注释,并为处理添加额外的逻辑。我举了一个注释非常简单的例子,但我希望有几个这样的注释具有更细粒度的控制。

解决这个问题有几种方法:

  • 创建过滤器
  • 创建拦截器
  • 使用自定义处理创建注释

我必须使用最新的一个,因为上面两个不适用于我的用例。

问题:

我在静态编程语言中有一个自定义注释,我希望它被注册并在运行时被检查。

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class OfflineProcessing(val allow: Bool)

REST控制器如下:

@RestController
class ApiController {

    @GetMapping("/api/version")
    @OfflineProcessing(true)
    fun apiVersion(): String {
        return "0.1.0"
    }
}

其思想是每个方法都有注释,并根据线性处理的允许与否,生成条件逻辑。

我已经尝试过创建基本的PostBean处理机

@Component
class OfflineProcessingAnnotationProcessor @Autowired constructor(
        val configurableBeanFactory: ConfigurableListableBeanFactory
) : BeanPostProcessor {

    @Throws(BeansException::class)
    override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any? {
        println("Before processor. Bean name: $beanName, Bean: $bean. Bean factory: $configurableBeanFactory.")
        return super.postProcessBeforeInitialization(bean, beanName)
    }

    @Throws(BeansException::class)
    override fun postProcessAfterInitialization(bean: Any, beanName: String): Any? {
        println("After processor. Bean name: $beanName, Bean: $bean. Bean factory: $configurableBeanFactory.")
        return super.postProcessAfterInitialization(bean, beanName)
    }

}

很明显,注释不会在BeanPost处理机的其他注释中被记录,我混淆了如何访问它,到目前为止,我没有找到任何其他没有BeanPost处理机的好例子。

依赖性:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

我做错什么了吗?还是我试图用错误的方法来完成任务?


共有2个答案

南宫胡媚
2023-03-14

这是一个一般性的问题,不是科特林特有的。

我认为,你试图解决这个问题的误解是,你在使用BeanPostProcessor。bean是在早期阶段创建的,它可能是一个单例,因此在执行rest请求时不会调用它。这意味着您需要检查一个包含注释的bean,然后在其上创建一个代理bean,并将您的逻辑嵌入到该代理中。

这与AOP的做法非常相似,@eol的方法是匹配复活节。

我想建议使用拦截器,但不是bean创建拦截器。

我的答案是受Spring Boot添加Http请求拦截器的启发

定义注释

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class OfflineProcessing(val allow: Boolean)

定义拦截器

@Component
class CustomRestAnnotationInterceptor:HandlerInterceptor {
    private val logger: Logger = LoggerFactory.getLogger(this.javaClass)

    override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
        if (handler is HandlerMethod) {
            var isOffline: OfflineProcessing? = handler.getMethodAnnotation(OfflineProcessing::class.java)
            if (null == isOffline) {
                isOffline = handler.method.declaringClass
                    .getAnnotation(OfflineProcessing::class.java)
            }
            if (null != isOffline) {
                logger.info("method called has OfflineProcessing annotation with allow=${isOffline.allow}" )
            }
        }
        return true
    }
}

将拦截器添加到路径

@Configuration
class WebConfig : WebMvcConfigurer {
    @Autowired
    lateinit var customRestAnnotationInterceptor: CustomRestAnnotationInterceptor

    override fun addInterceptors(registry: InterceptorRegistry) {
        // Custom interceptor, add intercept path and exclude intercept path
        registry.addInterceptor(customRestAnnotationInterceptor).addPathPatterns("/**")
    }
}

使用控制器上的注释

日志会显示

2022-04-14 08:48:58.785  INFO 32595 --- [nio-8080-exec-1] .h.s.k.q.CustomRestAnnotationInterceptor : method called has OfflineProcessing annotation with allow=true
郑安晏
2023-03-14

这不是对你的问题的直接回答,但是在这种情况下,我只是简单地使用Spring AOP,而不是实现BeanPost处理机。要做到这一点,您可以定义以下注释和相应的方面,例如:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
annotation class OfflineProcessing(val allowed: Boolean = true)

@Aspect
@Component
class OfflineProcessingAspect {
    @Pointcut("@annotation(<path.to.annotation.package>.OfflineProcessing)")
    fun offlineProcessingPointcut(offlineProcessing: OfflineProcessing?) {
    }

    @Around("offlineProcessingPointcut(offlineProcessing)")
    @Throws(Throwable::class)
    fun around(pjp: ProceedingJoinPoint, offlineProcessing: OfflineProcessing): Object {
        if (offlineProcessing.allowed()) {               
           // your pre-processing logic here
           val result = pjp.proceed()
           // post-processing logic here
           return result
        }
        // do the same for non-allowed offline-processing ...
    }
}

最后,添加以下依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
 类似资料:
  • 我有以下问题:-创建了几个模块来实现类,并用-我的Android应用程序正在使用检索这些类。但是由于某种原因,没有在

  • 我试图转换一些使用Jackson的@JsonSubTypes注释来管理多态性的Java代码。 以下是可用的Java代码: 以下是我认为等效的Kotlin代码: 但我在三行“JsonSubTypes.Type”中的每一行都会出现以下错误: 知道吗?

  • 暴露0.27.1是否能够翻译以下SQL语句? 下面是我尝试的内容,但不幸的是,子查询独立于查询的其余部分工作。 此外,如果可能的话,那么如何使用别名从ResultRow获取结果?在这个示例之后,解决方案似乎是将整个子查询存储在单个变量中,并使用一个alias()方法调用,但这看起来很难看。有没有更好的方法?

  • 我使用以下方法将KSP与Room结合使用: 这确实有效。但是,当我尝试运行它时,我会收到此警告 [ksp]我的数据库。kt:11:Schema导出目录未提供给注释处理器,因此无法导出架构。您可以提供注释处理器参数或将exportSchema设置为false。 为此:在使用KSP时,如何提供注释处理器参数?

  • 为了描述Gradle构建脚本,我们可以通过< code>build.gradle.kts文件使用Kotlin。在< code>dependencies和build 部分全局定义要使用的Kotlin版本是一个常见的问题(在给定的情况下使用不同的版本是相当罕见的)。 请考虑以下代码 (Gradle 4.3.1): 如您所见,kotlin(在本例中为1.2.30)定义了两次:和,它们通常没有区别。由于D

  • 我正在学习静态编程语言,我在函数方面有一些问题。我试图创建一个带有通用参数的函数接口。Java我会创建这样的东西: 然后我可以在其他地方像这样使用它(给定扩展: 你是怎么和Kotlin写这篇文章的? 我尝试的第一件事是使用如下类型别名: 但是,当我将绑定添加到type参数时,它停止了工作: 第二种方法是编写一个扩展函数类型的接口: 然而,现在我不知道如何用这个来实例化lambda函数。当我从中创建