可能最好的方法是使用
ApplicationEventListener。从那里,你可以听的“应用程序完成初始化”事件,并获得
ResourceModel从
ApplicationEvent。在
ResourceModel将所有的初始化
Resource秒。然后,您可以遍历
Resource其他人提到的。下面是一个实现。一些实施已取自
DropwizardResourceConfig实施。
import com.fasterxml.classmate.ResolvedType;import com.fasterxml.classmate.TypeResolver;import java.util.Comparator;import java.util.HashSet;import java.util.Set;import java.util.TreeSet;import org.glassfish.jersey.server.model.Resource;import org.glassfish.jersey.server.model.ResourceMethod;import org.glassfish.jersey.server.model.ResourceModel;import org.glassfish.jersey.server.monitoring.ApplicationEvent;import org.glassfish.jersey.server.monitoring.ApplicationEventListener;import org.glassfish.jersey.server.monitoring.RequestEvent;import org.glassfish.jersey.server.monitoring.RequestEventListener;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class EndpointLoggingListener implements ApplicationEventListener { private static final TypeResolver TYPE_RESOLVER = new TypeResolver(); private final String applicationPath; private boolean withOptions = false; private boolean withWadl = false; public EndpointLoggingListener(String applicationPath) { this.applicationPath = applicationPath; } @Override public void onEvent(ApplicationEvent event) { if (event.getType() == ApplicationEvent.Type.INITIALIZATION_APP_FINISHED) { final ResourceModel resourceModel = event.getResourceModel(); final ResourceLogDetails logDetails = new ResourceLogDetails(); resourceModel.getResources().stream().forEach((resource) -> { logDetails.addEndpointLogLines(getLinesFromResource(resource)); }); logDetails.log(); } } @Override public RequestEventListener onRequest(RequestEvent requestEvent) { return null; } public EndpointLoggingListener withOptions() { this.withOptions = true; return this; } public EndpointLoggingListener withWadl() { this.withWadl = true; return this; } private Set<EndpointLogLine> getLinesFromResource(Resource resource) { Set<EndpointLogLine> logLines = new HashSet<>(); populate(this.applicationPath, false, resource, logLines); return logLines; } private void populate(String basePath, Class<?> klass, boolean isLocator, Set<EndpointLogLine> endpointLogLines) { populate(basePath, isLocator, Resource.from(klass), endpointLogLines); } private void populate(String basePath, boolean isLocator, Resource resource, Set<EndpointLogLine> endpointLogLines) { if (!isLocator) { basePath = normalizePath(basePath, resource.getPath()); } for (ResourceMethod method : resource.getResourceMethods()) { if (!withOptions && method.getHttpMethod().equalsIgnoreCase("OPTIONS")) { continue; } if (!withWadl && basePath.contains(".wadl")) { continue; } endpointLogLines.add(new EndpointLogLine(method.getHttpMethod(), basePath, null)); } for (Resource childResource : resource.getChildResources()) { for (ResourceMethod method : childResource.getAllMethods()) { if (method.getType() == ResourceMethod.JaxrsType.RESOURCE_METHOD) { final String path = normalizePath(basePath, childResource.getPath()); if (!withOptions && method.getHttpMethod().equalsIgnoreCase("OPTIONS")) { continue; } if (!withWadl && path.contains(".wadl")) { continue; } endpointLogLines.add(new EndpointLogLine(method.getHttpMethod(), path, null)); } else if (method.getType() == ResourceMethod.JaxrsType.SUB_RESOURCE_LOCATOR) { final String path = normalizePath(basePath, childResource.getPath()); final ResolvedType responseType = TYPE_RESOLVER .resolve(method.getInvocable().getResponseType()); final Class<?> erasedType = !responseType.getTypeBindings().isEmpty() ? responseType.getTypeBindings().getBoundType(0).getErasedType() : responseType.getErasedType(); populate(path, erasedType, true, endpointLogLines); } } } } private static String normalizePath(String basePath, String path) { if (path == null) { return basePath; } if (basePath.endsWith("/")) { return path.startsWith("/") ? basePath + path.substring(1) : basePath + path; } return path.startsWith("/") ? basePath + path : basePath + "/" + path; } private static class ResourceLogDetails { private static final Logger logger = LoggerFactory.getLogger(ResourceLogDetails.class); private static final Comparator<EndpointLogLine> COMPARATOR = Comparator.comparing((EndpointLogLine e) -> e.path) .thenComparing((EndpointLogLine e) -> e.httpMethod); private final Set<EndpointLogLine> logLines = new TreeSet<>(COMPARATOR); private void log() { StringBuilder sb = new StringBuilder("nAll endpoints for Jersey applicationn"); logLines.stream().forEach((line) -> { sb.append(line).append("n"); }); logger.info(sb.toString()); } private void addEndpointLogLines(Set<EndpointLogLine> logLines) { this.logLines.addAll(logLines); } } private static class EndpointLogLine { private static final String DEFAULT_FORMAT = " %-7s %s"; final String httpMethod; final String path; final String format; private EndpointLogLine(String httpMethod, String path, String format) { this.httpMethod = httpMethod; this.path = path; this.format = format == null ? DEFAULT_FORMAT : format; } @Override public String toString() { return String.format(format, httpMethod, path); } }}然后,您只需要在Jersey上注册监听器即可。您可以从获取应用程序路径
JerseyProperties。您需要在Spring
Boot中
application.properties的属性下进行设置
spring.jersey.applicationPath。这将是根路径,就像您要
@ApplicationPath在
ResourceConfig子类上使用一样
@Beanpublic ResourceConfig getResourceConfig(JerseyProperties jerseyProperties) { return new JerseyConfig(jerseyProperties);}...public class JerseyConfig extends ResourceConfig { public JerseyConfig(JerseyProperties jerseyProperties) { register(HelloResource.class); register(new EndpointLoggingListener(jerseyProperties.getApplicationPath())); }}要注意的一件事是,默认情况下,Jersey
servlet上未设置启动时加载。这意味着,直到第一个请求,Jersey才会在启动时加载。因此,在第一个请求之前,您不会看到侦听器被触发。我打开了一个可能获取配置属性的问题,但与此同时,您有两种选择:
将Jersey设置为过滤器,而不是servlet。过滤器将在启动时加载。对于大多数帖子,使用Jersey作为过滤器,实际上并没有什么不同。要配置它,您只需要在
application.properties
spring.jersey.type=filter
另一个选项是覆盖Jersey
ServletRegistrationBean
并设置其loadOnStartup
属性。这是一个示例配置。一些实施是直接从JerseyAutoConfiguration
@SpringBootApplication
public class JerseyApplication {
public static void main(String[] args) { SpringApplication.run(JerseyApplication.class, args);}@Beanpublic ResourceConfig getResourceConfig(JerseyProperties jerseyProperties) { return new JerseyConfig(jerseyProperties);}@Beanpublic ServletRegistrationBean jerseyServletRegistration( JerseyProperties jerseyProperties, ResourceConfig config) { ServletRegistrationBean registration = new ServletRegistrationBean( new ServletContainer(config), parseApplicationPath(jerseyProperties.getApplicationPath()) ); addInitParameters(registration, jerseyProperties); registration.setName(JerseyConfig.class.getName()); registration.setLoadonStartup(1); return registration;}private static String parseApplicationPath(String applicationPath) { if (!applicationPath.startsWith("/")) { applicationPath = "/" + applicationPath; } return applicationPath.equals("/") ? "/*" : applicationPath + "/*";}private void addInitParameters(RegistrationBean registration, JerseyProperties jersey) { for (Entry<String, String> entry : jersey.getInit().entrySet()) { registration.addInitParameter(entry.getKey(), entry.getValue()); }}}
更新
因此,看起来Spring Boot将要添加该
load-on-startup属性,因此我们不必覆盖Jersey
ServletRegistrationBean。将在Boot 1.4.0中添加



