一、常見問(wèn)題描述
因?yàn)镴DK版本升級(jí)的改動(dòng),在Jdk9~17環(huán)境下,搭建Springboot項(xiàng)目,會(huì)出現(xiàn)原有@Resource(javax.annotation.Resource)不存在的問(wèn)題,導(dǎo)致項(xiàng)目從Jdk8遷移到高版本時(shí)遇到的問(wèn)題
原因
你可能會(huì)問(wèn),為什么javax.annotation.Resource注解不存在呢?
?從Jdk9開始,JavaEE從Jdk中分離,jdk就移除掉了javax.annotation.jar包的默認(rèn)集成,從而導(dǎo)致版本不兼容。所以一旦spring項(xiàng)目從JDK8升到高版本,都會(huì)出現(xiàn)javax.annotation.Resource無(wú)法引用報(bào)紅。
java EE 即 java Enterprise Edition,企業(yè)級(jí)應(yīng)用,目標(biāo)是制定一系列企業(yè)級(jí)應(yīng)用的標(biāo)準(zhǔn)服務(wù)。常見的?
javax.servlet
,?javax.annotation
。Oracle 收購(gòu)了創(chuàng)造 java 的 SUN 公司,Oracle 又不想發(fā)展 java EE 了,就把 java EE 交給 Eclipse 社區(qū)了,但是又因?yàn)椴恢脑颍股鐓^(qū)使用?
javax
?這個(gè)名字。所以,javax.servlet
?就變成了?jakarta.servlet
,?jakarta.annotation
。api無(wú)法向前兼容。?java ee 的最后一個(gè)版本也是 8,以后就再也沒(méi)有 java ee 的新版本
二、各版本出現(xiàn)的問(wèn)題和解決方案
2.1 Jdk9以上、Springboot3/Spring6.0以前版本的問(wèn)題
解決方案:
1、手動(dòng)導(dǎo)入javax.annotation包
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
?2、降到Jdk8,你發(fā)任你發(fā),我用Java8
2.2 Springboot3/Spring6.0以上版本的問(wèn)題
從Java EE APIs 到 Jakarta EE
Spring Boot 3開始,所有的Java EE Api都需要遷移到Jakarta EE上來(lái)。
大部分用戶需要修改import相關(guān)API的時(shí)候,要用jakarta替換javax。比如:原來(lái)引入javax.servlet.Filter的地方,需要替換為jakarta.servlet.Filter
但是當(dāng)Spring版本升級(jí)到6.0以上的版本,即使手動(dòng)引入javax.annotation包,但是還是會(huì)有問(wèn)題,你會(huì)發(fā)現(xiàn)類無(wú)法注入,導(dǎo)致引用的類is Null,報(bào)空指針。
因?yàn)镾pring也放棄了javax.annotation.Resource注解的支持,而是對(duì)jakarta.annotation.Resource注解的支持文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-758255.html
private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
return InjectionMetadata.EMPTY;
} else {
List<InjectedElement> elements = new ArrayList();
Class targetClass = clazz;
do {
List<InjectedElement> currElements = new ArrayList();
ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new CommonAnnotationBeanPostProcessor.EjbRefElement(field, field, (PropertyDescriptor)null));
} else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new CommonAnnotationBeanPostProcessor.ResourceElement(field, field, (PropertyDescriptor)null));
}
}
});
ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pdx = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new CommonAnnotationBeanPostProcessor.EjbRefElement(method, bridgedMethod, pdx));
} else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new CommonAnnotationBeanPostProcessor.ResourceElement(method, bridgedMethod, pd));
}
}
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
} while(targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
}
通過(guò)跟代碼進(jìn)去,發(fā)現(xiàn)@Resouce的源代碼是?jakarta.annotation下的文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-758255.html
package jakarta.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Resources.class)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default Object.class;
Resource.AuthenticationType authenticationType() default Resource.AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
public static enum AuthenticationType {
CONTAINER,
APPLICATION;
private AuthenticationType() {
}
}
}
到了這里,關(guān)于JDK9~17+Springboot3 @Resource常見問(wèn)題和解決方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!