Способ думать об этом - «думать как компилятор».
Представьте, что вы пишете компилятор. И вы видите такой код.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
Когда вы компилируете файл .cc (помните, что .cc, а не .h - это единица компиляции), вам нужно выделить пространство для объекта A
. Итак, хорошо, сколько пространства тогда? Достаточно хранить B
! Каков размер B
? Достаточно хранить A
!
Очевидно, что круговая ссылка, которую вы должны сломать.
Вы можете ее разбить, разрешив компилятору зарезервировать столько места, сколько он знает о указателях и ссылках на передний план, для например, всегда будет 32 или 64 бита (в зависимости от архитектуры), и поэтому, если вы замените (или один) указателем или ссылкой, все будет замечательно. Скажем, мы заменим в A
:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Теперь все лучше. В некотором роде. main()
все еще говорит:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include
, для всех экстентов и целей (если вы выберете препроцессор) просто копирует файл в .cc. Так что, .cc выглядит так:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
Вы можете понять, почему компилятор не может с этим справиться - он понятия не имеет, что B
- он даже не видел символ раньше .
Итак, давайте расскажем компилятору о B
. Это известно как декларация вперед и обсуждается далее в этом ответе .
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
Это работает . Это не отлично . Но на этом этапе у вас должно быть понимание проблемы с круговой ссылкой и что мы сделали, чтобы «исправить» ее, хотя исправление плохо.
Причина, по которой это исправление плохо, заключается в следующем: f17] должны объявить B
, прежде чем они смогут его использовать, и получите ужасную ошибку #include
. Итак, давайте переместим декларацию в себя.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
И в Bh на данный момент вы можете просто #include "A.h"
прямо.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.
С Джерси 1.x вы должны иметь возможность обслуживать статический контент с одного и того же пути, если вы переключитесь с сервлета Джерси на фильтр. Отбросьте XML-код сервлета, который вы указали, и переключите его на:
<filter>
<filter-name>Jersey Filter</filter-name>
<filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.frog.jump.JerseyApp</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.WebPageContentRegex</param-name>
<param-value>/.*html</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Jersey Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
EDIT: в Jersey 2.x вы должны иметь возможность делать то же самое, но имена свойств были изменены. Попробуйте что-то вроде:
<filter>
<filter-name>Jersey Filter</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>org.example</param-value>
</init-param>
<init-param>
<param-name>jersey.config.servlet.filter.staticContentRegex</param-name>
<param-value>/.*html</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Jersey Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
И ваш POM должен включать:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.0-m07-1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.0-m07-1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
Вам нужно будет настроить регулярное выражение в init-param, если вы хотите использовать css , jsp и т. д.
Еще один хороший вариант - использовать путь с версиями для ваших сервисов («/ v1 / *»), а затем статический контент будет работать без фильтра.
Вы должны добавить фильтр forwardOn404 для решения этой проблемы
<filter>
<filter-name>org.glassfish.jersey.examples.bookstore.webapp.MyApplication</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.glassfish.jersey.examples.bookstore.webapp.MyApplication</param-value>
</init-param>
<!-- pass to next filter if Jersey/App returns 404 -->
<init-param>
<param-name>jersey.config.servlet.filter.forwardOn404</param-name>
<param-value>true</param-value>
</init-param>
</filter>
Как сделано в этом примере https://github.com/jersey/jersey/blob/2.17/examples/bookstore -webapp / src / main / webapp / WEB-INF / web.xml
Примечание: убедитесь, что вы изменили конфигурацию <servlet>
на конфигурацию <filter>
. Джерси ServletContainer
является одновременно HttpServlet
и a Filter
, поэтому вы можете настроить его как в своем web.xml. Чтобы использовать свойство forwardOn404
, Джерси нужно настроить как фильтр.