我正在创建一个公共库,并希望添加一个使用ServletContext
的服务。但是由于库也应该在cli
环境中使用,我必须找到一种方法告诉spring忽略那里的servlet。
@Component
public class MyService {
//only available in a web environment
@Autowired(required = false)
private ServletContext servletContext;
}
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<optional>true</optional>
</dependency>
在实现项目中,我只想运行命令行界面,因此我没有包含servlet依赖项。
但是当我尝试启动时,启动时抛出以下异常:
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext
问题:如何使用ServletContext
中的CommonService
而不必将依赖项添加到重用该类的每个项目中?
答案 0 :(得分:3)
只需包含servlet依赖项,并使依赖项可选。所有其他选择都更糟糕。
这是一个相当轻量级的类 - 对于servlet规范3.1.0的jar来说是93K。
但是如果你绝对必须在类路径上没有类的情况下运行那么你可以执行以下操作......
首先让我说你遇到问题的原因不是因为ServletContext是一个字段,而是因为它是一个自动连接的字段。我写了一个小测试应用程序,并且不需要在运行时提供类的字段类型。
因此,要使其工作,您需要一个配置文件和一个命名bean。
首先,您需要按名称注入ServletContext,而不是将其键入ServletContext。这不是很好,因为当你需要使用它时,你需要将它转换为servlet上下文。
所以
@Autowired(required = false)
@Qualifier("servletContext")
Object servletContext
就是你要放在这里的。
然后创建另一个将提供serlvet上下文的类 - 这将通过一个配置文件打开 - 或者可能是@membersound引用的@ConditionalOnWebApplication仅在Spring Boot中可用。
@Configuration
@Profile("web") or @ConditionalOnWebApplication
public class ServletContextProvider {
@Autowired
ServletContext servletContext;
@Bean("servletContext")
public ServletContext getServletContext() {
return servletContext;
}
}
就像我说的那样,只需在类路径中包含ServletContext。
答案 1 :(得分:0)
幸运的是,有以下注释可以直接添加到课程中:
@ConditionalOnWebApplication
@ConditionalOnNotWebApplication
这样,cli环境中的spring不需要评估ServletContext
bean。
当然,这需要创建两个服务类,其中每个服务类都有一个上面的注释。
public abstract class MyService {
abstract String impl();
}
@Component
class MyServiceCLI {
@Override
String impl() {
return "cli specific";
}
}
@Component
class MyServiceWeb {
//only available in a web environment
@Autowired
private ServletContext servletContext;
@Override
String impl() {
//use servlet context...
return "ctx specific";
}
}
然后只注入@Autowired MyService
。
通过使实现包私有,它们对用户是不可见的,但Spring仍然会看到并创建它们。