[room] Лекция по Java
Eugene Prokopiev
prokopiev на stc.donpac.ru
Ср Окт 25 14:43:40 MSD 2006
> Что следует изучать первое, для возможности запуска приложений с
> минимальными требованиями к конфигурации сервера (то есть либо CGI, либо,
> если это требует какого-либо модуля апача -- то это то что есть в Сизифе)?
Первое: пусть польют меня грязью, но я в данном вопросе сторонник
недистрибутивного подхода, из Сизифа меня интересует только JDK/JRE.
Обоснование: продукт должен работать не только в ALT, и не только в
Linux (даже в качестве IDE я использую Eclipse в Linux, но со мной
работает один человек в Windows и один еще не определился :) ). Более
того, мне хочется, чтобы он собирался везде, где нет ничего, кроме JDK.
Поэтому мне пока проще таскать все необходимые библиотеки с собой, они у
меня лежат прямо в CVS вместе с исходниками. Я задницей чувствую, что
когда-нибудь это начнет меня напрягать, когда потребуется гарантировать
одинаковые версии библиотек в разных проектах, и тогда я буду смотреть
на maven, а пока мне достаточно ant. Грубые аналогии: ant - это make,
maven - это hasher/spt :)
Далее: CGI в виде отдельных процессов на каждый запрос в Java никто в
здравом уме делать не станет - это слишком дорого. Основа всех
технологий - это сервлеты, которые выглядят так:
public class Hello extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<head>");
writer.println("<title>Sample Application Servlet Page</title>");
writer.println("</head>");
writer.println("<body bgcolor=white>");
writer.println("</body>");
writer.println("</html>");
}
}
Принцип ясен?
Есть надстройки над этим - template engines типа JSP и Velocity, которые
позволяют писать в стиле PHP, т.е. html + вставки кода. Кстати, Velocity
как template engine используется в проектах, которые к web никаким боком.
Есть надстройки над этими надстройками :) Есть другие надстройки над
сервлетами. Начать читать можно отсюда -
http://www.techinfo.net.ru/docs/web/javawebdev.html
Об инфраструктуре: минимальное web-приложение выглядит так:
$ ls -lR
.:
итого 24
-rwxr-xr-x 1 john john 296 Фев 19 2006 build.sh
-rw-r--r-- 1 john john 2124 Окт 25 13:23 build.xml
drwxr-xr-x 2 john john 4096 Окт 25 13:24 docs
drwxr-xr-x 2 john john 4096 Окт 25 13:21 lib-build
drwxr-xr-x 3 john john 4096 Янв 25 2005 src
drwxr-xr-x 4 john john 4096 Янв 25 2005 web
./docs:
итого 4
-rw-r--r-- 1 john john 62 Авг 28 2004 README.txt
./lib-build:
итого 1556
-rw-r--r-- 1 john john 999966 Фев 19 2006 ant.jar
-rw-r--r-- 1 john john 407573 Фев 19 2006 ant-nodeps.jar
-rw-rw-rw- 1 john john 31642 Авг 13 2005 commons-logging.jar
-rw-r--r-- 1 john john 132263 Фев 19 2006 javax.servlet.jar
./src:
итого 4
drwxr-xr-x 2 john john 4096 Авг 28 2004 mypackage
./src/mypackage:
итого 4
-rw-r--r-- 1 john john 3165 Авг 28 2004 Hello.java
./web:
итого 16
-rw-r--r-- 1 john john 1019 Авг 28 2004 hello.jsp
drwxr-xr-x 2 john john 4096 Авг 28 2004 images
-rw-r--r-- 1 john john 636 Авг 28 2004 index.html
drwxr-xr-x 3 john john 4096 Окт 25 13:24 WEB-INF
./web/images:
итого 4
-rw-r--r-- 1 john john 1441 Авг 28 2004 tomcat.gif
./web/WEB-INF:
итого 8
drwxr-xr-x 2 john john 4096 Янв 25 2005 lib
-rw-r--r-- 1 john john 684 Фев 6 2005 web.xml
./web/WEB-INF/lib:
итого 0
web/WEB-INF/web.xml - это дескриптор вида:
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Hello, World Application</display-name>
<description>
This is a simple web application with a source code organization
based on the recommendations of the Application Developer's Guide.
</description>
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>mypackage.Hello</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
Класс Hello мы уже рассматривали :)
build.xml (и вызывающий его build.sh) умеет строить из этого дерева
файлов war-архив. Этот архив можно разными способами продеплоить в
Tomcat: например, скопировать его в определенный каталог, который он
мониторит на предмет появления новых приложений. Будет это приложение
работать и в других контейнерах вроде Jetty и Resin, а также в тяжелых
серверах приложений вроде JBoss и Geronimo, которые содержат встроенные
сервлет-контейнеры (коими являются Tomcat и Jetty :) ).
Мне больше нравится Jetty, т.к. он легче, меньше, проще, понятнее ...
Взять маленький Jetty можно тут -
http://lib.juga.ru/article/articleview/222/1/0?PrintableVersion=enabled
Т.е. Apache web server здесь отдыхает. Его подставляют как frontend.
Можно ли задействовать nginx - не в курсе.
Архив приложения ушел в личку ...
Но это все классика.
Если хочется странного (FastCGI), то пишется обычное java-приложение,
которое обменивается с web-сервером через сокеты.
Такое приложение можно писать, забыв о наличии каких-либо frameworks. Но
если я знаю, что будет много относительно независимых и взамозаменямых
модулей (и я узнаю о том, какие конфигурации будут нужны, только на
этапе внедрения), то я задействую Spring.
Стартовый класс:
public class Main {
public static void main(String[] args) throws InterruptedException {
if (args.length > 0) {
final AbstractApplicationContext ctx =
new FileSystemXmlApplicationContext(new String []{args[0]});
ctx.registerShutdownHook();
A a = (A)ctx.getBean("a");
a.doSomething();
Thread.sleep(Long.MAX_VALUE);
} else {
System.err.println("Usage : java mypackage.Main <context.xml>");
System.exit(-1);
}
}
}
В нем я загружаю все мои модули из внешнего конфигурационного файла
(контекста в терминах Spring), а затем получаю ссылку на модуль а и
вызываю один из его методов. Вывод на консоль после запуска java
mypackage.Main conf/beans.xml:
INFO CollectionFactory - JDK 1.4+ collections available
INFO XmlBeanDefinitionReader - Loading XML bean definitions
from file [/home/john/workspace/SpringApp/conf/beans.xml]
INFO FileSystemXmlApplicationContext - Bean factory for application
context
[org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=11850709]:
org.springframework.beans.factory.support.DefaultListableBeanFactory
defining beans [a,b]; root of BeanFactory hierarchy
INFO FileSystemXmlApplicationContext - 2 beans defined in application
context
[org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=11850709]
INFO FileSystemXmlApplicationContext - Unable to locate MessageSource
with name 'messageSource': using default
[org.springframework.context.support.DelegatingMessageSource на 173831b]
INFO FileSystemXmlApplicationContext - Unable to locate
ApplicationEventMulticaster with name 'applicationEventMulticaster':
using default
[org.springframework.context.event.SimpleApplicationEventMulticaster на 13caecd]
INFO DefaultListableBeanFactory - Pre-instantiating singletons in
factory
[org.springframework.beans.factory.support.DefaultListableBeanFactory
defining beans [a,b]; root of BeanFactory hierarchy]
INFO B - init
INFO A - init
INFO B - do something
Затем жду, пока пользователь не нажмет Ctrl+C :) Вывод:
INFO FileSystemXmlApplicationContext - Closing application context
[org.springframework.context.support.FileSystemXmlApplicationContext;hashCode=11850709]
INFO DefaultListableBeanFactory - Destroying singletons in
factory
{org.springframework.beans.factory.support.DefaultListableBeanFactory
defining beans [a,b]; root of BeanFactory hierarchy}
INFO A - destroy
INFO B - destroy
Конфигурационный файл со связями между модулями a и b выглядит так:
<beans>
<bean id="a" class="mypackage.A" init-method="init"
destroy-method="destroy">
<property name="c" ref="b"/>
</bean>
<bean id="b" class="mypackage.B" init-method="init"
destroy-method="destroy"/>
</beans>
Вот как выглядит класс B:
public class B implements C {
private Log log = LogFactory.getLog(getClass());
public void init() {
log.info("init");
}
public void destroy() {
log.info("destroy");
}
public void doSomething() {
log.info("do something");
}
}
Он реализует интерфейс С:
public interface C {
public void doSomething();
}
Который, в свою очередь, используется классом А:
public class A {
private Log log = LogFactory.getLog(getClass());
private C c;
public void setC(C c) {
this.c = c;
}
public void init() {
log.info("init");
}
public void destroy() {
log.info("destroy");
}
public void doSomething() {
c.doSomething();
}
}
Удобство Spring в том, что он:
1) позволяет декларативно описать, кто кого и как должен вызвать, что с
какими параметрами должно быть инициализировано - но тут реализация
HiveMind может быть даже более изящна
2) подключить готовые модули, например, для доступа к БД и т.д - вот тут
равных Spring'у нет
Рассмотрим последнее на примере задействования технологии JMX. Пусть в
процессе работы приложения обслуживающий персонал должен вызывать
зачем-то метод A.doSomething(). Мы описываем класс A как implements
AMBean, последний выглядит так:
public interface AMBean {
public void doSomething();
}
Теперь исправляем beans.xml:
<beans>
<bean id="mbeanServer"
class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
<bean id="exporter"
class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=A" value-ref="a"/>
</map>
</property>
<property name="assembler">
<bean
class="org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler"/>
</property>
<property name="server" ref="mbeanServer"/>
</bean>
<bean id="myBean" class="MyBean"/>
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean">
<property name="objectName" value="connector:name=rmiConnector"/>
<property name="serviceUrl"
value="service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"/>
<property name="threaded" value="true"/>
<property name="daemon" value="true"/>
<property name="server">
<ref local="mbeanServer"/>
</property>
</bean>
<bean id="registry"
class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="1099"/>
</bean>
<bean id="a" class="mypackage.A" init-method="init"
destroy-method="destroy">
<property name="c" ref="b"/>
</bean>
<bean id="b" class="mypackage.B" init-method="init"
destroy-method="destroy"/>
</beans>
После запуска приложения запускаем jconsole, подключаемся к
service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi без логина/пароля,
находим в дереве наш класс и вызываем doSomething
Архив с проектом ушел в личку ...
Кто скажет, что это не изящно, пусть бросит в меня камень :)
Да, похоже я исполнил мечту г-на dlaygovta@ :)
Денис, если все это тебе еще интересно, то в качестве оплаты лекции
прошу написанное причесать и куда нибудь на f.i. выложить :)
>>EP>> А если хочется "FastCGI, темплейтов и прочей радости, а также компилятор
>>EP>> в неё с простого PHP-like язычка" - то бишь именно своего велосипеда -
>>EP>> то вообще непонятно, что в PHP есть такого, что ты предпочел именно его
>>EP>> ... К слову, компиляторов в байт-код JVM с различных функциональных и
>>EP>> императивных языков довольно много
>
>
>>>Скорее уж проще самому налабать интерпретатор на той же жабе.
>
> EP> Свой DSL? Возможно, есть смысл посмотреть в сторону antlr ...
>
> Посмотрю.
>
> Кстати о. Какие наиболее простые средства a-la flex/bison сейчас есть в
> Java?
кажется, именно antlr и есть
>>>PHP было выбрано как меньшее из зол. То бишь либо самому делать весь стек,
>>>либо не строить из себя идеалиста а просто сделать чтобы хорошо работало.
>>>Но я все равно ищу что-то куда свалить.
>
> EP> :)
> EP> Прелесть Java не в языке. Язык средний, в частностях вроде интерфейсов и
> EP> анонимных классов лучше предшественника (C++), а в некоторых более
> EP> глобальных вопросах (класс String ;) ) просто потрясающий своей
> EP> нелогичностью. Хотя привыкнуть можно :)
>
> Меня String убивает именно тем, что код который на perl том же занимает
> несколько символов и понятен -- на Java получается простыня кода :)
В Java есть регулярные выражения - не помогут?
> EP> Прелесть именно в окружении. В наличии спецификаций, в конкурирующих и
> EP> относительно совместимых реализаций этих спецификаций. В количестве
> EP> библиотек (один jakarta.apache.org чего стоит). В средствах сборки типа
> EP> ant/maven. В неплохих IDE вроде Eclipse и IDEA, хотя, конечно, для
> EP> любителей vim/emacs это не аргумент :)
>
> Другая проблема -- в отличии от perl, где фактически все в одной коробке,
> Java имеет больший порог вхождения чтобы знать какой из модулей наиболее
> применим для данной задачи. Именно из-за конкуренции.
Есть такая беда :)
Многие "левые" решения имеют тенденцию к помещению к коробку, правда,
иногда в изуродованном виде, так что удобнее оказывается использовать
то, что осталось вне коробки :) Яркий пример - механизмы
протоколирования вроде встроенного, log4j и унифицированного commons logging
>>>Ну, в жабе в этом смысле все можно сделать красиво, если я правильно
>>>понял. Спрятать вообще доступ к SQL в объеты, реализовать для них
>>>интерфейсе serializable после чего сделать кэш. Вот во всяких PHP-подобных
>>>это уже оказывается куда тяжелее.
>
> EP> А в Java даже есть готовое вроде JBoss Tree Cache :)
>
> :)
У меня как-то был соблазн к нему подступиться, но потом понял, что узкое
место было не здесь ...
--
С уважением, Прокопьев Евгений
Подробная информация о списке рассылки smoke-room