Wolę trzecie podejście, które czerpie to, co najlepsze z
Podejścia 1 i Podejścia 2 opisanego przez użytkownika1016403 .
Podejście 3
- Zapisz właściwości bazy danych w
server.xml
- odwołać się do
server.xml
właściwości bazy danych z aplikacji internetowejMETA-INF/context.xml
Podejście 3 korzyści
Podczas gdy pierwszy punkt jest przydatny ze względów bezpieczeństwa, drugi punkt jest przydatny do odwoływania się do wartości właściwości serwera z aplikacji internetowej, nawet jeśli wartości właściwości serwera ulegną zmianie.
Ponadto oddzielenie definicji zasobów na serwerze od ich wykorzystania przez aplikację internetową sprawia, że taka konfiguracja jest skalowalna w różnych organizacjach o różnym stopniu złożoności, w których różne zespoły pracują na różnych poziomach / warstwach: zespół administratorów serwera może pracować bez konfliktu z zespołem programistów, jeśli administrator udostępnia to samo Nazwa JNDI z deweloperem dla każdego zasobu.
Podejście 3 wdrożenie
Zdefiniuj nazwę JNDI jdbc/ApplicationContext_DatabaseName
.
Zadeklaruj jdbc/ApplicationContext_DatabaseName
różne właściwości i wartości w Tomcat, server.xml
używając czegoś takiego:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContext_DatabaseName" auth="Container" type="javax.sql.DataSource"
username="dbUsername" password="dbPasswd"
url="jdbc:postgresql://localhost/dbname"
driverClassName="org.postgresql.Driver"
initialSize="5" maxWait="5000"
maxActive="120" maxIdle="5"
validationQuery="select 1"
poolPreparedStatements="true"/>
</GlobalNamingResources/>
Połącz jdbc/ApplicationContext_DatabaseName
właściwości z aplikacji internetowej META-INF/context.xml
za pomocą prywatnego kontekstu JNDI aplikacji java:comp/env/
określonego w name
atrybucie:
<Context path="/ApplicationContext" ... >
<!--
"global" attribute links to GlobalNamingResources in the ${catalina.base}/conf/server.xml (server administrator team)
"name" attribute is relative to the application-private JNDI context java:comp/env/ and is looked up from the java web application (application developer team)
-->
<ResourceLink global="jdbc/ApplicationContext_DatabaseName" name="jdbc/DatabaseName" type="javax.sql.DataSource"/>
</Context>
Na koniec, aby użyć zasobu JNDI, określ nazwę JNDI jdbc/DatabaseName
w deskryptorze wdrażania aplikacji WWW:
<resource-ref>
<description>DatabaseName's Datasource</description>
<res-ref-name>jdbc/DatabaseName</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
aw kontekście wiosny:
<jee:jndi-lookup id="DatabaseNameDataSource"
jndi-name="jdbc/DatabaseName"
expected-type="javax.sql.DataSource" />
Podejmij 3 wady
Jeśli nazwa JNDI zostanie zmieniona wtedy zarówno server.xml
i META-INF/context.xml
będą musiały być edytowane i wdrożyć byłoby konieczne; niemniej jednak ten scenariusz jest rzadki.
Podejdź do 3 odmian
Wiele źródeł danych używanych przez jedną aplikację internetową
Po prostu dodaj konfiguracje do Tomcat server.xml
:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContext_DatabaseName1" ... />
<Resource name="jdbc/ApplicationContext_DatabaseName2" ... />
...
</GlobalNamingResources/>
Dodaj aplikację internetową odsyłacza META-INF/context.xml
za pomocą prywatnego kontekstu JNDI aplikacji java:comp/env/
określonego w name
atrybucie:
<Context path="/ApplicationContext" ... >
<ResourceLink global="jdbc/ApplicationContext_DatabaseName1" name="jdbc/DatabaseName1" ... />
<ResourceLink global="jdbc/ApplicationContext_DatabaseName2" name="jdbc/DatabaseName2" ... />
...
</Context>
Na koniec dodaj użycie zasobów JNDI w deskryptorze wdrażania aplikacji internetowej:
<resource-ref>
<description>DatabaseName1's Datasource</description>
<res-ref-name>jdbc/DatabaseName1</res-ref-name> ...
</resource-ref>
<resource-ref>
<description>DatabaseName2's Datasource</description>
<res-ref-name>jdbc/DatabaseName2</res-ref-name> ...
</resource-ref>
...
aw kontekście wiosny:
<jee:jndi-lookup id="DatabaseName1DataSource"
jndi-name="jdbc/DatabaseName1" ... />
<jee:jndi-lookup id="DatabaseName2DataSource"
jndi-name="jdbc/DatabaseName2" ... />
...
Wiele źródeł danych używanych przez wiele aplikacji internetowych na tym samym serwerze
Po prostu dodaj konfigurację do Tomcat server.xml
:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContextX_DatabaseName1" ... />
<Resource name="jdbc/ApplicationContextX_DatabaseName2" ... />
<Resource name="jdbc/ApplicationContextY_DatabaseName1" ... />
<Resource name="jdbc/ApplicationContextY_DatabaseName2" ... />
...
</GlobalNamingResources/>
inne konfiguracje powinny dać się wyprowadzić z poprzedniego przypadku zmienności.
Wiele źródeł danych do tej samej bazy danych używanej przez wiele aplikacji internetowych na tym samym serwerze
W takim przypadku server.xml
konfiguracje Tomcata, takie jak:
<GlobalNamingResources>
<Resource name="jdbc/ApplicationContextX_DatabaseName" ... />
<Resource name="jdbc/ApplicationContextY_DatabaseName" ... />
kończy się w dwóch różnych aplikacjach internetowych, META-INF/context.xml
takich jak:
<Context path="/ApplicationContextX" ... >
<ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>
i jak:
<Context path="/ApplicationContextY" ... >
<ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>
więc ktoś może się martwić faktem, że to samo name="jdbc/DatabaseName"
jest wyszukiwane, a następnie używane przez dwie różne aplikacje wdrożone na tym samym serwerze: nie stanowi to problemu, ponieważ jdbc/DatabaseName
jest to kontekst JNDI prywatnej aplikacji java:comp/env/
, więc ApplicationContextX
używającjava:comp/env/
nie można (zgodnie z projektem) wyszukuje zasoby, z którymi jest powiązany global="jdbc/ApplicationContextY_DatabaseName"
.
Oczywiście, jeśli czułeś się bardziej zrelaksowany bez tego zmartwienia, możesz użyć innej strategii nazewnictwa, na przykład:
<Context path="/ApplicationContextX" ... >
<ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/applicationXprivateDatabaseName" ... />
</Context>
i jak:
<Context path="/ApplicationContextY" ... >
<ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/applicationYprivateDatabaseName" ... />
</Context>
<Resource name="jdbc/ApplicationContextX_DatabaseName" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName" ... />
Gdyby zasoby były pulami połączeń, czy dałoby to dwie oddzielne pule, po jednej na aplikację internetową? Zważywszy, że jeśli połączyłem się z obu aplikacji internetowych do jednego zasobu, byłaby tylko jedna pula połączeń, prawda? Jakieś powody, by preferować jeden od drugiego? (oddzielne pule połączeń DB, po jednej na aplikację internetową w porównaniu z jedną pulą połączeń współdzieloną przez wszystkie aplikacje internetowe)? Dzięki.YOUR_APP.xml
plikPreferuję podejście 2 (umieść wszystko (nie tylko jakiś atrybut w konfiguracji), ale zamiast umieszczać je w globalnym
server.xml
lub globalnymcontext.xml
, powinieneś umieścić je w pliku specyficznym dla aplikacji w swoim Tomcacie.context.xml.default
YOUR_APP.xml
YOUR_APP.xml
Plik znajduje się$catalinaHome/conf/<engine>/<host>
(na przykładconf/Catalina/localhost/YOUR_APP.xml
).Konfiguracja specyficzna dla aplikacji
YOUR_APP.xml
jest dostępna tylko dla określonej aplikacji.Zobacz przewodnik opublikowany przez MuleSoft. Zobacz też oficjalną dokumentację Tomcat Configuration Reference , strona The Context Container
Cytując tę dokumentację:
źródło
Podejście 4
Zamiast korzystać z JNDI, pracuję z
.properties
plikami i buduję złożone obiekty podczas inicjalizacji programu zamiast w czasie konfiguracji.Używasz już Springa i jest to łatwe do skonstruowania
DataSource
poprzez:<context:property-placeholder location="classpath:app.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@${db.host}:${db.port}:${db.user}"/> <property name="username" value="${db.user}"/> <property name="password" value="${db.pass}"/> </bean>
Całkowicie zgadzam się z Ralphem co do używania deskryptora wdrażania w,
$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml
ale zamiast JNDI lubię zwykły plik klucz-wartość!Dzięki wiosennemu wstrzykiwaniu powyższych właściwości na pola fasoli jest to łatwe:
@Value("${db.user}") String defaultSchema;
zamiast JNDI:
@Inject ApplicationContext context; Enviroment env = context.getEnvironment(); String defaultSchema = env.getProperty("db.user");
Zauważ również, że EL pozwala na to (wartości domyślne i głębokie podstawianie rekurencyjne):
@Value('${db.user:testdb}') private String dbUserName; <property name='username' value='${db.user.${env}}'/>
Do eksternalizacji
.properties
pliku używam nowoczesnego Tomcat 7, który ma org.apache.catalina.loader.VirtualWebappLoader :<Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="/srv/web/app/"/>
Więc twoi devopsy wypełniają
virtualClasspath
lokalne zewnętrzne pełne ścieżki, które są oddzielne dla aplikacji i umieszczają lokalnieapp.properties
w tym katalogu .Zobacz też:
źródło
Możesz również użyć obsługi adresów URL JNDI do różnych konfiguracji aplikacji na potrzeby testów, testów integracji i produkcji.
<Context> ... <Resource auth="Container" factory="com.benasmussen.jndi.url.URLFactory" name="url/MyUrl" type="java.net.URL" url="file:///your/path/to/file"/> ... </Context> <jee:jndi-lookup id="myUrl" jndi-name="java:comp/env/url/MyUrl" expected-type="java.net.URL" />
Zapoznaj się z projektem GitHub Obsługa adresów URL JNDI Tomcat, aby włączyć obsługę adresów URL JNDI dla serwerów Tomcat.
źródło
krok 1: context.xml
<Context path="/projectname"> <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" logAbandoned="true" maxActive="100" `` maxIdle="30" maxWait="10000" name="refname" removeAbandoned="true" removeAbandonedTimeout="60" type="javax.sql.DataSource" url="jdbc:mysql://localhost:8080/dbname" username="root" password="root"/> </Context>
Krok 2: web.xml
Krok 3: Utwórz klasę, aby uzyskać połączenie
Connection connection = null; Context context = (Context) new InitialContext().lookup("java:comp/env"); DataSource ds = (DataSource) context.lookup("refname"); connection = ds.getConnection();
Wszystko gotowe
źródło