guice依赖注入原理和使用简介

添加链接描述

添加链接描述

**Guice:**整个框架的门面
Injector:一个依赖的管理上下文
创建一个injector
1、获取injector
2、injector.injectMembers(this);
3、创建一个Injector可以使用多个任意多个Module
4、实例创建injector.getInstance(FooStarter.class);

Binder:一个接口和实现的绑定
Module:一组Binder
Provider:bean的提供者
Key:Binder中对应一个Provider
Scope:Provider的作用域
Stage:运行方式(为了不同的要求)

Module

(重载Configure方法实现接口和实现类的绑定 ,告诉guice发现对接口的依赖时,应该调用哪个实现类)
自定义module extends AbstractModule,重写configure方法

 @Override
    protected void configure() {
        bind(Environment.class).toInstance(getEnvironment());
        bind(org.apache.commons.configuration2.Configuration.class).toInstance(getApacheConfig());
        bind(Configuration.class).toInstance(getConfiguration());
    }

由此也可以看出@Inject 和 bind是一起出现的

Module之间的关系

1、并列:默认顺序传递就是此关系

Guice.createInjector(new MainModule(), .......);

2、嵌套:大的Module可以嵌套任意多个子Module

public class ServerModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new MainModule());
    }
}

3、 覆盖:如果有冲突的话后者覆盖前者,没有的话就都生效
// 用后者覆盖前者

Module finalModule = Modules.override(new MainModule()).with(new ServerModule()); 

绑定

告诉guice接口的实现类是哪个,任何需要依赖注入的资源,只有先实现了绑定才能注入
绑定的几种方式
1、类名绑定:把实现类绑定到接口,具体实例交给框架去帮你创建

bind(Animal.class).to(Dog.class);

2、实例绑定:绑定一个现有实例

bind(Animal.class).toInstance(new Dog())

注意:采用这种绑定,依赖注入时永远是单例(也就是这个实例)

3、连接绑定:对于已经绑定了的关系,可以无限一直连接下去

bind(Animal.class).to(Dog.class);
bind(Dog.class).toInstance(new Dog(){
    @Override
    public void run() {
        System.out.println("son dog");
        super.run();
    }
});

4、Provider绑定:类似于Spring的@Bean注解,适合完成需要编程逻辑完成的实例

 bind(EventService.class).toProvider(new Provider<EventService>(){    
    @Override    
    public EventService get(){        
       return new SpringEventService();    
    }
});

5、泛型绑定:支持泛型类型的绑定。借助TypeLiteral来完成

bind(new TypeLiteral<List<Animal>>(){}).toInstance(Arrays.asList(new Dog(),new Cat()));

6、集合绑定:可在不同的Module内向同一个集合分别去绑定自己所要支持的内容,当然喽也可以在同一个Module内

Multibinder<Animal> multibinder = Multibinder.newSetBinder(binder(), Animal.class);
multibinder.addBinding().toInstance(new Dog());
multibinder.addBinding().toInstance(new Cat());  
说明:依赖于扩展包guice-multibindings,需要导入这个jar才行

7、bind(EventService.class).toConstructor((Constructor)SpringEventService.class.getConstructors()[0]);

如何保证单例?
1、使用@Singleton注解

@Singleton
public class Dog implements Animal { ... }

说明:该注解只能标注在实现类上,不能标注在接口/抽象类上

2、在provider上用@Singleton注解

@Provides
    @Singleton
    public PushService providePushService() {
        return new PushServiceStub();
    }

3、绑定时指定单例

bind(Animal.class).to(Dog.class).in(Singleton.class);

或者

bind(SpringEventService.class).asEagerSingleton();

4、绑定一个现存的实例

bind(Animal.class).toInstance(new Dog());

以上三种方式处理后,使用依赖注入或者用API injector.getInstance()得到的均会是同一个实例对象,这就是单例了。

@ImplementedBy 与 @ProvidedBy

如果不想使用Module手动关联服务的话,可以使用这两个注解
@ImplementedB:注解用于简化绑定配置,通常用于指定默认的实现类型。最常用的场景在于编写 Dao 或者 Service 时,指定 Interface 的实现类

@ImplementedBy(Dog.class)

// @Singleton // 不能标记在接口上,只能标记在Dog实现类上

public interface Animal {
    void run();
}

效果同

bind(Animal.class).to(Dog.class)

@ProvidedBy 
@ProvidedBy(OneServiceProvider.class)
public interface Service {
    public void execute();
}

public class ProviderServiceDemo2 {
    public static void main(String[] args) {
        ProviderServiceDemo2 instance = Guice.createInjector().getInstance(ProviderServiceDemo2.class);
        // instance.service.execute(); //发现不起作用不知何解 ?
    }
}

效果同

bind(Animal.class).toProvider(DogProvider.class)

注入

1、简单注入(接口仅有一个实现类)

@Inject
private GuiDomainParser parser;

2、provider注入

@Inject 
private Provider<Animal> animal; 

或者

@Provides // 作用类似于@Bean 
@Singleton // 若这里不使用该注解,那就是多例,每次都会执行此方法
 private Animal getAnimal(){ 
   return new Dog();
 } 

注意:使用了@Provides方式配置了实例,那么向bind(Animal.class).toInstance(new Dog())这句话就不能再要了,否则就是重复绑定,启动时会抛错:

3、命名注入:用于对同一接口多个实现类做区分注入
(自定义注解方式)

bind(Animal.class).annotatedWith(DogAnno.class).to(Dog.class);
bind(Animal.class).annotatedWith(CatAnno.class).to(Cat.class);

@Inject
@DogAnno
private Animal animal;

(@named注解方式)

bind(ClassFinder.class)
                .annotatedWith(Names.named("ByPackageScan"))
                .to(ScanPackageClassFinder.class)
                .in(Singleton.class);

使用如下方式注入

@Inject
	@Named("ByPackageScan")
	private ClassFinder classFinder;

除了自定义注解,你还可以使用Guice自带的命令类:Names.named(“dog”)(它返丝线了注解接口,所以返回值是个注解类型)

@Inject的optional默认为false,注入时如果依赖不存在,则报错停止,当使用@Inject(optional = true)时可达到忽然依赖是否存在的效果

Injector 继承
一个Injector中如果包含了多个Module,各Module中的是可以相互使用的,也就是可以相互依赖
如果一个Injector想依赖另一个Injector中的实例,那就要通过继承了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值