[英]Can spring annotation access method parameters?
考慮一個UrlValidator
方法注釋,該注釋在調用方法之前測試給定的url是否有效。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UrlValdator{
String value();
}
當路由是靜態的並且提前知道時,這可以正常工作。 例如:
@UrlValidator("http://some.known.url")
public void doSomething();
但這不是很靈活。 例如,如果路由在doSomething()
方法簽名中是隱式的,該怎么辦? 我可以以某種方式通過Spring Expression Language或其他方式訪問它嗎? 例如, 這不起作用,但這是我要拍攝的
@UrlValidator("#p1")
public void doSomething(String url)
要么
@UrlValidator("#p1.url")
public void doSomething(Request request)
是否可以通過這種方式使注釋動態化?
這是我找到的最接近的線程,但是線程較舊,可以接受的答案非常麻煩/難以遵循。 是否有一個最小的工作示例/更新的方式來做到這一點?
我不確定這是否是您的初衷,但是我建議使用Spring AOP,因為它可以為您提供很大的靈活性。
既然您在評論之一中提到您已經在使用Spring AOP,所以我假設您已將spring-boot-starter-aop
為依賴項,並且已啟用對組件的支持。通過使用@EnableAspectJAutoProxy
注釋您的一個配置類來標記@Aspect
例如,具有這樣的注釋:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface EnsureUrlValid {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface UrlToVerify {
}
我可以在示例彈簧組件中使用它們,如下所示:
@Component
public class SampleComponent {
private static final Logger logger = LogManager.getLogger(SampleComponent.class);
@EnsureUrlValid
public void fetchData(String url) {
logger.info("Fetching data from " + url);
}
@EnsureUrlValid
public long fetchData(Long id, @UrlToVerify String url) {
logger.info("Fetching data for user#" + id + " from " + url);
// just to show that a method annotated like this can return values too
return 10L;
}
@EnsureUrlValid
public void fetchDataFailedAttempt() {
logger.info("This should not be logged");
}
}
這是EnsureUrlValid
批注的樣本“處理器”。 它查找帶注釋的方法,嘗試提取傳入的url,並根據url是否有效,繼續調用該方法或引發異常。 很簡單,但是它表明您可以完全控制所注釋的方法。
@Aspect
@Component
public class UrlValidator {
@Around(value = "@annotation(EnsureUrlValid)")
public Object checkUrl(ProceedingJoinPoint joinPoint) throws Throwable {
final Optional<String> urlOpt = extractUrl(joinPoint);
if (urlOpt.isPresent()) {
final String url = urlOpt.get();
if (isUrlValid(url)) {
return joinPoint.proceed();
}
}
throw new RuntimeException("The passed-in url either could not be resolved or is not valid");
}
private Optional<String> extractUrl(JoinPoint joinPoint) {
Object[] methodArgs = joinPoint.getArgs();
Object rawUrl = null;
if (methodArgs.length == 1) {
rawUrl = methodArgs[0];
}
else if (methodArgs.length > 1) {
// check which parameter has been marked for validation
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
Parameter[] parameters = method.getParameters();
boolean foundMarked = false;
int i = 0;
while (i < parameters.length && !foundMarked) {
final Parameter param = parameters[i];
if (param.getAnnotation(UrlToVerify.class) != null) {
rawUrl = methodArgs[i];
foundMarked = true;
}
i++;
}
}
if (rawUrl instanceof String) { // if rawUrl is null, instanceof returns false
return Optional.of((String) rawUrl);
}
// there could be some kind of logic for handling other types
return Optional.empty();
}
private boolean isUrlValid(String url) {
// the actual validation logic
return true;
}
}
我希望這會有所幫助。
簡短的回答:是的。
長答案: ElementType指定注釋的目標,可以是以下內容: ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE, and TYPE_PARAMETER
。 在這里對PARAMETER
感興趣。 由於我們希望編譯器運行我們的代碼,因此RetentionPolicy.RUNTIME
適合保留類型。 接下來,我們必須添加@Constraint
批注,根據文檔:
將注釋標記為Bean驗證約束。
這意味着,Spring將選擇您的參數並在運行時對其進行驗證。 我們要做的最后一件事是實現驗證本身,這意味着創建一個實現ConstraintValidator
接口的類。
放在一起:
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UrlValidatorImplementation.class)
public @interface UrlValidator{
String message() default "Invalid url";
}
UrlValidatorImplementation
類的實現:
public class UrlValidatorImplementation implements ConstraintValidator<UrlValidator, String> {
@Override
public void initialize(UrlValidator annotation) {
// initialization, probably not needed
}
@Override
public boolean isValid(String url, ConstraintValidatorContext context) {
// implementation of the url validation
}
}
注釋的用法:
public void doSomething(@UrlValidator url) { ... }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.