因项目使用 Guice + Jersey + Jetty 框架,所有进行了学习,下面是学习笔记。
目录
一、Guice
1. 依赖注入方式: @Inject
2. 依赖绑定(依赖注册): bind()
3. 作用域
4. 基本使用
二、Jersey
使用内置容器为例(使用Jetty发布Jersey服务)
三、Jetty
四、Guice + Jersey + Jetty Demo
Guice 是谷歌推出的一个轻量级 依赖注入 框架。官网地址:GitHub - google/guice: Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 8 and above, brought to you by Google.
① 构造注入
public class OrderServiceImpl implements OrderService {
private ItemService itemService;
private PriceService priceService;
@Inject
public OrderServiceImpl(ItemService itemService, PriceService priceService) {
this.itemService = itemService;
this.priceService = priceService;
}
}
② 一般注入
public class OrderServiceImpl implements OrderService {
private ItemService itemService;
private PriceService priceService;
@Inject
public void init(ItemService itemService, PriceService priceService) {
this.itemService = itemService;
this.priceService = priceService;
}
}
public class OrderServiceImpl implements OrderService {
private ItemService itemService;
private PriceService priceService;
@Inject
public void setItemService(ItemService itemService) {
this.itemService = itemService;
}
@Inject
public void setPriceService(PriceService priceService) {
this.priceService = priceService;
}
}
Guice 提供依赖配置类:继承 AbstractModule,实现 configure 或者使用 @Provides 方法,完成依赖绑定。
Binder 语义:
基本配置:binder.bind(serviceClass).to(implClass).in(Scopes.[SINGLETON | NO_SCOPE]);
无base类、接口配置:binder.bind(implClass).in(Scopes.[SINGLETON | NO_SCOPE]);
service实例配置:binder.bind(serviceClass).toInstance(servieInstance).in(Scopes.[SINGLETON | NO_SCOPE]);
多个实例按名注入:binder.bind(serviceClass).annotatedWith(Names.named(“name”)).to(implClass).in(Scopes.[SINGLETON | NO_SCOPE]);
① 基本绑定
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
}
}
② @Named 注解绑定(多实现绑定同一个接口)
// 1.注入的地方添加 @Named 注解
@Inject
public RealBillingService(@Named("Checkout") CreditCardProcessor processorg, TransactionLog transactionLog) {
// ......
}
// 2.在绑定中添加 annotatedWith 方法指定 @Named 中指定的名称
bind(TransactionLog.class).to(TransactionLogImpl.class);
bind(CreditCardProcessor.class)
.annotatedWith(Names.named("Checkout"))
.to(CheckoutCreditCardProcessor.class);
// 1.注入
@Inject
public List getAllItemServices(@Named("impl1") NamedService nameService1,
@Named("impl2") NamedService nameService2) {
}
// 2.绑定
bind(NamedService.class).annotatedWith(Names.named("impl1")).to(NamedServiceImpl1.class);
bind(NamedService.class).annotatedWith(Names.named("impl2")).to(NamedServiceImpl2.class);
③ toInstance 实例绑定
bind(String.class)
.annotatedWith(Names.named("JDBC URL"))
.toInstance("jdbc:mysql://localhost/pizza");
④ @Provides 方法
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
...
}
@Provides
TransactionLog provideTransactionLog() {
DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
transactionLog.setThreadPoolSize(30);
return transactionLog;
}
}
Guice 提供了很多作用域,有单例 Singleton,Session 作用域 SessionScoped,Request 请求作用域 RequestScoped 等等。
默认情况下 Guice 会在每次注入的时候创建一个新对象,用以下方式设置作用域:
① 实现类上添加 @Singleton 注解
@Singleton
public class InMemoryTransactionLog implements TransactionLog {
/* everything here should be threadsafe! */
}
② 在配置类中指定
bind(TranLog.class).to(TranLogImpl.class).in(Singleton.class);
③ 在 @Provides 方法中也中指定单例
@Provides @Singleton
TransactionLog provideTransactionLog() {
...
}
① 引入依赖
com.google.inject
guice
4.1.0
② 业务接口 和 接口实现
public interface UserService {
void process();
}
public class UserServiceImpl implements UserService {
@Override
public void process() {
System.out.println("我需要做一些业务逻辑");
}
}
③ 注入
public interface Application {
void work();
}
public class MyApp implements Application {
private UserService userService;
@Inject
public MyApp(UserService userService) {
this.userService = userService;
}
@Override
public void work() {
userService.process();
}
}
④ 依赖绑定
public class MyAppModule extends AbstractModule {
@Override
protected void configure() {
bind(UserService.class).to(UserServiceImpl.class);
bind(Application.class).to(MyApp.class);
}
}
⑤ 创建注入器 Guice.createInjector
public class MyAppTest {
private static Injector injector;
@BeforeClass
public static void init() {
injector = Guice.createInjector(new MyAppModule());
}
@Test
public void testMyApp() {
Application myApp = injector.getInstance(Application.class);
myApp.work();
}
}
参考1:JAVA轻量级IOC框架Guice - Leejk - 博客园
参考2:Guice 快速入门 - 腾讯云开发者社区-腾讯云
guice 官网地址:GitHub - google/guice: Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 8 and above, brought to you by Google.
Jersey 是一个 REST 框架,官网地址:Eclipse Jersey
基于 Jersey 的 REST 应用,可以运行在 Servlet 环境下(例如 Tomcat),也可以脱离 Servlet 环境,使用内置容器(例如 Jetty)。
注意:
jersey 1.X 使用的是 sun 的 com.sun.jersey
jersey 2.X 使用的是 glassfish 的 org.glassfish.jersey
jersey 1.X
项目结构:
① 添加 maven 依赖
org.eclipse.jetty
jetty-server
9.3.8.v20160314
org.eclipse.jetty
jetty-servlet
9.3.8.v20160314
com.sun.jersey
jersey-server
1.19.1
com.sun.jersey
jersey-servlet
1.19.1
② 创建一个 JettyServer 类,用于配置 Jetty 环境:
package com.yuyu.jersey;
public class JettyServer {
private void start() throws Exception {
Server server = new Server(8080);
ServletContextHandler context =
new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
ServletHolder sh = new ServletHolder(ServletContainer.class);
sh.setInitParameter(
"com.sun.jersey.config.property.resourceConfigClass",
"com.sun.jersey.api.core.PackagesResourceConfig");
sh.setInitParameter(
"com.sun.jersey.config.property.packages",
"com.yuyu.jersey.api");
context.addServlet(sh, "/*");
server.start();
}
public void stop() throws Exception {
}
public static void main(String[] args) throws Exception {
JettyServer server = new JettyServer();
server.start();
}
}
③ REST 服务的类(也称资源类,路径要和上面配置的保持一致)
package com.yuyu.jersey.api;
@Path("/welcome")
public class WelcomeResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sayHello() {
return "Welcome to Jersey world";
}
}
执行 main 方法,请求 http://localhost:8080/welcome,得到响应:
jersey 2.X
项目结构:
① 添加 maven 依赖
org.glassfish.jersey.containers
jersey-container-jetty-http
2.21
② 创建一个 Application 类,用于设置发布环境:
package com.yuyu.jersey;
public class RestApplication extends ResourceConfig {
public RestApplication(){
this.packages("com.yuyu.jersey");
}
}
· ResourceConfig 类继承了 Application 类,此类是 Jersey 中的基础类,用于定义一个 JAX-RS 应用的基础组件。
· 在 RestApplication 类的构造方法中,我们调用了 packages 方法注册了扫描资源类的基础包。
③ REST 服务的类(也称资源类)
package com.yuyu.jersey.test.demo;
@Path("hello")
public class HelloService {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hi(){
return "hello jersey";
}
}
1. 在类上面添加了 @Path("hello"),代表资源根路径为 hello;
2. @GET 代表该方法接受 GET类型请求;
3. @Produces 代表该方法的响应类型为 text/plain;
4. 该方法返回 String,这个 String 值 Jersey 会自动按照 text/plain 格式输出。
④ 发布应用
package com.yuyu.jersey;
public class App {
public static void main(String[] args) {
JettyHttpContainerFactory.createServer(URI.create("http://localhost:8082/"), new RestApplication());
}
}
执行 main 方法,请求 localhost:8082/hello,得到响应:
参考1:Jersey 开发RESTful(七)Jersey快速入门 - 简书
参考2:Jersey 开发RESTful(八)Jersey参数绑定 - 简书
参考3:Jetty + Jersey简单RESTful例子_飞飞好奇的博客-CSDN博客
jersey 官网:Eclipse Jersey
Jetty 是一个开源的 servlet 容器,可以为JSP和Servlet提供运行时环境。
jetty 与 tomcat 区别:
(1) Jetty 比 Tomcat 架构更加简单。 jetty的所有组件都是基于 Handler 来实现,它的主要功能扩展都可以用 Handler 来实现。
(2) jetty 比较容易扩展第三方框架,所以也跟容易定制
(3) jetty更加轻量可以节省内存;
(4) tomcat 更加稳定、更加成熟。
参考:jetty、jetty原理、jetty与tomcat区别 - 知乎
项目结构:
① 添加 maven 依赖
org.eclipse.jetty
jetty-server
9.3.24.v20180605
org.eclipse.jetty
jetty-servlet
9.3.24.v20180605
com.google.inject.extensions
guice-servlet
4.2.3
com.google.inject
guice
4.2.3
com.sun.jersey
jersey-server
1.19
com.sun.jersey.contribs
jersey-guice
1.19
② 创建一个资源 api 服务
@Path("/myTest")
public class ResourceTest {
@GET
@Path("/test")
@Produces(MediaType.TEXT_PLAIN)
public String testApi(){
return "this is a test";
}
}
③ 创建 WebServer 配置 servlet
public class WebServer {
private final Server jetty;
private final Connector connector;
@Inject
public WebServer(Server jetty, Connector connector) {
this.jetty = jetty;
this.connector = connector;
}
public void start() throws Exception {
this.jetty.addConnector(connector);
ServletHolder apiServletHolder = new ServletHolder(new GuiceContainer(Start.getInjector()));
apiServletHolder.setInitParameter("com.sun.jersey.config.property.resourceConfigClass", "com.sun.jersey.api.core.PackagesResourceConfig");
apiServletHolder.setInitParameter("com.sun.jersey.config.property.packages", "com.yuyu.demo.api");
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.addServlet(apiServletHolder, "/*");
this.jetty.setHandler(context);
this.jetty.start();
}
public void stop() throws Exception {
this.jetty.stop();
}
}
④ 实现 ConnectorProvider 为 jetty 提供 http 连接
public class HttpConnectorProvider implements Provider {
private Server jetty;
@Inject
public HttpConnectorProvider(Server jetty) {
this.jetty = jetty;
}
@Override
public Connector get() {
ServerConnector ret = new ServerConnector(this.jetty);
ret.setName("test");
ret.setHost("0.0.0.0");
ret.setPort(8089);
return ret;
}
}
⑤ 创建 WebServerModule 绑定依赖
public class WebServerModule extends AbstractModule {
private Server jetty;
public WebServerModule() throws Exception {
this.jetty = new Server();
}
@Override
protected void configure() {
bind(Server.class).in(Scopes.SINGLETON);
bind(WebServer.class).in(Scopes.SINGLETON);
bind(Connector.class).toProvider(HttpConnectorProvider.class);
}
}
⑥ 创建 main 方法执行服务
public class Start {
private static Injector injector;
public static void main(String[] args) throws Exception {
injector = Guice.createInjector(new WebServerModule());
WebServer webServer = injector.getInstance(WebServer.class);
webServer.start();
}
public static Injector getInjector() {
return injector;
}
}
执行结果:
参考:GitHub - sunnygleason/j4-minimal: Minimal web application example using Embedded Jetty, Jersey, Guice, and Jackson