2017-08-18 1 views
1

Ich erstelle eine allgemeine Bibliothek und möchte einen Dienst hinzufügen, der ServletContext verwendet. Aber da die Bibliothek auch in einer cli Umgebung verwendet werden soll, muss ich einen Weg finden, dem Frühling zu sagen, das Servlet dort zu ignorieren.Wie füge ich die optionale Abhängigkeitsklasse im Frühling hinzu?

@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> 

Im Einführungsprojekt möchte ich nur eine Befehlszeilenschnittstelle laufen, so dass ich nicht die Servlet-Abhängigkeit enthalten.

Aber wenn ich zu starten versuchen, die folgende Ausnahme beim Start ausgelöst wird: Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext

Frage: Wie kann ich die Verwendung der ServletContext im CommonService ohne hinzuzufügen, um die Abhängigkeit zu jedem Projekt zu machen, die das wieder verwendet Klasse?

+0

Dies scheint korrekt zu sein: Wenn Ihre Klasse die 'ServletContext' Klasse importiert, muss sie im Klassenpfad sein, andernfalls wird eine Ausnahme ausgelöst. [Maven Dokumentation] (http://maven.apache.org/guides/introduction/introduction-toptional-and-excludes-dependencies.html) sagt: * Die Idee ist, dass einige der Abhängigkeiten nur für bestimmte Funktionen verwendet werden im Projekt, und wird nicht benötigt, wenn diese Funktion nicht verwendet wird *. Das Feature 'MyService' wird verwendet, da Spring es beim Start lädt, also ist es nicht das von Maven-Entwicklern beschriebene Szenario, und ich schätze, Sie können das nicht tun. – BackSlash

+0

Also wie könnte ich es umgehen? – membersound

+0

Sie sollten es in eine Klasse stellen, die nicht vom Frühling geladen wird. Aber so würde die '@ Autowired' Annotation nicht funktionieren. Deshalb sagte ich, ich schätze, du kannst das nicht tun. Sie benötigen Felder, um Felder für Sie automatisch zu aktivieren, aber ohne die Annotation "@ Component" funktioniert es nicht und mit der Annotation "@ Component" erhalten Sie die "ClassNotFoundException". Sie könnten die '@ Component' entfernen und [diese Lösung] (https://Stackoverflow.com/a/24373710/1759845) verwenden, um die Abhängigkeit zu autowire, wenn die Klasse instanziiert wird, aber es ist eine Art schmutziger Hack. Außerdem können Sie MyService nicht mehr automatisch starten. – BackSlash

Antwort

0

Zum Glück gibt es die folgenden Anmerkungen, die direkt auf die Klasse hinzugefügt werden könnten:

@ConditionalOnWebApplication 
@ConditionalOnNotWebApplication 

Auf diese Weise Feder in einer cli Umgebung braucht nicht die ServletContext Bohne zu bewerten.

Natürlich erfordert dies die Erstellung von zwei Serviceklassen, wobei jede von ihnen eine der obigen Anmerkungen hat.

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

} 

Dann injizieren Sie einfach @Autowired MyService.

Durch die Implementierungen Paket privat sind sie für die Benutzer unsichtbar, aber der Frühling sieht und erstellt sie noch.

2

Fügen Sie einfach die Servlet-Abhängigkeit ein und machen Sie die Abhängigkeit optional, wie Sie es getan haben. Alle anderen Optionen sind schlechter.

Es ist eine ziemlich leichte Klasse - 93K für das Glas auf Servlet Spec 3.1.0.

Aber wenn Sie absolut ohne die Klasse auf dem Classpath laufen müssen, dann können Sie die folgenden Schritte aus ...

mich Zum einen lassen sagen, dass der Grund, warum Sie das Problem mit bist ist nicht, weil die ServletContext ein Feld aber weil es ein automatisches Feld ist. Ich habe eine kleine Test-App geschrieben und die Art der Felder einer Klasse muss zur Laufzeit nicht verfügbar sein.

Damit dies funktioniert, benötigen Sie ein Profil und eine benannte Bean.

Zuerst müssen Sie den ServletContext nach Namen injizieren - und nicht als ServletContext eingegeben haben. Dies ist nicht gut, da Sie es in den Servlet-Kontext umwandeln müssen, wenn Sie es verwenden müssen.

So

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

ist, was Sie hier gestellt werden.

Dann erstellen Sie eine andere Klasse, die den Serlvet-Kontext bereitstellen wird - und dies wird über ein Profil aktiviert - oder möglicherweise, was @membersound referierte, obwohl @ConditionalOnWebApplication nur im Spring Boot verfügbar ist.

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

    @Autowired 
    ServletContext servletContext; 

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

Wie gesagt, ServletContext in Ihren Klassenpfad einfügen.

Verwandte Themen