简体   繁体   English

如何在春季添加可选的依赖项类?

[英]How to add optional dependency class in spring?

I'm creating a common library and would like to add a service that uses ServletContext . 我正在创建一个公共库,并想添加一个使用ServletContext的服务。 But as the library should also be used in a cli environment, I have to find a way telling spring to ignore the servlet there. 但是由于该库也应该在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>

In the implementation project, I want to run only a command line interface, thus I did not include the servlet dependency. 在实施项目中,我只想运行命令行界面,因此不包括servlet依赖项。

But when I try to launch, the following exception is thrown on startup: Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext 但是,当我尝试启动时,在启动时Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext以下异常: Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext以下原因Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext

Question: how can I make use of the ServletContext in the CommonService without having to add the dependency to each project that reuses that class? 问:我如何可以利用的ServletContextCommonService ,而不必依赖添加到重用该类每个项目?

Just include the servlet dependency and make the dependency optional as you've done. 只需包含servlet依赖项,然后将依赖项设置为可选即可。 All the other options are worse. 所有其他选择都更糟。

It's a fairly light weight class - 93K for the jar on servlet spec 3.1.0. 这是一个非常轻量级的类-Servlet规范3.1.0上的jar为93K。

But if you absolutely must run without the class on the classpath then you could do the following... 但是,如果您绝对必须在类​​路径上没有该类的情况下运行,则可以执行以下操作...

Firstly let me say that the reason you're having the issue is not because the ServletContext is a field but because it is an autowired field. 首先,让我说您遇到问题的原因不是因为ServletContext是一个字段,而是因为它是一个自动装配的字段。 I wrote a little test app and the type of the fields of a class are not required to be available at runtime. 我编写了一个小测试应用程序,并且在运行时不需要类的字段类型。

So to get this to work you'll need a profile and a named bean. 因此,要使其正常工作,您将需要一个配置文件和一个命名bean。

Firstly you're going to need to inject the ServletContext by name - and not have it typed as ServletContext. 首先,您需要按名称注入ServletContext-而不是将其键入为ServletContext。 This is not great as you're going to need to cast it to servlet context when you need to use it. 这不是很好,因为您将需要在使用它时将其强制转换为servlet上下文。

So 所以

@Autowired(required = false)
@Qualifier("servletContext")
Object servletContext

is what you'll put here. 这就是你要放在这里的东西。

Then create another class that is going to provide the serlvet context - and this will be turned on via a profile - or possibly what @membersound referred though @ConditionalOnWebApplication is only available in Spring Boot. 然后创建另一个提供Serlvet上下文的类-这将通过配置文件打开-或@membersound引用的@ConditionalOnWebApplication可能仅在Spring Boot中可用。

@Configuration
@Profile("web") or @ConditionalOnWebApplication
public class ServletContextProvider {

  @Autowired
  ServletContext servletContext;

    @Bean("servletContext")
    public ServletContext getServletContext() {
      return servletContext;
    }
}

Like I said, just include ServletContext on your classpath. 就像我说的那样,只需在类路径中包含ServletContext。

Luckily there are the following annotations that could be directly added onto the class: 幸运的是,可以将以下注释直接添加到类中:

@ConditionalOnWebApplication
@ConditionalOnNotWebApplication

This way spring in a cli environment does not need to evaluate the ServletContext bean. 这样,在cli环境中的spring不需要评估ServletContext bean。

Of course this requires the creation of two service classes, where each of them has one of the annotations above. 当然,这需要创建两个服务类,其中每个服务类都具有上面的注释之一。

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";
       }

}

Then inject just @Autowired MyService . 然后只注入@Autowired MyService

By making the implementations package private , they are invisible to the users, but spring still sees and creates them. 通过将实现设为私有 ,用户看不到它们,但是spring仍然可以看到并创建它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM