使用guice进行依赖注入与模块化系统

一、Guice介绍
1,Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC)。Guice非常小而且快。Guice是类型安全的,它能够对构造函数,属性,方法(包含任意个参数的任意方法,而不仅仅是setter方法)进行注入。
2,elasticsearch是直接把guice的源码放到自己的包内(es把很多开源项目的代码都直接集成到自己项目中,省得依赖一堆的jar包,也使es的jar包达到差不多10M),在org.elasticsearch.common.inject目录下。

二、Module依赖注册
Guice提供依赖配置类,需要继承至AbstractModule,实现configure方法。在configure方法中我们可以用Binder配置依赖。

Binder利用链式形成一套独具语义的DSL,如:

基本配置: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]);
运行时注入:利用@Provides标注注入方法,相当于spring的@Bean。
@ImplementedBy:或者在实现接口之上标注@ImplementedBy指定其实现类。这种方式有点反OO设计,抽象不该知道其实现类。

三、如何使用Guice进行依赖注入

public interface WatchVideoService {

    public void buyVip();

}
public interface SearchService {

    public void printSource();
}
import com.google.inject.Inject;
import com.sohu.search.guice.service.SearchService;
import com.sohu.search.guice.service.WatchVideoService;

/**
 * Created by jiangtao on 17-6-19.
 */
public class MobileSearchServiceImpl implements SearchService {


    private WatchVideoService watchVideoService;

    //使用@inject guice会扫描inject注释,并对方法中出现的参数实例寻找对应注册的实例进行初始化。
    @Inject
    public MobileSearchServiceImpl(WatchVideoService watchVideoService){
        this.watchVideoService = watchVideoService;
    }


    @Override
    public void printSource() {
        watchVideoService.buyVip();
        System.out.println("移动端不出UGC视频");
    }
}

import javax.inject.Inject;

/**
 * Created by jiangtao on 17-6-19.
 */
public class PCSearchServiceImpl implements SearchService {



    private WatchVideoService watchVideoService;

    /**
     * 使用@inject  guice会扫描inject注释,并对方法中出现的参数实例寻找对应注册的实例进行初始化。
     * @param watchVideoService
     */
    @Inject
    public PCSearchServiceImpl(WatchVideoService watchVideoService){
        this.watchVideoService = watchVideoService;
    }

    @Override
    public void printSource() {
        watchVideoService.buyVip();
        System.out.println("pc端出ugc视频");
    }
}

/**
 * Created by jiangtao on 17-6-20.
 */
public class WatchVideoServiceImpl implements WatchVideoService {

    @Override
    public void buyVip() {
        System.out.println("请购买会员,再观看视频");
    }

}
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Provides;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import com.sohu.search.guice.service.SearchService;
import com.sohu.search.guice.service.WatchVideoService;
import com.sohu.search.guice.service.impl.MobileSearchServiceImpl;
import com.sohu.search.guice.service.impl.PCSearchServiceImpl;
import com.sohu.search.guice.service.impl.WatchVideoServiceImpl;

import java.util.List;

import static com.google.common.collect.ImmutableList.of;

/**
 * Created by jiangtao on 17-6-19.
 */
public class SearchModule extends AbstractModule {


    /**
     * 每个module里面都有一个方法configure()用于将对象和实现类作绑定
     * Module(模块)是Guice用来管理一组绑定关系的地方。
     * 自定义模块需要继承AbstractModule类并覆盖configure方法,在configure方法中设置绑定关系。
     * Guice创建时可使用多个模块,则注入器可以注入多个模块中指定的绑定关系。
     */
    @Override
    protected void configure() {
        final Binder binder = binder();
        /**
         * 一个接口多个实现。
         */
        binder.bind(SearchService.class).annotatedWith(Names.named("pcSearch")).to(PCSearchServiceImpl.class);
        binder.bind(SearchService.class).annotatedWith(Names.named("mobileSearch")).to(MobileSearchServiceImpl.class);
        /**
         * 一个接口只有一个实现。
         * bind接口将接口跟具体实现类绑定。
         */

        //使用asEagerSingleton方法,强制Guice立即实例化类并注入:饿汉模式。
        binder.bind(WatchVideoService.class).to(WatchVideoServiceImpl.class).asEagerSingleton();
    }


    /**
     * @Provides标注注入方法来运行时注入
     * @param pcService
     * @param mobileService
     * @return
     */
    @Provides
    public SearchService getSearchService(@Named("pcSearch") SearchService pcService,
                                                  @Named("mobileSearch") SearchService mobileService) {

        if(Math.random()*10 > 5){
            return pcService;
        }
        return mobileService;
    }

}
/**
 * Created by jiangtao on 17-6-19.
 */
public class SearchModuleTest {

    private Injector injector;

   //使用 Injector 引导应用程序。
    @Before
    public void setUp() throws Exception {
        injector = Guice.createInjector(new SearchModule());
    }


    @Test
    public void print() throws Exception {

        final SearchService pcService = injector.getInstance(PCSearchServiceImpl.class);

        pcService.printSource();

        /**
         *
         */
        final SearchService mobileService = injector.getInstance(MobileSearchServiceImpl.class);

        mobileService.printSource();

        /**
         * 使用@provides进行动态注入
         */
        final SearchService searchService = injector.getInstance(new Key(){});

        searchService.printSource();
    }


    /**
     * 是否为单例
     * result:为单例
     * @throws Exception
     */
    @Test
    public void should_be_singleton_for_one_without_interface_bean() throws Exception {
        //when
        final WatchVideoService first = injector.getInstance(WatchVideoService.class);
        final WatchVideoService second = injector.getInstance(WatchVideoService.class);
        //then
        assertThat(first, is(sameInstance(second)));
    }
}

四、参考文档:
1,https://www.ibm.com/developerworks/cn/java/j-guice.html (ibm关于guice 2.0讲解)
2,https://github.com/google/guice/wiki/GettingStarted (guice官方wiki)

你可能感兴趣的:(使用guice进行依赖注入与模块化系统)