Guice框架-DI(依赖注入细节注入)

1.3 多接口实现

1.3.1 接口多实现

如果一个接口有多个实现,这样通过@Inject和Module都难以直接实现,但是这种现象确实是存在的,于是Guice提供了其它注入方式来解决此问题。

比如下面的自定义注解。

 public interface Service {

     void execute();

 }

 public class HomeService implements Service {

     @Override

     public void execute() {

         System.out.println("home.imxylz.cn");

    }

 }

 public class WwwService implements Service {

     @Override

     public void execute() {

         System.out.println("www.teny32.blog.51cto.com");

     }

}

 @Retention(RetentionPolicy.RUNTIME)

 @Target({FIELD,PARAMETER})

 @BindingAnnotation

  public @interface Home {

  }

 @Retention(RetentionPolicy.RUNTIME)

 @Target({FIELD,PARAMETER})

 @BindingAnnotation

 public @interface Www {

 }

上面的代码描述的是一个Service服务,有WwwService和HomeService两个实现,同时有Www和Home两个注解(如果对注解各个参数不明白的需要单独去学习JAVA 5注解)。

 

好了下面请出我们的主角。

 5     package cn.imxylz.study.guice.inject.more;

 7     import com.google.inject.Binder;

 8     import com.google.inject.Guice;

 9     import com.google.inject.Inject;

10     import com.google.inject.Module;

 

16     public class MultiInterfaceServiceDemo {

17         @Inject

18         @Www

19         private Service wwwService;

20         @Inject

21         @Home

22         private Service homeService;

23         

  public static void main(String[] args) {

24             MultiInterfaceServiceDemo misd = Guice.createInjector(new Module() {

25                 @Override

26                 public void configure(Binder binder) {

binder.bind(Service.class).annotatedWith(Www.class).to(WwwService.class);

binder.bind(Service.class).annotatedWith(Home.class).to(HomeService.class);

}}).getInstance(MultiInterfaceServiceDemo.class);

31             misd.homeService.execute();

32             misd.wwwService.execute();

33         }

34     }

此类的结构是注入两个Service服务,其中wwwService是注入@Www注解关联的WwwService服务,而homeService是注入@Home注解关联的HomeService服务。

同样关于此结构我们要问几个问题。

问题(1)静态注入多个服务怎么写?

其实,参照教程02,我们可以使用下面的例子。

 1 public class StaticMultiInterfaceServiceDemo {

 2     @Inject

 3     @Www

 4     private static Service wwwService;

 5     @Inject

 6     @Home

 7     private static Service homeService;

 8     public static void main(String[] args) {

 9        Guice.createInjector(new Module() {

10             @Override

11         public void configure(Binder binder) {

binder.bind(Service.class).annotatedWith(Www.class).to(WwwService.class);

   binder.bind(Service.class).annotatedWith(Home.class).to(HomeService.class);

14          binder.requestStaticInjection(StaticMultiInterfaceServiceDemo.class);

15          }

16         });

17         StaticMultiInterfaceServiceDemo.homeService.execute();

18         StaticMultiInterfaceServiceDemo.wwwService.execute();

19     }

20 }

问题(2):如果不小心一个属性绑定了多个接口怎么办?

非常不幸,你将得到类似一下的错误,也就是说不可以绑定多个服务。

1) cn.imxylz.study.guice.inject.more.StaticMultiInterfaceServiceDemo.wwwService 

has more than one annotation annotated with 

@BindingAnnotation: 

   cn.imxylz.study.guice.inject.more.Www and cn.imxylz.study.guice.inject.more.Home

  at cn.imxylz.study.guice.inject.more.StaticMultiInterfaceServiceDemo.wwwService(StaticMultiInterfaceServiceDemo.java:17)

问题(3):我太懒了不想写注解来区分多个服务,怎么办?

程序员都是懒惰的,于是Google帮我们提供了一个Names的模板来生成注解。看下面的例子。

 1 public class NoAnnotationMultiInterfaceServiceDemo {

 2     @Inject

 3     @Named("Www")

 4     private static Service wwwService;

 5     @Inject

 6     @Named("Home")

 7     private static Service homeService;

 8     public static void main(String[] args) {

 9        Guice.createInjector(new Module() {

10             @Override

11             public void configure(Binder binder) {

binder.bind(Service.class).annotatedWith(Names.named("Www")).to(WwwService.class);

binder.bind(Service.class).annotatedWith(Names.named("Home")).to(HomeService.class);

binder.requestStaticInjection(NoAnnotationMultiInterfaceServiceDemo.class);

15             }

16         });

17         NoAnnotationMultiInterfaceServiceDemo.homeService.execute();

18         NoAnnotationMultiInterfaceServiceDemo.wwwService.execute();

19     }

20 }

上面的例子中我们使用Named来标注我们的服务应该使用什么样的注解,当然前提是我们已经将相应的服务与注解关联起来了。

 

1.3.2 Provider注入

在教程第一篇中我们提到了可以通过Provider注入一个服务,这里详细说说这种模式。

首先我们需要构造一个Provider<T>出来。

 

1     public class WwwServiceProvider implements Provider<Service> {

3         @Override

4         public Service get() {

5             return new WwwService();

6         }

7     }

 

 

 

 

上面的Provider的意思很简单,每次新建一个新的WwwService对象出来。

注入的过程看下面的代码。

 1     public class ProviderServiceDemo {

 3         @Inject

 4        private Service service;

6         public static void main(String[] args) {

 7             Injector inj=  Guice.createInjector(new Module() {

 8                 @Override

 9                 public void configure(Binder binder) {

10                   binder.bind(Service.class).toProvider(WwwServiceProvider.class);

11                 }

12             });

13             ProviderServiceDemo psd = inj.getInstance(ProviderServiceDemo.class);

14             psd.service.execute();

15         }

17     }

很显然如果这东西和线程绑定就非常好了,比如我们可以使用ThreadLocal来做线程的对象交换。

当然如果想自动注入(不使用Module手动关联)服务的话,可以使用@ProviderBy注解。

1     @ProvidedBy(WwwServiceProvider.class)

2     public interface Service {

4         void execute();

5     }

这样我们就不必使用Module将Provider绑定到Service上,获取服务就很简单了。

ProviderServiceDemo psd = Guice.createInjector().getInstance(ProviderServiceDemo.class);

psd.service.execute();

除了上述两种方式我们还可以注入Provider,而不是注入服务,比如下面的例子例子中,属性不再是Service,而是一个Provider<Service>。

 1     public class ProviderServiceDemo {

 3         @Inject

 4         private Provider<Service> provider;

 5 

 6         public static void main(String[] args) {

 7             ProviderServiceDemo psd = Guice.createInjector(new Module() {

 8                 @Override

 9                 public void configure(Binder binder) {

10                     binder.bind(Service.class).toProvider(WwwServiceProvider.class);

11                 }

12             }).getInstance(ProviderServiceDemo.class);

13             psd.provider.get().execute();

14         }

15     }

16 

17 

当然了,由于我们WwwServiceProvider每次都是构造一个新的服务出来,因此在类ProviderServiceDemo中的provider每次获取的服务也是不一样的。

1.3.3 绑定常量

看看下面的例子,演示了一个绑定整数值到实例的例子。

 

 

 1     public class ConstantInjectDemo {

 2 

 3         @Inject

 4         @Named("v")

 5         private int v;

 6         public static void main(String[] args) {

 7 

 8             ConstantInjectDemo cid = Guice.createInjector(new Module() {

 9                 @Override

10                 public void configure(Binder binder) {

11                     binder.bindConstant().annotatedWith(Names.named("v")).to(12);

12                 }

13             }).getInstance(ConstantInjectDemo.class);

14             System.out.println(cid.v);

15         }

16     }

当然,既然可以使用Named,也就可以使用自己写注解了。但是看起来好像没有多大作用。除了上述写法,也可以用下面的方式实现。

binder.bind(int.class).annotatedWith(Names.named("v")).toInstance(12);

除了可以绑定int外,在ConstantBindingBuilder类中还可以绑定其它的基本类型。

com.google.inject.binder.ConstantBindingBuilder.to(String)

com.google.inject.binder.ConstantBindingBuilder.to(long)

com.google.inject.binder.ConstantBindingBuilder.to(boolean)

com.google.inject.binder.ConstantBindingBuilder.to(double)

com.google.inject.binder.ConstantBindingBuilder.to(float)

com.google.inject.binder.ConstantBindingBuilder.to(short)

com.google.inject.binder.ConstantBindingBuilder.to(char)

1.3.4 绑定Properties

除了可以绑定基本类型外,还可以绑定一个Properties到Guice中,当然了,由于Properties本质上时一个Map<String,String>,因此Guice也允许绑定一个Map<String,String>。

 

 

 1     @Inject

 2     @Named("web")

 3     private String web;

 4 

 5     public static void main(String[] args) {

 6 

 7         ConstantInjectDemo cid = Guice.createInjector(new Module() {

 8             @Override

 9             public void configure(Binder binder) {

10                 Properties properties= new Properties();

11                 properties.setProperty("web", "www.teny32.blog.51cto.com");

12                 Names.bindProperties(binder, properties);

13             }

14         }).getInstance(ConstantInjectDemo.class);

15         System.out.println(cid.web);

16     }

17 

18

时间: 2024-10-15 01:47:13

Guice框架-DI(依赖注入细节注入)的相关文章

Guice框架-DI(依赖注入之作用域)

本章节继续讨论依赖注入的其他话题,包括作用域(scope,这里有一个与线程绑定的作用域例子).立即初始化(Eagerly Loading Bindings).运行阶段(Stage).选项注入(Optional Injection)等等.     1.3.5 Scope(作用域)   在1.1章节中我们初步了解了对象的单例模式,在Guice中提供了一些常见的作用域,比如对于单例模式有下面两个作用域.         com.google.inject.Scopes.SINGLETON      

Guice框架-DI(依赖注入基础入门)

所谓的绑定就是将一个接口绑定到具体的类中,这样客户端不用关心具体的实现,而只需要获取相应的接口完成其服务即可. HelloWorld.java      public interface HelloWorld {         String sayHello();      } 然后是具体的实现,HelloWorldImpl.java      public class HelloWorldImpl implements HelloWorld {         @Override      

Guice框架-DI(依赖注入属性注入)

1.2.1 基本属性注入 首先来看一个例子.Service.java  @ImplementedBy(ServiceImpl.class)   public interface Service {       void execute();  }   ServiceImpl.java  public class ServiceImpl implements Service {     @Override     public void execute() {         System.out

Spring DI[依赖注入]

依赖注入(Dependency Injection,简称DI)意思是由容器或者框架将被调用类注入给调用对象,以此来降低调用对象和被调用类之间的依赖关系. 依赖注入主要有2种不同的实现形式: 1. 构造函数注入(Constructor Injection) 2. 设值注入(Setter Injection) 1.构造函数注入 通过调用类的构造函数,并将被调用类当做参数传递给构造函数,以此实现注入. example: public class UserImpl implements UserDao

phalapi-进阶篇2(DI依赖注入和单例模式)

phalapi-进阶篇2(DI依赖注入和单例模式) 前言 先在这里感谢phalapi框架创始人@dogstar,为我们提供了这样一个优秀的开源框架. 离上一次更新过去了快两周,在其中编写了一个关于DB分表分库解决大数据量的拓展,有兴趣的童鞋可以了解了解.废话不多说,本小节在于解释一下在PhalApi框架中两个比较好的思想,单例模式和依赖注入. 附上: 官网地址:http://www.phalapi.net/ 开源中国Git地址:http://git.oschina.net/dogstar/Pha

持久化框架一定能防止SQL注入?

问题描述 持久化框架一定能防止SQL注入吗?用了持久化框架,但是安全扫描的时候还是有SQL注入和盲注的安全漏洞. 解决方案 解决方案二:持久化框架用的什么?安全扫描用的什么工具?解决方案三: 解决方案四:引用1楼testcs_dn的回复: 持久化框架用的什么?安全扫描用的什么工具? 不是说持久化框架能防止么,用的APPSCAN扫描的解决方案五:不能彻底防止,防止SQL的关键是要注意不能将输入参数随意拼入SQL,当然包括其它形式的SQL变形,如HQL.解决方案六:不能,还得看你自己怎么写程序解决方

php通用防注入与注入详细说明

还有服务器和mysql教程也要加强一些安全防范. 对于linux服务器的安全设置: 加密口令,使用"/usr/sbin/authconfig"工具打开密码的shadow功能,对password进行加密. 禁止访问重要文件,进入linux命令界面,在提示符下输入: #chmod 600 /etc/inetd.conf    //改变文件属性为600 #chattr +i  /etc/inetd.conf     //保证文件属主为root #chattr –i  /etc/inetd.c

FIS源码-fis release增量编译与依赖扫描细节

开篇 前面已经提到了fis release命令大致的运行流程.本文会进一步讲解增量编译以及依赖扫描的一些细节. 首先,在fis release后加上--watch参数,看下会有什么样的变化.打开命令行 fis release --watch 不难猜想,内部同样是调用release()方法把源文件编译一遍.区别在于,进程会监听项目路径下源文件的变化,一旦出现文件(夹)的增.删.改,则重新调用release()进行增量编译. 并且,如果资源之间存在依赖关系(比如资源内嵌),那么一些情况下,被依赖资源

java框架spring依赖注入的6种方式

spring中如何给对象的属性复制? 1)通过构造方法2)通过set方法给属性注入值3)p命名空间4)自动转配(了解即可,不推荐使用)5)注解6)通过接口 准备工作(模拟业务方法)Action-->service-->dao 1)UserDao:     p<span style="font-family:Courier New;">ublic class UserDao {           public void save(){