使用dropwizard(3)-加入DI-dagger2

前言

习惯了Spring全家桶,对spring的容器爱不释手。使用dropwizard,看起来确实很轻,然而,真正使用的时候不得不面临一个问题。我们不可能一个resource就能把所有的业务逻辑囊括!那么,必然就要有负责处理逻辑的代码,有要提取的公共的代码,要做面向接口开发等等。按照简单的用法,Java Bean就自己new,只要通过Jersey提供的web能力发出去就好。这样写下来,到处都需要new,难以测试等等。目前我最care的是,每个request过来都要new一堆重复的对象,垃圾回收频繁。写个单例不就解决了?是的,当然要想到单例,然后发现几乎所有的类都是设计成单例的。然后,一堆单例的代码写的死。这就是样板代码。于是,想到提取工具类,算了,不如用Dagger好了。

什么是Dagger

Dagger是Java里开源的DI框架中最火的之一,主要用在Android领域,很多特性也多针对Android开发的。因为Android开发对省电,性能之类的要求比较高,因此抛弃了反射,直接在编译级别生成工厂。详细学习测试:Dagger2之helloworld原理探究

Demo Source

https://github.com/Ryan-Miao/l4dropwizard

structure

.
├── pom.xml
├── readme.md
└── src
    └── main
        ├── java
        │   └── com
        │       └── test
        │           ├── HelloWorldApplication.java
        │           ├── bundles
        │           │   └── ConnectivityBundle.java
        │           ├── configuration
        │           │   ├── HelloWorldConfiguration.java
        │           │   └── modules
        │           │       ├── ConnectAndReadConfig.java
        │           │       └── GithubApiConfig.java
        │           └── domain
        │               ├── connect
        │               │   ├── FeignClientBuilder.java
        │               │   ├── GithubClient.java
        │               │   └── GithubConnector.java
        │               ├── entiry
        │               │   ├── GithubUser.java
        │               │   └── Saying.java
        │               ├── exception
        │               │   └── UpstreamException.java
        │               ├── health
        │               │   └── TemplateHealthCheck.java
        │               ├── ioc
        │               │   ├── component
        │               │   │   └── GithubComponent.java
        │               │   └── module
        │               │       ├── ConfigurationModule.java
        │               │       ├── ConnectorModule.java
        │               │       └── ServiceModule.java
        │               ├── resource
        │               │   ├── GithubResource.java
        │               │   └── HelloWorldResource.java
        │               └── service
        │                   ├── IGithubService.java
        │                   └── impl
        │                       └── GithubService.java
        └── resources
            └── config
                └── dev.yml

本文基于之前的dropwizard入门演进.

添加dagger依赖

properties结点下新增

<dagger.verion>2.12</dagger.verion>

在dependencies下新增

<dependency>
    <groupId>com.google.dagger</groupId>
    <artifactId>dagger</artifactId>
    <version>${dagger.verion}</version>
</dependency>

build.plugins下新增plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.6.1</version>
    <configuration>
        <source>${java.version}</source>
        <target>${java.version}</target>
        <encoding>UTF-8</encoding>
        <annotationProcessorPaths>
            <path>
                <groupId>com.google.dagger</groupId>
                <artifactId>dagger-compiler</artifactId>
                <version>${dagger.verion}</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

在IDEA设置中,找到Build>Compiler>Annotation Processors, 选择Enable annotation processing.

创建一个Component

下面创建Component,用来包容Resource类,对外提供Resource类。新建com.test.domain.ioc.component.GithubComponent

package com.test.domain.ioc.component;

import com.test.domain.ioc.module.ServiceModule;
import com.test.domain.resource.GithubResource;
import dagger.Component;

import javax.inject.Singleton;

/**
 * Created by Ryan Miao on 10/26/17.
 */
@Singleton
@Component(modules = {ServiceModule.class})
public interface GithubComponent {
     GithubResource gitHubResource();
}

显然,这个GithubResource需要注入一个service,于是声明一个ServiceModule, 创建com.test.domain.ioc.module.ServiceModule

package com.test.domain.ioc.module;

import com.test.domain.service.IGithubService;
import com.test.domain.service.impl.GithubService;
import dagger.Module;
import dagger.Provides;

import javax.inject.Singleton;

/**
 * Created by Ryan Miao on 10/26/17.
 */
@Module(includes = ConnectorModule.class)
public class ServiceModule {

    @Singleton
    @Provides
    public IGithubService githubService(GithubService service) {
        return service;
    }
}

ServiceModule用来提供service注入,service接着依赖connector层,新建com.test.domain.ioc.module.ConnectorModule

package com.test.domain.ioc.module;

import com.test.domain.connect.FeignClientBuilder;
import dagger.Module;
import dagger.Provides;

import javax.inject.Singleton;

/**
 * Created by Ryan Miao on 10/26/17.
 */
@Module(includes = ConfigurationModule.class)
public class ConnectorModule {

    @Provides
    @Singleton
    public FeignClientBuilder feignClientBuilder(){
        return new FeignClientBuilder();
    }
    
}

connecttor层中,需要调用GlobalConfiguration的配置项,所以,单独把配置提出来,引入。新增com.test.domain.ioc.module.ConfigurationModule

package com.test.domain.ioc.module;

import com.test.configuration.HelloWorldConfiguration;
import dagger.Module;
import dagger.Provides;

import javax.inject.Singleton;

/**
 * Created by Ryan Miao on 11/20/17.
 */
@Module
public class ConfigurationModule {
    private final HelloWorldConfiguration configuration;

    public ConfigurationModule(HelloWorldConfiguration configuration) {
        this.configuration = configuration;
    }


    @Provides
    @Singleton
    public HelloWorldConfiguration helloWorldConfiguration(){
        return configuration;
    }
}

这是依赖的最底层,我们通过手动构造函数的方式注入configuration,这样可以在dropwizard启动时生成module,并且得到configuration。

引入我们的Component

这时候,build一下,dagger就会自动生成我们的工厂。

mvn clean install

然后,在IDEA里的maven plugin里,右键,reimport。防止IDEA不认识dagger自动生成的类。dagger自动生成的类位于target/generated-sources/annotations. 点击刷新按钮,刷新下maven依赖。

然后,在com.test.HelloWorldApplication中,新增

private void registerResources(HelloWorldConfiguration configuration, Environment environment) {
    GithubComponent component = DaggerGithubComponent.builder()
            .configurationModule(new ConfigurationModule(configuration))
            .build();
    environment.jersey().register(component.gitHubResource());
}

DaggerGithubComponent要在maven install之后,dagger生成的。完整启动类如下:

public class HelloWorldApplication extends Application<HelloWorldConfiguration> {

    public static void main(String[] args) throws Exception {
        new HelloWorldApplication().run(args);
    }

    @Override
    public String getName() {
        return "hello-world";
    }

    @Override
    public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
        bootstrap.addBundle(new ConnectivityBundle());
    }

    @Override
    public void run(HelloWorldConfiguration configuration, Environment environment) throws Exception {
        final HelloWorldResource resource = new HelloWorldResource(
                configuration.getTemplate(),
                configuration.getDefaultName()
        );
        final TemplateHealthCheck healthCheck =
                new TemplateHealthCheck(configuration.getTemplate());
        environment.healthChecks().register("template", healthCheck);
        environment.jersey().register(resource);
        environment.jersey().register(healthCheck);

        registerResources(configuration, environment);

    }

    private void registerResources(HelloWorldConfiguration configuration, Environment environment) {
        GithubComponent component = DaggerGithubComponent.builder()
                .configurationModule(new ConfigurationModule(configuration))
                .build();
        environment.jersey().register(component.gitHubResource());
    }
}

当然,我们的Resource也要改成Inject模式

public class GithubResource {

    private IGithubService service;

    @Inject
    public GithubResource(IGithubService service) {
        this.service = service;
    }

    @GET
    @Timed
    @Path("/users/{username}")
    public GithubUser getUserProfile(@PathParam("username") final String username) {
        return service.getUserProfile(username);
    }

}

启动,运行。一切OK。以后就可以在需要注入的类的构造器上声明@Inject, 或者在module里@Provide,就可以实现构造解耦。测试不要太方便.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java后端技术

SpringBoot各类扩展点详解

  上篇文章我们深入分析了SpringBoot的一站式启动流程。然后我们知道SpringBoot的主要功能都是依靠它内部很多的扩展点来完成的,那毋容置疑,这些扩...

803
来自专栏情情说

《深入实践Spring Boot》阅读笔记之三:核心技术源代码分析

上篇文章总结了《深入实践Spring Boot》的第二部分,本篇文章总结第三部分,也是最后一部分。这部分主要讲解核心技术的源代码分析,因为篇幅和能力原因,分析的...

4758
来自专栏编程

Spring in Action 要点总结

一、Spring基础 1. Environment 环境抽象:profiles 和 properties. 2. SpEL Spring EL 表达式 3. 设...

1705
来自专栏一个会写诗的程序员的博客

Spring Boot 使用 Zuul 开发 API GatewaySpring Boot 使用 Zuul 开发 API Gateway

Spring Boot 是构建单个微服务应用的理想选择,但是我们还需要以某种方式将它们互相联系起来。这就是 Spring Cloud Netflix 所要解决的...

554
来自专栏zhisheng

Spring Boot 2.0 迁移指南

前提 本文档将帮助您把应用程序迁移到 Spring Boot 2.0。 在你开始之前 首先,Spring Boot 2.0需要Java 8或更高版本。Java ...

80314
来自专栏Kirito的技术分享

浅析Spring中的事件驱动机制

今天来简单地聊聊事件驱动,其实写这篇文章挺令我挺苦恼的,因为事件驱动这个名词,我没有找到很好的定性解释,担心自己的表述有误,而说到事件驱动可能立刻联想到如此众多...

5969
来自专栏全栈架构

Spring Boot 与 kotlin 使用Thymeleaf模板引擎渲染web视图

在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源,使用Spring Boot 与 kotlin如何去支持这些静态资源?,很简单。

733
来自专栏阿杜的世界

Spring Boot Admin的使用

上一篇文章中了解了Spring Boot提供的监控接口,例如:/health、/info等等,实际上除了之前提到的信息,还有其他信息业需要监控:当前处于活跃状态...

622
来自专栏编程微刊

验证码倒计时的注册页面

1042
来自专栏编程坑太多

springboot(15)Spring Security

1112

扫码关注云+社区