Domů > Nezařazené > Tomcat - Sdílený back-end

Tomcat - Sdílený back-end

Téměř všechny příklady a tutoriály, jak konfigurovat Tomcat popisují jen ty nejjednodušší případy a aplikace. My jsme potřebovali Tomcat nakonfigurovat tak, aby několik web aplikací mohlo sdílet jediný modul obsahující servisní a DAO vrstvy. V tomto článku vám ukážu, jak na to.

Struktura naší aplikace

Deployment diagram

Deployment diagram

Front-end je tvořen několika webovými aplikacemi. V našem případě jsme měli pro každý výstupní formát speciální web aplikaci (WML, HTML). Tyto aplikace sdílí společný back-end, který obsahuje Spring application context a v něm nakonfigurovanou servisní a DAO vrstvu. Service locator pouze zabaluje Spring application context a webové aplikace si jej mohou najít v JNDI.

Proč je výhodou mít jediný společný back-end? V našem případě back-end obsahuje většinu business logiky, která je všem web aplikacím společná. Jedná se například o persistenci, cache, scheduler, logování statistik, atd. Další výhodou je, že můžete modifikovat web aplikaci bez nutnosti restartování back-endu, což se při vývoji hodí, protože back-end může startovat dost dlouho (v jednom z našich projektů back-end startoval půl minuty).

Testovací aplikace

Připravil jsem archív obsahující testovací aplikaci, skládající se z front-endu, back-endu a konfigurace tomcatu. Stáhněte si tomcat-example.zip a rozbalte někam na disk. Abyste mohli tuto aplikaci zkompilovat a spustit, musíte mít následující:

Po rozbalení archívu tomcat-example.zip byste měli mít na disku tuto strukturu:

───tomcat-example
   │   build.xml
   │
   ├───core
   │   │   .classpath
   │   │   .project
   │   │
   │   └───src
   │       └───itplace
   │           └───example
   │               └───core
   │                       HelloService.java
   │                       HelloServiceImpl.java
   │                       ServiceLocator.java
   │                       ServiceLocatorFactory.java
   │                       ServiceLocatorImpl.java
   │
   ├───tomcat
   │   │   run.cmd
   │   │
   │   └───conf
   │           catalina.policy
   │           catalina.properties
   │           context.xml
   │           logging.properties
   │           server.xml
   │           tomcat-users.xml
   │           web.xml
   │
   └───webapp1
       │   .classpath
       │   .project
       │
       ├───src
       │   └───itplace
       │       └───example
       │           └───webapp1
       │                   HelloServlet.java
       │
       └───webapp
           └───WEB-INF
               │   web.xml
               │
               └───classes
  • tomcat-example/core obsahuje třídy back-endu
  • tomcat-example/webapp1 je projekt obsahující web aplikaci.
  • tomcat-exmple/tomcat obsahuje konfiguraci Tomcatu a dávku run.cmd, která nastartuje nakonfigurovaný tomcat.

Spuštěním příkazu ant v adresáři tomcat-example dojde ke zkompilování obou projektů core a webapp1. Výsledek kompilace se uloží do tomcat-example/core/bin resp. tomcat-example/webap­p1/webapp/WEB-INF/classes.

Projekty core a webapp1 si můžete naimportovat do Eclipse, budete ale potřebovat říct Eclipse, kde má hledat knihovny serveru Tomcat.

Konfigurace Tomcatu

Nejprve prozkoumáme adresář tomcat-example/tomcat. Tento adresář neobsahuje instalaci Tomcatu ale pouze jeho konfiguraci. Pro spuštění naší aplikace je potřeba:

Nakonfigurovat classpath společnou všem aplikacím (common loader)

Podívejte se do souboru tomcat-example/tomcat/con­f/catalina.pro­perties. Na konci řádku 47 najdete toto:

common.loader= ...... ${catalina.base}/../core/bin

Proměnná ${catalina.base} je nastavená do adresáře tomcat-example/tomcat. Tomcat tedy do classpath společné všem web aplikacím i serveru samotného přidá třídy našeho back-endu.

Nakonfigurovat ServiceLocator

Třídu ServiceLocatorImpl mužete najít v projektu tomcat-example/core:

package itplace.example.core;

public class ServiceLocatorImpl implements ServiceLocator {
    public HelloService getHelloService() {
        return new HelloServiceImpl();
    }
}

Vidíte, že tato implementace pouze vytváří novou instanci service HelloServiceImpl. Na tomto místě v reálném projektu může být použit například Spring a jeho BeanFactory.

Jak tedy přinutit Tomcat, aby při startu vytvořil jedinou instanci třídy ServiceLocatorImpl? Podívejte se do souboru tomcat-example/tomcat/con­f/server.xml. Na řádku 40 najdete tento kousek xml:

<Resource name="serviceLocator" auth="Container"
      type="itplace.example.core.ServiceLocator"
      description=""
      factory="itplace.example.core.ServiceLocatorFactory"
/>

Pomocí tagu Resource deklarujeme JNDI resource typu itplace.example.core.ServiceLocator a jména serviceLocator. Tomcat pro jeho vytvoření použije továrnu itplace.example.core.ServiceLocatorFactory, která vypadá takto:

package itplace.example.core;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;

public class ServiceLocatorFactory implements ObjectFactory {

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
            Hashtable<?, ?> environment) throws Exception {
        System.out.println("creating new service locator");
        return new ServiceLocatorImpl();
    }
}

Vidíte, že tovární metoda getObjectInstance jednoduše vytváří novou instanci třídy ServiceLocatorImpl.

Zpřístupnit ServiceLocator webovým aplikacím

Tomcat již tedy inicializuje náš service locator při startu. Nyní je potřeba říct, jak k němu webové aplikace mohou přistupovat. Tuto konfiguraci najdete v souboru tomcat-example/tomcat/con­f/context.xml na řádku 36:

<ResourceLink name="serviceLocator" global="serviceLocator"
    type="itplace.example.core.ServiceLocator" />

Tento kousek xml, již jen propojuje globální kontext serveru s kontextem webových aplikací. Nyní mohou web aplikace získat referenci na náš ServiceLocator standardním vyhledáním v JNDI. Podívejte se, jak toto vyhledání funguje v servletu HelloServlet, který najdete v projektu tomcat-example/webapp1:

....
Context initialContext;
try {
    initialContext = new InitialContext();
    ServiceLocator serviceLocator =
        (ServiceLocator) initialContext.lookup("java:comp/env/serviceLocator");
    PrintWriter out = response.getWriter();
    String message =
        serviceLocator.getHelloService().getHelloMessage("ITPlace");
    out.println("HelloServlet: " + message);
} catch (NamingException e) {
    throw new ServletException(e);
}
....

Referenci na náš service locator získáme vyhledáním java:comp/env/serviceLocator v JNDI. Tuto část je pak dobré přesunout do některé statické metody, aby jste nemuseli tento kód opakovat v každém servletu.

Spuštění naší aplikace

To je celá věda, nyní můžete aplikaci spustit:

  • nejprve vše zkompilujte – v adresáři tomcat-example spusťte příkaz ant.
  • v adresáři tomcat-example/tomcat spusťte dávku run.cmd.
  • otevřete svůj internetový prohlížeč a jděte na: http://localhost/…HelloServlet

Pokud vše proběhlo správně, měli byste vidět hlášku: HelloServlet: HelloServiceImpl says: hello ITPlace !!!.

Závěr

Ikdyž je Tomcat pouze servlet container, dají se s ním dělat psí kusy. Je ale na pováženou jestli není lepší pro běh aplikací podobných naší testovací použít některý z aplikačních serverů. Pokud vaše aplikace nepotřebuje vlastnosti a funkcionality aplikačního serveru a vystačí si se Springem (jako to bylo v našem případě), myslím, že je Tomcat díky své jednoduchosti dobrá volba.

Odkazy

Jan Šmuk Nezařazené

  1. Ladislav Thon
    19.08.2009 na 15:13 | #1

    > Je ale na pováženou jestli není lepší pro běh aplikací podobných naší testovací použít některý z aplikačních serverů.

    Nebo všechno nechat v jedné aplikaci a jen v ní mít dva DispatcherServlety (pro Spring Web MVC, nebo třeba WicketFiltery pro Wicket, to je jedno).

    Předpokládám, že jste měli důvod ty webové aplikace oddělovat, ostatně u nás to v jedné aplikaci máme udělané prakticky stejně, ale osobně mám mnohem radši situaci, kdy je úplně všechno v jednom WARu (EARu pro aplikáče? Ale tomu nerozumím.) a není potřeba nic konfigurovat vedle.

  2. Ariel
    26.08.2009 na 17:39 | #2

    Ja jsem o javax.namin­g.ObjectFacto­ry vedela, akorat nevim, proc potrebujete ten ServiceLocator mit v JNDI? Vzdyt to mate na (common) Classpath, takze se to da vyzvednout primo pres navrhovy vzor singleton a nemusi se jit pres JNDI.
    Ale uznavam, ze i takhle je to pekne pruhledne.

  3. 27.08.2009 na 09:34 | #3

    @Ariel
    Máte pravdu, že ve výsledku není velký rozdíl mezi použitím singletonu a JNDI.
    Návrhový vzor Singleton se ale v J2EE aplikacích nedoporučuje, protože použitím singletonu svazujete vaši aplikaci k jediné JVM.
    Použití popsaného způsobu má ale také praktické výhody, jako hlavní vidím fakt, že zodpovědnost za inicializaci service locatoru nemá moje aplikace, ale Tomcat.

  4. 06.10.2013 na 22:43 | #4

    Není prostě v době kdy cena jedné 8GB paměti je směšná prostě použít tomcaty dva?

  5. 07.10.2013 na 16:04 | #5

    Nejde ani tak o paměť, ale o to, jak sdílet business logiku několika frontendy.

  1. Žádné zpětné odkazy
Musíte být přihlášen k poslání komentáře.