Skip to content
This repository has been archived by the owner on Jun 6, 2018. It is now read-only.

Commit

Permalink
#3 swagger support
Browse files Browse the repository at this point in the history
  • Loading branch information
calvin1978 committed Dec 23, 2016
1 parent d3133dd commit 6497c49
Show file tree
Hide file tree
Showing 16 changed files with 202 additions and 41 deletions.
Binary file removed doc/architecture.jpg
Binary file not shown.
Binary file removed doc/lifecycle.jpg
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

import io.springside.springtime.springboot.EnableSpringTime;
import io.springside.springtime.springboot.SpringTimeConfiguration;
import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@Import(SpringTimeConfiguration.class)
@EnableSwagger2
@EnableSpringTime
public class HelloServiceApp {
public static void main(String[] args) throws Exception {
SpringApplication.run(HelloServiceApp.class, args);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package io.springside.springtime.examples.helloservice.idl;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Api("Greeting Service")
public interface GreetingService {


public static class HelloRequest {
public String name;
}
Expand All @@ -18,8 +23,10 @@ public static class WeatherResponse {
public String weather;
}

@ApiOperation(value = "hello")
public HelloResponse hello(HelloRequest helloRequest);

@ApiOperation(value = "weather")
public WeatherResponse weather(WeatherRequest weatherRequest);

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package io.springside.springtime.examples.helloservice.service;

import org.springframework.stereotype.Controller;

import io.springside.springtime.examples.helloservice.idl.GreetingService;
import io.springside.springtime.springboot.SpringTimeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Api("greeting")
@Controller("greeting")
@SpringTimeService("greeting")
public class GreetingServiceImpl implements GreetingService {

@Override
Expand Down
8 changes: 7 additions & 1 deletion springtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,15 @@

<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<artifactId>swagger-core</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>${swagger.version}</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

import io.springside.springtime.serializer.JsonSerializer;
import io.springside.springtime.serializer.Serializer;
import io.springside.springtime.service.ServiceBeanFactory;
import io.springside.springtime.service.ServiceDispatcher;
import io.springside.springtime.service.ServiceBeanRegistry;
import io.swagger.annotations.Api;
import io.springside.springtime.springboot.SpringTimeService;

/**
* Jetty的Handler.
Expand All @@ -32,13 +32,14 @@ public class SpringTimeHandler extends AbstractHandler {
private Serializer serializer = new JsonSerializer();

public SpringTimeHandler(ApplicationContext applicationContext) {
ServiceBeanRegistry serviceRegistry = new ServiceBeanRegistry();
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Api.class);
ServiceBeanFactory serviceBeanFactory = new ServiceBeanFactory();
//TODO: 检查名称重复的方法
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(SpringTimeService.class);
for (Entry<String, Object> entry : beans.entrySet()) {
serviceRegistry.add(RPC_PREFIX, entry.getKey(), entry.getValue());
serviceBeanFactory.add(RPC_PREFIX, entry.getKey(), entry.getValue());
}

dispatcher = new ServiceDispatcher(serviceRegistry);
dispatcher = new ServiceDispatcher(serviceBeanFactory);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/**
* 保存通过cglib快速执行服务方法的MethodInvoker
*/
public class ServiceBeanRegistry {
public class ServiceBeanFactory {
//key: path
public Map<String, MethodInvoker> methodInvokerMap = new HashMap<String, MethodInvoker>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import java.io.OutputStream;

import io.springside.springtime.serializer.Serializer;
import io.springside.springtime.service.ServiceBeanRegistry.MethodInvoker;
import io.springside.springtime.service.ServiceBeanFactory.MethodInvoker;

public class ServiceDispatcher {

private ServiceBeanRegistry registry;
private ServiceBeanFactory registry;

public ServiceDispatcher(ServiceBeanRegistry registry) {
public ServiceDispatcher(ServiceBeanFactory registry) {
this.registry = registry;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.springside.springtime.springboot;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import org.springframework.context.annotation.Import;

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({SpringTimeConfiguration.class})
public @interface EnableSpringTime {

}
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
package io.springside.springtime.springboot;

import static springfox.documentation.builders.PathSelectors.*;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import com.google.common.base.Predicates;

import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import io.springside.springtime.swagger.SpringFoxConfiguration;

@ComponentScan
@Configuration
@Import(SpringFoxConfiguration.class)
public class SpringTimeConfiguration {

@Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2).groupName("business-api").select().paths(Predicates.not(regex("/manage.*"))) // and by paths
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.web.ServerProperties;
Expand All @@ -23,15 +24,17 @@
import io.springside.springtime.jetty.SpringTimeHandler;

/**
* 定制化Jetty,加入Http/Http2支持,指定专门的
* 定制化Jetty,加入Http/Http2支持,指定专门的Handler
*/
@Component
@ConfigurationProperties(prefix = "server.jetty", ignoreUnknownFields = true)
public class SpringTimeJettyCustomizer implements EmbeddedServletContainerCustomizer, ApplicationContextAware {

private ApplicationContext applicationContext;

private Integer maxThreads = Runtime.getRuntime().availableProcessors() * 20;
private Integer minThreads = Math.max(8, Runtime.getRuntime().availableProcessors());

private Integer maxThreads = Math.max(200, Runtime.getRuntime().availableProcessors() * 20);

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
Expand Down Expand Up @@ -77,34 +80,31 @@ private void customizeHttp2Connector(Server server) {
}

private void customizeSpringTimeHanlder(Server server) {
// add SpringTimeHandler at the beginning
// add SpringTimeHandler as first handler
Handler[] oldHandlers = server.getHandlers();
SpringTimeHandler springTimeHandler = new SpringTimeHandler(applicationContext);

HandlerList handlerList = new HandlerList();
handlerList.addHandler(springTimeHandler);
for (Handler handler : oldHandlers) {
handlerList.addHandler(handler);
}
handlerList.setHandlers(ArrayUtil.prependToArray(springTimeHandler, oldHandlers, Handler.class));

server.setHandler(handlerList);
}

});
}

private void customizeThreadPool(JettyEmbeddedServletContainerFactory jettyFactory) {
QueuedThreadPool threadPool = (QueuedThreadPool) jettyFactory.getThreadPool();
if (threadPool == null) {
threadPool = new QueuedThreadPool();
jettyFactory.setThreadPool(threadPool);
}
threadPool.setMaxThreads(maxThreads);
threadPool.setIdleTimeout(10000);
QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, minThreads, 10000);
jettyFactory.setThreadPool(threadPool);
}

public void setMaxThreads(Integer maxThreads) {
this.maxThreads = maxThreads;
}

public void setMinThreads(Integer minThreads) {
this.minThreads = minThreads;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.springside.springtime.springboot;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Component;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface SpringTimeService {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
String value() default "";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.springside.springtime.swagger;

import static springfox.documentation.builders.PathSelectors.*;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.google.common.base.Predicates;

import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@ComponentScan
@Configuration
public class SpringFoxConfiguration {

//TODO: manage路径从Spring里读
@Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2).groupName("restful-api").select()
.paths(Predicates.not(regex("/manage.*"))).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.springside.springtime.swagger;

import static org.springframework.http.MediaType.*;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import io.springside.springtime.springboot.SpringTimeService;
import io.swagger.jaxrs.Reader;
import io.swagger.jaxrs.config.ReaderConfigUtils;
import io.swagger.models.Info;
import io.swagger.models.Swagger;
import springfox.documentation.annotations.ApiIgnore;

@RestController
@ApiIgnore
public class SpringTimeSwaggerDocsController implements InitializingBean, ApplicationContextAware {
private Swagger swagger;

private ApplicationContext applicationContext;

@Override
public void afterPropertiesSet() throws Exception {
swagger = new Swagger();
Info info = new Info();
info.setTitle("GreetingService");
swagger.setInfo(info);

Map<String, Object> beans = applicationContext.getBeansWithAnnotation(SpringTimeService.class);
Set<Class<?>> classes = new HashSet<Class<?>>();
for (Object bean : beans.values()) {
classes.add(bean.getClass());
}

Reader reader = new Reader(swagger, ReaderConfigUtils.getReaderConfig(null));
swagger = reader.read(classes);
}

@RequestMapping(value = "/v2/rfc-api-docs", method = RequestMethod.GET, produces = { APPLICATION_JSON_VALUE })
public @ResponseBody Swagger getDocumentation(HttpServletRequest servletRequest) {
return swagger;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.springside.springtime.swagger;

import java.util.List;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider;
import springfox.documentation.swagger.web.SwaggerResource;

@Component
@Primary
public class SpringTimeSwaggerProvider extends InMemorySwaggerResourcesProvider {

public SpringTimeSwaggerProvider(DocumentationCache documentationCache) {
super(documentationCache);
}

@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = super.get();
SwaggerResource springTimeResource = new SwaggerResource();
springTimeResource.setName("SpringTime");
springTimeResource.setLocation("/v2/rfc-api-docs");
resources.add(0, springTimeResource);
return resources;
}

}

0 comments on commit 6497c49

Please sign in to comment.