AEM环境中@Inject注入服务触发空指针,@Reference可成功注入
咱先拆解下你遇到的问题:在用org.apache.felix.maven-scr-plugin构建AEM OSGi组件时,给@SlingServlet修饰的MyServlet用javax.inject.Inject注入MyConfigurationService会报空指针,但换成org.apache.felix.scr.annotations.Reference就正常,核心原因是插件和注解体系不兼容。
为啥@Inject会失效?
maven-scr-plugin是基于旧版的Felix SCR注解体系工作的——它只会识别org.apache.felix.scr.annotations包下的注解(比如@Reference、@Component),根本不认识javax.inject.Inject这类属于OSGi Declarative Services(DS)的注解。所以插件在生成OSGi组件元数据时,完全不会处理@Inject标记的字段,导致你的myConfigurationService一直是null,调用方法自然就抛空指针了。
两种可行的解决办法
办法1:继续使用SCR注解体系(快速适配)
如果你暂时不想调整构建插件,直接沿用@Reference注解就没问题,这也是maven-scr-plugin原生支持的方式:
import org.apache.felix.scr.annotations.Reference; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.servlets.annotations.SlingServlet; @SlingServlet(paths = "/content/my/servlet/path") public class MyServlet extends SlingSafeMethodsServlet { @Reference private MyConfigurationService myConfigurationService; // 后续调用myConfigurationService的方法就正常了 }
办法2:迁移到OSGi DS注解体系(推荐长期方案)
现在AEM官方更推荐使用OSGi Declarative Services(DS)的注解体系,你需要把构建插件换成支持DS的maven-bundle-plugin,同时调整注解:
- 替换Maven插件:在pom.xml中移除
maven-scr-plugin,添加并配置maven-bundle-plugin,确保它能处理DS注解:
<plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>5.1.9</version> <extensions>true</extensions> <configuration> <instructions> <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName> <Bundle-Version>${project.version}</Bundle-Version> <!-- 启用DS注解处理 --> <Service-Component>OSGI-INF/*.xml</Service-Component> <Export-Package>com.yourpackage.*</Export-Package> </instructions> </configuration> </plugin>
- 调整Servlet类的注解,使用DS的
@Component和@Inject:
import javax.inject.Inject; import org.osgi.service.component.annotations.Component; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.servlets.annotations.SlingServletResourceTypes; // 用DS的@Component标记为OSGi组件,配合SlingServlet的注解 @Component(service = {javax.servlet.Servlet.class}) @SlingServletResourceTypes( resourceTypes = "your-project/components/page", methods = "GET" ) public class MyServlet extends SlingSafeMethodsServlet { @Inject private MyConfigurationService myConfigurationService; // 现在调用myConfigurationService就不会空指针了 }
注意:如果你的Servlet是通过路径绑定的,也可以用
@SlingServlet(paths = "/content/my/path"),但要确保@Component的service属性包含javax.servlet.Servlet.class,这样OSGi才能识别它是一个Servlet服务。
内容的提问来源于stack exchange,提问作者Alexander Staroselsky

