├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── io │ │ └── vertx │ │ └── ext │ │ └── spring │ │ ├── ContextFactory.java │ │ ├── VertxSpring.java │ │ ├── annotation │ │ ├── RouterHandler.java │ │ └── VertxRouter.java │ │ └── impl │ │ ├── NamespaceHandler.java │ │ ├── SpringHttpVerticle.java │ │ ├── VertxHolder.java │ │ ├── factory │ │ ├── HttpClientFactory.java │ │ ├── JdbcClientFactory.java │ │ ├── RedisClientFactory.java │ │ ├── RouterFactory.java │ │ └── VertxFactory.java │ │ └── parser │ │ ├── HttpClientParser.java │ │ ├── JdbcParser.java │ │ ├── RedisClientParser.java │ │ ├── RouterParser.java │ │ └── VertxParser.java └── resources │ ├── META-INF │ ├── spring.handlers │ └── spring.schemas │ └── vertx-spring-web.xsd └── test ├── java └── io │ └── vertx │ └── ext │ └── spring │ ├── InMemoryCache.java │ ├── MultiVerticleServer.java │ ├── SimpleTest.java │ └── TestRouter.java └── resources └── test-context.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/src 3 | !.gitignore 4 | !pom.xml 5 | !README.md 6 | /target/**/*.* 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vertx-spring-web 2 | 3 | ## Overview 4 | 5 | `vertx-spring-web` is a vertx module. The goal of `vertx-spring-web` is to integrate vertx-web and spring framework together. 6 | 7 | ### Features 8 | 9 | 1. Annotation-driven web router handlers 10 | 1. Full support for non-blocking I/O model with vertx 11 | 1. Full support for spring IOC 12 | 1. Auto inject frequently-used vertx components (Vertx instance, RedisClient, JDBCClient etc) with spring beanFactory 13 | 14 | ## Documentation 15 | 16 | English | [中文](https://github.com/guoyu511/vertx-spring-web/wiki/%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C) 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | io.vertx 7 | vertx-parent 8 | 5 9 | 10 | 11 | vertx-spring-web 12 | jar 13 | 0.0.1 14 | Spring integrate with vertx-web 15 | 16 | 17 | 3.4.2 18 | 4.11 19 | 4.1.0.RELEASE 20 | 21 | 22 | 23 | 24 | 25 | io.vertx 26 | vertx-dependencies 27 | ${stack.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | 36 | io.vertx 37 | vertx-core 38 | 39 | 40 | io.vertx 41 | vertx-web 42 | 43 | 44 | io.vertx 45 | vertx-jdbc-client 46 | provided 47 | 48 | 49 | io.vertx 50 | vertx-redis-client 51 | provided 52 | 53 | 54 | org.springframework 55 | spring-core 56 | ${spring.version} 57 | 58 | 59 | org.springframework 60 | spring-context 61 | ${spring.version} 62 | 63 | 64 | io.vertx 65 | vertx-core 66 | test-jar 67 | test 68 | 69 | 70 | junit 71 | junit 72 | ${junit.version} 73 | test 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/ContextFactory.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring; 2 | 3 | import org.springframework.context.ApplicationContext; 4 | 5 | /** 6 | * Created by guoyu on 16/6/27. 7 | */ 8 | public interface ContextFactory { 9 | 10 | ApplicationContext create(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/VertxSpring.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring; 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext; 4 | 5 | import io.vertx.core.AsyncResult; 6 | import io.vertx.core.Handler; 7 | import io.vertx.core.Vertx; 8 | import io.vertx.core.http.HttpServerOptions; 9 | import io.vertx.ext.spring.impl.SpringHttpVerticle; 10 | 11 | 12 | public interface VertxSpring { 13 | 14 | static void deploy(Vertx vertx, String configurationFile, HttpServerOptions options) { 15 | deploy(vertx, () -> new ClassPathXmlApplicationContext(configurationFile), options); 16 | } 17 | 18 | static void deploy(Vertx vertx, String configurationFile, HttpServerOptions options, Handler> handler) { 19 | deploy(vertx, () -> new ClassPathXmlApplicationContext(configurationFile), options, handler); 20 | } 21 | 22 | static void deploy(Vertx vertx, ContextFactory factory, HttpServerOptions options) { 23 | deploy(vertx, factory, options, (ar) -> { 24 | }); 25 | } 26 | 27 | static void deploy(Vertx vertx, ContextFactory factory, HttpServerOptions options, Handler> handler) { 28 | vertx.deployVerticle(new SpringHttpVerticle(factory, options), handler); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/annotation/RouterHandler.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.annotation; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import io.vertx.core.http.HttpMethod; 10 | 11 | @Target(ElementType.METHOD) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface RouterHandler { 14 | 15 | HttpMethod method() default HttpMethod.GET; 16 | 17 | String value(); 18 | 19 | boolean worker() default false; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/annotation/VertxRouter.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.annotation; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.TYPE) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface VertxRouter { 12 | 13 | String value() default ""; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/NamespaceHandler.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl; 2 | 3 | import org.springframework.beans.factory.xml.NamespaceHandlerSupport; 4 | 5 | import io.vertx.ext.spring.impl.parser.HttpClientParser; 6 | import io.vertx.ext.spring.impl.parser.JdbcParser; 7 | import io.vertx.ext.spring.impl.parser.RedisClientParser; 8 | import io.vertx.ext.spring.impl.parser.RouterParser; 9 | import io.vertx.ext.spring.impl.parser.VertxParser; 10 | 11 | public class NamespaceHandler extends NamespaceHandlerSupport { 12 | 13 | @Override 14 | public void init() { 15 | registerBeanDefinitionParser("vertx", new VertxParser()); 16 | registerBeanDefinitionParser("router", new RouterParser()); 17 | registerBeanDefinitionParser("http-client", new HttpClientParser()); 18 | registerBeanDefinitionParser("jdbc", new JdbcParser()); 19 | registerBeanDefinitionParser("redis", new RedisClientParser()); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/SpringHttpVerticle.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl; 2 | 3 | import org.springframework.context.ApplicationContext; 4 | 5 | import io.vertx.core.AbstractVerticle; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.http.HttpServerOptions; 8 | import io.vertx.ext.spring.ContextFactory; 9 | import io.vertx.ext.web.Router; 10 | 11 | /** 12 | * Created by guoyu on 16/6/23. 13 | */ 14 | public class SpringHttpVerticle extends AbstractVerticle { 15 | 16 | private ContextFactory factory; 17 | 18 | private ApplicationContext applicationContext; 19 | 20 | private HttpServerOptions options; 21 | 22 | public SpringHttpVerticle(ContextFactory factory, HttpServerOptions options) { 23 | this.factory = factory; 24 | this.options = options; 25 | } 26 | 27 | @Override 28 | public void start(Future startFuture) throws Exception { 29 | vertx.executeBlocking((f) -> { 30 | try { 31 | VertxHolder.set(getVertx()); 32 | applicationContext = factory.create(); 33 | f.complete(applicationContext); 34 | } catch (Exception e) { 35 | f.fail(e); 36 | } 37 | }, (ar) -> { 38 | if (ar.failed()) { 39 | startFuture.fail(ar.cause()); 40 | } else { 41 | Router router = applicationContext.getBean(Router.class); 42 | vertx.createHttpServer(options) 43 | .requestHandler(router::accept) 44 | .listen(); 45 | startFuture.complete(null); 46 | } 47 | }); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/VertxHolder.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl; 2 | 3 | import io.vertx.core.Vertx; 4 | 5 | 6 | public class VertxHolder { 7 | 8 | private static ThreadLocal threadLocal = new ThreadLocal<>(); 9 | 10 | public static Vertx get() { 11 | return threadLocal.get(); 12 | } 13 | 14 | public static void set(Vertx vertx) { 15 | threadLocal.set(vertx); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/factory/HttpClientFactory.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.factory; 2 | 3 | import org.springframework.beans.factory.FactoryBean; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | 6 | import io.vertx.core.Vertx; 7 | import io.vertx.core.http.HttpClient; 8 | import io.vertx.core.http.HttpClientOptions; 9 | 10 | public class HttpClientFactory implements FactoryBean { 11 | 12 | @Autowired 13 | Vertx vertx; 14 | 15 | private boolean keepAlive; 16 | 17 | private int maxPoolSize; 18 | 19 | private boolean pipelining; 20 | 21 | public void setKeepAlive(boolean keepAlive) { 22 | this.keepAlive = keepAlive; 23 | } 24 | 25 | public void setMaxPoolSize(int maxPoolSize) { 26 | this.maxPoolSize = maxPoolSize; 27 | } 28 | 29 | public void setPipelining(boolean pipelining) { 30 | this.pipelining = pipelining; 31 | } 32 | 33 | @Override 34 | public HttpClient getObject() throws Exception { 35 | 36 | return vertx.createHttpClient(new HttpClientOptions() 37 | .setUsePooledBuffers(true) 38 | .setKeepAlive(keepAlive) 39 | .setMaxPoolSize(maxPoolSize) 40 | .setPipelining(pipelining)); 41 | } 42 | 43 | @Override 44 | public Class getObjectType() { 45 | return HttpClient.class; 46 | } 47 | 48 | @Override 49 | public boolean isSingleton() { 50 | return true; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/factory/JdbcClientFactory.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.factory; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.beans.InvalidPropertyException; 5 | import org.springframework.beans.factory.FactoryBean; 6 | import org.springframework.beans.factory.InitializingBean; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.ApplicationContext; 9 | import org.springframework.context.ApplicationContextAware; 10 | 11 | import javax.sql.DataSource; 12 | 13 | import io.vertx.core.Vertx; 14 | import io.vertx.ext.jdbc.JDBCClient; 15 | 16 | public class JdbcClientFactory implements InitializingBean, ApplicationContextAware, FactoryBean { 17 | 18 | @Autowired 19 | Vertx vertx; 20 | 21 | private String dataSourceRef; 22 | 23 | private DataSource dataSource; 24 | 25 | private ApplicationContext applicationContext; 26 | 27 | public void setDataSourceRef(String dataSourceRef) { 28 | this.dataSourceRef = dataSourceRef; 29 | } 30 | 31 | @Override 32 | public JDBCClient getObject() throws Exception { 33 | return JDBCClient.create(vertx, dataSource); 34 | } 35 | 36 | @Override 37 | public Class getObjectType() { 38 | return JDBCClient.class; 39 | } 40 | 41 | @Override 42 | public boolean isSingleton() { 43 | return true; 44 | } 45 | 46 | @Override 47 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 48 | this.applicationContext = applicationContext; 49 | } 50 | 51 | @Override 52 | public void afterPropertiesSet() throws Exception { 53 | Object bean = applicationContext.getBean(dataSourceRef); 54 | if (!DataSource.class.isInstance(bean)) { 55 | throw new InvalidPropertyException(DataSource.class, "data-source-ref", "Invalid DataSource"); 56 | } 57 | dataSource = (DataSource) bean; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/factory/RedisClientFactory.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.factory; 2 | 3 | import org.springframework.beans.factory.FactoryBean; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | 6 | import io.vertx.core.Vertx; 7 | import io.vertx.redis.RedisClient; 8 | import io.vertx.redis.RedisOptions; 9 | 10 | public class RedisClientFactory implements FactoryBean { 11 | 12 | @Autowired 13 | Vertx vertx; 14 | 15 | private String host; 16 | 17 | private int port; 18 | 19 | public void setHost(String host) { 20 | this.host = host; 21 | } 22 | 23 | public void setPort(int port) { 24 | this.port = port; 25 | } 26 | 27 | @Override 28 | public RedisClient getObject() throws Exception { 29 | return RedisClient.create(vertx, new RedisOptions() 30 | .setHost(host) 31 | .setPort(port) 32 | .setTcpKeepAlive(true) 33 | .setTcpNoDelay(true)); 34 | } 35 | 36 | @Override 37 | public Class getObjectType() { 38 | return RedisClient.class; 39 | } 40 | 41 | @Override 42 | public boolean isSingleton() { 43 | return true; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/factory/RouterFactory.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.factory; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.beans.factory.FactoryBean; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.context.ApplicationContextAware; 8 | 9 | import java.lang.reflect.Method; 10 | import java.util.Map; 11 | 12 | import io.vertx.core.Handler; 13 | import io.vertx.core.Vertx; 14 | import io.vertx.core.http.HttpMethod; 15 | import io.vertx.core.logging.Logger; 16 | import io.vertx.core.logging.LoggerFactory; 17 | import io.vertx.ext.spring.annotation.RouterHandler; 18 | import io.vertx.ext.spring.annotation.VertxRouter; 19 | import io.vertx.ext.web.Router; 20 | import io.vertx.ext.web.RoutingContext; 21 | import io.vertx.ext.web.handler.BodyHandler; 22 | 23 | public class RouterFactory implements ApplicationContextAware, FactoryBean { 24 | 25 | private static Logger logger = LoggerFactory.getLogger(RouterFactory.class); 26 | 27 | @Autowired 28 | Vertx vertx; 29 | 30 | private ApplicationContext applicationContext; 31 | 32 | @Override 33 | public Router getObject() throws Exception { 34 | Router router = Router.router(vertx); 35 | Map handlers = applicationContext.getBeansWithAnnotation( 36 | VertxRouter.class); 37 | handlers.values().forEach((handler) -> registerHandlers(router, handler)); 38 | return router; 39 | } 40 | 41 | @Override 42 | public Class getObjectType() { 43 | return Router.class; 44 | } 45 | 46 | @Override 47 | public boolean isSingleton() { 48 | return true; 49 | } 50 | 51 | @Override 52 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 53 | this.applicationContext = applicationContext; 54 | } 55 | 56 | private static void registerHandlers(Router router, Object handler) { 57 | VertxRouter controller = handler.getClass().getAnnotation(VertxRouter.class); 58 | for (Method method : handler.getClass().getMethods()) { 59 | RouterHandler mapping = method.getAnnotation(RouterHandler.class); 60 | if (mapping != null) { 61 | if (method.getParameterTypes().length == 1 && 62 | method.getParameterTypes()[0].equals(RoutingContext.class)) { 63 | registerMethod(router, handler, method, controller, mapping); 64 | } else { 65 | throw new UnsupportedOperationException( 66 | "Handler method " + 67 | handler.getClass().getSimpleName() + "." + method.getName() + 68 | "should only be declared with 1 parameter " + 69 | RoutingContext.class); 70 | } 71 | } 72 | } 73 | } 74 | 75 | private static void registerMethod(Router router, 76 | Object handler, Method method, 77 | VertxRouter controller, RouterHandler mapping) { 78 | if (mapping.method() == HttpMethod.POST || mapping.method() == HttpMethod.PUT) { 79 | router.route(mapping.method(), controller.value() + mapping.value()) 80 | .handler(BodyHandler.create()); 81 | } 82 | if (mapping.worker()) { 83 | router.route(mapping.method(), controller.value() + mapping.value()) 84 | .blockingHandler(new RouterHandlerImpl(handler, method, mapping.method())) 85 | .failureHandler((ctx) -> { 86 | logger.error(ctx.failure()); 87 | ctx.response() 88 | .setStatusCode(500) 89 | .setStatusMessage(ctx.failure().getMessage()); 90 | }); 91 | } else { 92 | router.route(mapping.method(), controller.value() + mapping.value()) 93 | .handler(new RouterHandlerImpl(handler, method, mapping.method())) 94 | .failureHandler((ctx) -> { 95 | logger.error(ctx.failure()); 96 | ctx.response() 97 | .setStatusCode(500) 98 | .setStatusMessage(ctx.failure().getMessage()); 99 | }); 100 | } 101 | logger.info("Register handler " + 102 | mapping.method() + " " + 103 | controller.value() + mapping.value() + 104 | " on " + 105 | handler.getClass().getSimpleName() + 106 | "." + 107 | method.getName()); 108 | } 109 | 110 | private static class RouterHandlerImpl implements Handler { 111 | 112 | Object handler; 113 | 114 | Method method; 115 | 116 | HttpMethod httpMethod; 117 | 118 | RouterHandlerImpl(Object handler, Method method, HttpMethod httpMethod) { 119 | this.handler = handler; 120 | this.method = method; 121 | this.httpMethod = httpMethod; 122 | } 123 | 124 | @Override 125 | public void handle(RoutingContext context) { 126 | logger.debug(context.request().method().toString() + " " + context.request().uri()); 127 | try { 128 | method.invoke(handler, context); 129 | } catch (Throwable e) { 130 | context.fail(e); 131 | } 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/factory/VertxFactory.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.factory; 2 | 3 | import org.springframework.beans.factory.FactoryBean; 4 | 5 | import io.vertx.core.Vertx; 6 | import io.vertx.ext.spring.impl.VertxHolder; 7 | 8 | /** 9 | * Created by guoyu on 16/6/28. 10 | */ 11 | public class VertxFactory implements FactoryBean { 12 | 13 | @Override 14 | public Vertx getObject() throws Exception { 15 | return VertxHolder.get(); 16 | } 17 | 18 | @Override 19 | public Class getObjectType() { 20 | return Vertx.class; 21 | } 22 | 23 | @Override 24 | public boolean isSingleton() { 25 | return true; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/parser/HttpClientParser.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.parser; 2 | 3 | import org.springframework.beans.MutablePropertyValues; 4 | import org.springframework.beans.factory.config.BeanDefinition; 5 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 6 | import org.springframework.beans.factory.support.GenericBeanDefinition; 7 | import org.springframework.beans.factory.xml.BeanDefinitionParser; 8 | import org.springframework.beans.factory.xml.ParserContext; 9 | import org.w3c.dom.Element; 10 | 11 | import io.vertx.ext.spring.impl.factory.HttpClientFactory; 12 | 13 | /** 14 | * Created by guoyu on 16/3/14. 15 | */ 16 | public class HttpClientParser implements BeanDefinitionParser { 17 | 18 | @Override 19 | public BeanDefinition parse(Element element, ParserContext parserContext) { 20 | BeanDefinitionRegistry registry = parserContext.getRegistry(); 21 | GenericBeanDefinition def = new GenericBeanDefinition(); 22 | MutablePropertyValues prop = new MutablePropertyValues(); 23 | def.setBeanClass(HttpClientFactory.class); 24 | prop.addPropertyValue("keepAlive", element.getAttribute("keep-alive")); 25 | prop.addPropertyValue("maxPoolSize", element.getAttribute("max-pool-size")); 26 | prop.addPropertyValue("pipelining", element.getAttribute("pipelining")); 27 | def.setPropertyValues(prop); 28 | registry.registerBeanDefinition("httpClient", def); 29 | return def; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/parser/JdbcParser.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.parser; 2 | 3 | import org.springframework.beans.MutablePropertyValues; 4 | import org.springframework.beans.factory.config.BeanDefinition; 5 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 6 | import org.springframework.beans.factory.support.GenericBeanDefinition; 7 | import org.springframework.beans.factory.xml.BeanDefinitionParser; 8 | import org.springframework.beans.factory.xml.ParserContext; 9 | import org.w3c.dom.Element; 10 | 11 | import io.vertx.ext.spring.impl.factory.JdbcClientFactory; 12 | 13 | /** 14 | * Created by guoyu on 16/3/14. 15 | */ 16 | public class JdbcParser implements BeanDefinitionParser { 17 | 18 | @Override 19 | public BeanDefinition parse(Element element, ParserContext parserContext) { 20 | BeanDefinitionRegistry registry = parserContext.getRegistry(); 21 | GenericBeanDefinition def = new GenericBeanDefinition(); 22 | MutablePropertyValues prop = new MutablePropertyValues(); 23 | def.setBeanClass(JdbcClientFactory.class); 24 | String id = element.getAttribute("id"); 25 | prop.addPropertyValue("dataSourceRef", element.getAttribute("data-source-ref")); 26 | def.setPropertyValues(prop); 27 | registry.registerBeanDefinition(id, def); 28 | return def; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/parser/RedisClientParser.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.parser; 2 | 3 | import org.springframework.beans.MutablePropertyValues; 4 | import org.springframework.beans.factory.config.BeanDefinition; 5 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 6 | import org.springframework.beans.factory.support.GenericBeanDefinition; 7 | import org.springframework.beans.factory.xml.BeanDefinitionParser; 8 | import org.springframework.beans.factory.xml.ParserContext; 9 | import org.w3c.dom.Element; 10 | 11 | import io.vertx.ext.spring.impl.factory.RedisClientFactory; 12 | 13 | /** 14 | * Created by guoyu on 16/3/14. 15 | */ 16 | public class RedisClientParser implements BeanDefinitionParser { 17 | 18 | @Override 19 | public BeanDefinition parse(Element element, ParserContext parserContext) { 20 | BeanDefinitionRegistry registry = parserContext.getRegistry(); 21 | GenericBeanDefinition def = new GenericBeanDefinition(); 22 | MutablePropertyValues prop = new MutablePropertyValues(); 23 | def.setBeanClass(RedisClientFactory.class); 24 | String id = element.getAttribute("id"); 25 | prop.addPropertyValue("host", element.getAttribute("host")); 26 | prop.addPropertyValue("port", element.getAttribute("port")); 27 | def.setPropertyValues(prop); 28 | registry.registerBeanDefinition(id, def); 29 | return def; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/parser/RouterParser.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.parser; 2 | 3 | import org.springframework.beans.factory.config.BeanDefinition; 4 | import org.springframework.beans.factory.support.BeanDefinitionDefaults; 5 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 6 | import org.springframework.beans.factory.support.GenericBeanDefinition; 7 | import org.springframework.beans.factory.xml.BeanDefinitionParser; 8 | import org.springframework.beans.factory.xml.ParserContext; 9 | import org.springframework.context.ConfigurableApplicationContext; 10 | import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; 11 | import org.springframework.core.type.filter.AnnotationTypeFilter; 12 | import org.springframework.util.StringUtils; 13 | import org.w3c.dom.Element; 14 | 15 | import io.vertx.ext.spring.annotation.VertxRouter; 16 | import io.vertx.ext.spring.impl.factory.RouterFactory; 17 | 18 | /** 19 | * Created by guoyu on 16/3/14. 20 | */ 21 | public class RouterParser implements BeanDefinitionParser { 22 | 23 | @Override 24 | public BeanDefinition parse(Element element, ParserContext parserContext) { 25 | BeanDefinitionRegistry registry = parserContext.getRegistry(); 26 | ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(parserContext.getRegistry(), false); 27 | BeanDefinitionDefaults defaults = new BeanDefinitionDefaults(); 28 | defaults.setLazyInit(true); 29 | scanner.setBeanDefinitionDefaults(defaults); 30 | String basePackage = element.getAttribute("base-package"); 31 | scanner.addIncludeFilter(new AnnotationTypeFilter(VertxRouter.class)); 32 | scanner.scan(StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); 33 | GenericBeanDefinition def = new GenericBeanDefinition(); 34 | def.setBeanClass(RouterFactory.class); 35 | registry.registerBeanDefinition("vertx-spring-web-router", def); 36 | return def; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/vertx/ext/spring/impl/parser/VertxParser.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring.impl.parser; 2 | 3 | import org.springframework.beans.factory.config.BeanDefinition; 4 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 5 | import org.springframework.beans.factory.support.GenericBeanDefinition; 6 | import org.springframework.beans.factory.xml.BeanDefinitionParser; 7 | import org.springframework.beans.factory.xml.ParserContext; 8 | import org.w3c.dom.Element; 9 | 10 | import io.vertx.ext.spring.impl.factory.VertxFactory; 11 | 12 | /** 13 | * Created by guoyu on 16/6/28. 14 | */ 15 | public class VertxParser implements BeanDefinitionParser { 16 | 17 | @Override 18 | public BeanDefinition parse(Element element, ParserContext parserContext) { 19 | BeanDefinitionRegistry registry = parserContext.getRegistry(); 20 | GenericBeanDefinition def = new GenericBeanDefinition(); 21 | def.setBeanClass(VertxFactory.class); 22 | registry.registerBeanDefinition("vertx", def); 23 | return def; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.handlers: -------------------------------------------------------------------------------- 1 | http\://www.vertx.io/schema/vertx-spring-web=io.vertx.ext.spring.impl.NamespaceHandler -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.schemas: -------------------------------------------------------------------------------- 1 | http\://www.vertx.io/schema/vertx-spring-web.xsd=vertx-spring-web.xsd -------------------------------------------------------------------------------- /src/main/resources/vertx-spring-web.xsd: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/spring/InMemoryCache.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.HashMap; 6 | 7 | @Component 8 | public class InMemoryCache { 9 | 10 | // shared by verticles 11 | private static HashMap testMap = new HashMap<>(); 12 | 13 | String get(String key) { 14 | return testMap.getOrDefault(key, ""); 15 | } 16 | 17 | String set(String key, String value) { 18 | testMap.put(key, value); 19 | return value; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/spring/MultiVerticleServer.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring; 2 | 3 | import java.util.Arrays; 4 | 5 | import io.vertx.core.CompositeFuture; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.Vertx; 8 | import io.vertx.core.http.HttpServerOptions; 9 | 10 | /** 11 | * Created by guoyu on 16/6/23. 12 | */ 13 | public class MultiVerticleServer { 14 | 15 | public static void main(String[] args) { 16 | Vertx vertx = Vertx.vertx(); 17 | CompositeFuture.all( 18 | Arrays.asList( 19 | deploy(vertx), 20 | deploy(vertx), 21 | deploy(vertx), 22 | deploy(vertx)) 23 | ).setHandler((res) -> { 24 | if (res.failed()) { 25 | res.cause().printStackTrace(); 26 | } 27 | }); 28 | } 29 | 30 | private static Future deploy(Vertx vertx) { 31 | Future future = Future.future(); 32 | VertxSpring.deploy(vertx, 33 | "test-context.xml", 34 | new HttpServerOptions() 35 | .setPort(8080), 36 | future.completer()); 37 | return future; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/spring/SimpleTest.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring; 2 | 3 | import org.junit.Test; 4 | 5 | import io.vertx.core.AsyncResult; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.Handler; 8 | import io.vertx.core.Vertx; 9 | import io.vertx.core.http.HttpClient; 10 | import io.vertx.core.http.HttpServerOptions; 11 | import io.vertx.test.core.AsyncTestBase; 12 | 13 | public class SimpleTest extends AsyncTestBase { 14 | 15 | private Vertx vertx = Vertx.vertx(); 16 | 17 | private HttpClient client; 18 | 19 | @Test 20 | public void testServer() { 21 | vertx = Vertx.vertx(); 22 | client = vertx.createHttpClient(); 23 | VertxSpring.deploy(vertx, 24 | "test-context.xml", 25 | new HttpServerOptions() 26 | .setPort(8080), 27 | (deployRes) -> { 28 | if (deployRes.failed()) { 29 | deployRes.cause().printStackTrace(); 30 | assertTrue(deployRes.succeeded()); 31 | return; 32 | } 33 | testAll((testRes) -> 34 | vertx.undeploy(deployRes.result(), (undeployRes) -> { 35 | testComplete(); 36 | }) 37 | ); 38 | }); 39 | await(); 40 | } 41 | 42 | private void testAll(Handler> handler) { 43 | testPut("a", "1", (ar) -> 44 | testGet("a", "1", handler) 45 | 46 | ); 47 | } 48 | 49 | private void testPut(String key, String value, Handler> handler) { 50 | client.put(8080, "127.0.0.1", "/test?key=" + key + "&value=" + value, (response) -> { 51 | if (response.statusCode() != 200) { 52 | handler.handle(Future.failedFuture(response.statusMessage())); 53 | return; 54 | } 55 | response 56 | .exceptionHandler((e) -> 57 | handler.handle(Future.failedFuture(e)) 58 | ) 59 | .bodyHandler((buff) -> 60 | handler.handle(Future.succeededFuture()) 61 | ); 62 | }).end(); 63 | } 64 | 65 | private void testGet(String key, String value, Handler> handler) { 66 | client.getNow(8080, "127.0.0.1", "/test?key=" + key, (response) -> { 67 | if (response.statusCode() != 200) { 68 | handler.handle(Future.failedFuture(response.statusMessage())); 69 | return; 70 | } 71 | response 72 | .exceptionHandler((e) -> 73 | handler.handle(Future.failedFuture(e)) 74 | ) 75 | .bodyHandler((buff) -> { 76 | assertEquals(value, buff.toString()); 77 | handler.handle(Future.succeededFuture()); 78 | }); 79 | }); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/io/vertx/ext/spring/TestRouter.java: -------------------------------------------------------------------------------- 1 | package io.vertx.ext.spring; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | 6 | import java.util.HashMap; 7 | import java.util.Optional; 8 | 9 | import io.vertx.core.http.HttpMethod; 10 | import io.vertx.ext.spring.annotation.RouterHandler; 11 | import io.vertx.ext.spring.annotation.VertxRouter; 12 | import io.vertx.ext.web.RoutingContext; 13 | import io.vertx.redis.RedisClient; 14 | 15 | @VertxRouter 16 | public class TestRouter { 17 | 18 | @Autowired 19 | @Qualifier("testRedis") 20 | RedisClient redis; 21 | 22 | @Autowired InMemoryCache testCache; 23 | 24 | @RouterHandler(method = HttpMethod.GET, value = "/test") 25 | public void testGet(RoutingContext context) { 26 | String key = context.request().params().get("key"); 27 | context.response() 28 | .end(testCache.get(key)); 29 | } 30 | 31 | @RouterHandler(method = HttpMethod.PUT, value = "/test") 32 | public void testSet(RoutingContext context) { 33 | String key = context.request().params().get("key"); 34 | String value = context.request().params().get("value"); 35 | testCache.set(key, value); 36 | context.response().end(value); 37 | } 38 | 39 | @RouterHandler(method = HttpMethod.GET, value = "/redis") 40 | public void testRedisGet(RoutingContext context) { 41 | String key = context.request().params().get("key"); 42 | redis.get(key, (res) -> { 43 | if (res.failed()) { 44 | context.response() 45 | .setStatusCode(500) 46 | .end(res.cause().getMessage()); 47 | return; 48 | } 49 | context.response() 50 | .end(Optional.ofNullable(res.result()).orElse("")); 51 | }); 52 | } 53 | 54 | @RouterHandler(method = HttpMethod.PUT, value = "/redis") 55 | public void testRedisSet(RoutingContext context) { 56 | String key = context.request().params().get("key"); 57 | String value = context.request().params().get("value"); 58 | redis.set(key, value, (res) -> { 59 | if (res.failed()) { 60 | context.response() 61 | .setStatusCode(500) 62 | .end(res.cause().getMessage()); 63 | return; 64 | } 65 | context.response().end(value); 66 | }); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/resources/test-context.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | --------------------------------------------------------------------------------