Метод init()

И еще пара полезных мелочей. Конечно, я про инициализацию сервлета. Как ты уже знаешь, после того, как веб-сервер создал объект сервлета и поместил его в контейнер, он вызывает у сервлета метод init(). Ты можешь переопределить этот метод и инициализировать в нем все, что тебе нужно.

А почему бы не использовать конструктор?

Потому что процесс создания сервлета происходит примерно так:

  • Создаем объект, унаследованный от HttpServlet
  • Создаем объект ServletContext, добавляем его переменную сервлета
  • Создаем объект ServletConfig, добавляем его переменную сервлета
  • Веб-сервер присоединяет сервлет к контейнеру
  • Вызываем метод init()

В конструкторе твоего сервлета еще очень много его внутренних переменных не инициализировано. Контейнер ничего не знает о твоем сервлете, твой сервлет ничего не знает о его контексте. Думаю, тут и так все понятно.

Давай напишем сервлет, который при инициализации находит properties-файл с настройками:


public class PropertiesServlet extends HttpServlet {
    public init() {
         try (InputStream input = new FileInputStream("c:/path/to/config.properties")) {
 
             Properties prop = new Properties();
             prop.load(input);
 
             String databaseURL = prop.getProperty("db.url");
             String databaseUser = prop.getProperty("db.user ");
             String databasePassword = prop.getProperty("db.password");
	 }
  }
}

Тут мы создаем объект Properties и загружаем в него данные из файла config.properties. Ну и в дальнейшем можно доставать из объекта Properties различные параметры, такие как данные для доступа к базе данных, например.

Как правильно загрузить properties-файл

Кстати, а что делать, если твой сервлет выполняется не на твоем компьютере?

Скажем, написали его тут, а он выполняется на сервере где-то в другой части света. Или на нескольких серверах. Как правильно загрузить properties-файл в этом случае?

Хороший вопрос. Обычно в процессе работы сервлет знает только относительный путь своих properties-файлов, но не знает их абсолютного пути, так как war-файлы с сервлетами могут храниться где угодно.

Значит, нам нужно узнать путь, где храниться наш сервлет (сервлет-то уже проинициализирован) и добавить к нему относительный путь :)

Выглядит это примерно так:


String path = absoluteServletParh + "относительный путь";

И, как всегда, у такой элементарной задачи часто есть свое маленькое “но”. Твой сервлет и его properties-файл хранятся внутри архива :) Не обязательно, конечно, но и такое бывает. properties-файл частенько хранится внутри jar- или war-файлов.

То есть физического пути на диске у твоего файла может не быть. Но так как контейнер сумел загрузить твой сервлет, он скорее всего сможет загрузить и твой properties-файл.

Для этого тебе нужно получить объект загрузчика класса (ClassLoader) и попросить его загрузить твой файл. Вот как это будет выглядеть:


ClassLoader loader = Thread.currentThread().getContextClassLoader();       	
InputStream stream = loader.getResourceAsStream("/config.properties");
 
Properties prop = new Properties();
prop.load(stream);

Метод getConfig()

Кстати, не все параметры можно передавать в сервлет в properties-файлах. Например, твой сервлет взаимодействует с другими сервлетами в распределенном веб-приложении.

Тогда нужно сделать так, чтобы контейнер передал твоему сервлету всю необходимую информацию, когда он будет вызвать его метод init(). Более того, он так и делает.

У твоего сервлета (ты ведь помнишь, что он унаследован от класса HttpServlet) есть метод getServletConfig(). Который возвращает объект ServletConfig, созданный и инициализированный контейнером. У этого объекта есть такие методы:

getInitParameterNames() Возвращает список имен параметров сервлета
getInitParameter(String name) Возвращает параметр сервлета по его имени
getServletName() Возвращает собственное имя сервлета
getServletContext() Возвращает объект ServletContext

Давай напишем сервлет, который возвращает список своих параметров из ServletConfig’а. Класть их туда будет через файл web.xml:

	<web-app> 
 	
        <servlet> 
            <servlet-name>Print-Servlet</servlet-name> 
            <servlet-class>PrintServlet</servlet-class> 
            <init-param> 
                <param-name>jdbc-driver</param-name> 
    	        <param-value>sun.jdbc.odbc.JdbcOdbcDriver</param-value> 
	        </init-param> 
        </servlet> 
  	
        <servlet-mapping> 
            <servlet-name>Print-Servlet</servlet-name> 
            <url-pattern>/print</url-pattern> 
        </servlet-mapping> 
  	
    </web-app>

Получить свои параметры сервлет может с помощью кода:


public class PrintServlet extends HttpServlet {
    public void init() {
        ServletConfig config = this.getServletConfig(); 
        Enumeration<String> initParameterNames = config.getInitParameterNames();
 
        while (initParameterNames.hasMoreElements()){
       	     String key = initParameterNames.nextElement();
             System.out.println("%s: %s\n", key, config.getInitParameter(key));
    	}
  }
}