前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Guice依赖注入(Scope)

Guice依赖注入(Scope)

原创
作者头像
程序猿梦工厂
修改2021-09-06 14:14:06
1K0
修改2021-09-06 14:14:06
举报
文章被收录于专栏:程序猿梦工厂程序猿梦工厂

本文章主要详细讲解Guice依赖注入中的一些高级选项,他们分别是ScopeEagerly Loading BindingsStageOptional Injection。我们将一一对他们进行讲解。

基础环境

技术

版本

Java

1.8+

Guice

4.2.3

初始化项目

  • 初始化项目
代码语言:txt
复制
mvn archetype:generate -DgroupId=io.edurt.lc.guice -DartifactId=guice-binder-scope -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0.0 -DinteractiveMode=false
  • 修改pom.xml增加Guice依赖
代码语言:txt
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>lc-guice</artifactId>
        <groupId>io.edurt.lc.guice</groupId>
        <version>1.0.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>guice-binder-scope</artifactId>
    <name>Learning Center for Guice Binder(Scope)</name>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.google.inject</groupId>
            <artifactId>guice</artifactId>
            <version>4.2.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

guice: guice就是我们核心要使用的依赖

Singleton

Guice支持我们在其他DI框架中逐渐习惯的ScopeScope机制。Guice默认提供已定义依赖项的新实例。

  • src/main/java目录下新建io.edurt.lc.guice.GuiceScopeService类文件,在文件输入以下内容
代码语言:txt
复制
package io.edurt.lc.guice;

public interface GuiceScopeService
{
    void println(String input);
}
  • src/main/java目录下新建io.edurt.lc.guice.GuiceScopeServiceImpl类文件,在文件输入以下内容
代码语言:txt
复制
package io.edurt.lc.guice;

public class GuiceScopeServiceImpl
        implements GuiceScopeService
{
    @Override
    public void println(String input)
    {
        System.out.println(input);
    }
}
  • 接下来在src/test/java目录创建io.edurt.lc.guice.TestGuiceScope类文件进行定义的服务进行测试,添加以下代码
代码语言:txt
复制
package io.edurt.lc.guice;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Scopes;
import org.junit.Test;

public class TestGuiceScope
{
    @Test
    public void test()
    {
        Injector injector = Guice.createInjector(binder -> binder.bind(GuiceScopeService.class).to(GuiceScopeServiceImpl.class).in(Scopes.SINGLETON));
        GuiceScopeService service = injector.getInstance(GuiceScopeService.class);
        service.println("Singleton Scope");
    }
}

我们运行程序输出

代码语言:txt
复制
Singleton Scope

通过代码binder.bind(GuiceScopeService.class).to(GuiceScopeServiceImpl.class).in(Scopes.SINGLETON)我们指定了GuiceScopeService的Scope,他将会被标志为一个单例实例。当然我们也可以使用@Singleton标志该类的作用域

  • src/test/java目录创建GuiceScopeServiceAutoImpl类文件进行定义的服务进行测试,添加以下代码
代码语言:txt
复制
package io.edurt.lc.guice;

import com.google.inject.Singleton;

@Singleton
public class GuiceScopeServiceAutoImpl
        implements GuiceScopeService
{
    @Override
    public void println(String input)
    {
        System.out.println(input);
    }
}
  • 接下来在src/test/java目录创建io.edurt.lc.guice.TestGuiceScopeAuto类文件进行定义的服务进行测试,添加以下代码
代码语言:txt
复制
package io.edurt.lc.guice;

import com.google.inject.Guice;
import com.google.inject.Injector;
import org.junit.Test;

public class TestGuiceScopeAuto
{
    @Test
    public void test()
    {
        Injector injector = Guice.createInjector(binder -> binder.bind(GuiceScopeService.class).to(GuiceScopeServiceAutoImpl.class));
        GuiceScopeService service = injector.getInstance(GuiceScopeService.class);
        service.println("Singleton Auto Scope");
    }
}

我们运行程序输出

代码语言:txt
复制
Singleton Auto Scope

两种方式实现的效果都是一致的。此时GuiceScopeService会被构建为单例实例。

当然还有一个asEagerSingleton()方法也可以用来标记单例模式。

他们的对比图如下:

使用方式

PRODUCTION

DEVELOPMENT

.asEagerSingleton()

eager

eager

.in(Singleton.class)

eager

lazy

.in(Scopes.SINGLETON)

eager

lazy

@Singleton

eager*

lazy

自定义Scope

Guice还支持我们用户自定义作用域,通常情况下我们不需要自己实现Scope,一般内置的作用域对于大多数的应用已经足够了。如果您正在编写一个web应用程序,那么ServletModule为HTTP请求和HTTP会话提供了简单的、良好作用域实现是一个很好的想法。

  • src/main/java目录下新建io.edurt.lc.guice.annotation.GuiceCustomScope类文件,实现自定义Scope注解,在文件输入以下内容

Scope注解用于标记当前Scope在容器中使用的作用域。将使用它来注释guice构造的类型,@Provides方法和bind语法中的in()

代码语言:txt
复制
package io.edurt.lc.guice.annotation;

import com.google.inject.ScopeAnnotation;

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

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({TYPE, METHOD})
@Retention(RUNTIME)
@ScopeAnnotation
public @interface GuiceCustomScope
{
}

在使用自定义Scope时,请确保导入了正确的Scope注解。否则,您可能会得到一个SCOPE_NOT_FOUND错误。

  • src/main/java目录下新建io.edurt.lc.guice.GuiceCustomScopeImpl类文件, 在文件输入以下内容

Scope接口确保每个Scope实例拥有一到多个类型实例。

代码语言:txt
复制
package io.edurt.lc.guice;

import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;

public class GuiceCustomScopeImpl
        implements Scope
{
    ThreadLocal<Object> threadLocal = new ThreadLocal<>();

    @Override
    public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped)
    {
        return () -> {
            T instance = (T) threadLocal.get();
            if (instance == null) {
                instance = unscoped.get();
                threadLocal.set(instance);
            }
            return instance;
        };
    }
}

我们在上述代码中实现了一个简单线程抽取Scope,我们只是为了做测试使用,具体的Scope还需要根据业务自己使用。当我们传递的线程中没有构造一个对象时,先构造一个,然后放入线程上下文中,以后每次都从线程中获取对象。

  • 接下来在src/test/java目录创建io.edurt.lc.guice.TestGuiceCustomScope类文件进行定义的服务进行测试,添加以下代码
代码语言:txt
复制
package io.edurt.lc.guice;

import com.google.inject.Guice;
import com.google.inject.Injector;
import org.junit.Test;

public class TestGuiceCustomScope
{
    @Test
    public void test()
    {
        Injector injector = Guice.createInjector(binder -> {
            binder.bind(GuiceScopeService.class).to(GuiceScopeServiceImpl.class).in(new GuiceCustomScopeImpl());
        });
        for (int i = 0; i < 3; i++) {
            System.out.println(injector.getInstance(GuiceScopeService.class).hashCode());
        }
    }
}

运行程序后我们得到以下结果:

代码语言:txt
复制
508198356
508198356
508198356

我们通过结果得到运行了3次后的实例hashCode是一致的,这就说明我们的自定义Scope已经起作用了。如果新的实例构建后那么hashCode将会被改变。

  • 接下来在src/main/java目录创建io.edurt.lc.guice.GuiceCustomScopeModule类文件绑定自定义Scope注解,我们通过实现Module进行注入,添加以下代码
代码语言:txt
复制
package io.edurt.lc.guice;

import com.google.inject.AbstractModule;
import io.edurt.lc.guice.annotation.GuiceCustomScope;

public class GuiceCustomScopeModule
        extends AbstractModule
{
    @Override
    protected void configure()
    {
        bindScope(GuiceCustomScope.class, new GuiceCustomScopeImpl());
    }
}

需要使用到改Module只需要在Guice.createInjector构建的时候添加该Module即可,代码如下:

代码语言:txt
复制
Injector injector = Guice.createInjector(new GuiceCustomScopeModule(), binder -> {
    binder.bind(GuiceScopeService.class).to(GuiceScopeServiceImpl.class).in(new GuiceCustomScopeImpl());
});

ScopeService类上使用@GuiceCustomScope注解即可。

源码地址

GitHub

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基础环境
  • 初始化项目
  • Singleton
  • 自定义Scope
  • 源码地址
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档