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

简介:

本章节继续讨论依赖注入的其他话题,包括作用域(scope,这里有一个与线程绑定的作用域例子)、立即初始化(Eagerly Loading Bindings)、运行阶段(Stage)、选项注入(Optional Injection)等等。

 

 

1.3.5 Scope(作用域)

 

在1.1章节中我们初步了解了对象的单例模式,在Guice中提供了一些常见的作用域,比如对于单例模式有下面两个作用域。

 

 

    com.google.inject.Scopes.SINGLETON

 

    com.google.inject.Scopes.NO_SCOPE

 

在使用上,可以使用Module的bind来实现,看下面的例子。

 

 

 1     public class ScopeDemo {

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

 3 

 4             Service service = Guice.createInjector(new Module() {

 5                 @Override

 6                 public void configure(Binder binder) {

 7                     binder.bind(Service.class).to(WwwService.class).in(Scopes.SINGLETON);

 8                 }

 9             }).getInstance(Service.class);

10             service.execute();

11         }

12     }

13 

14 

当然单例模式还可以似乎用@Singleton注解。

 

 

在com.google.inject.binder.ScopedBindingBuilder.in(Scope)方法中,一个Scope除了可以使上面的SINGLETION和NO_SCOPE外,还可以是自己定义的Scope。下面的例子演示了一个与线程绑定的Scope例子。

 

 1 /**

 2  * $Id: ThreadScopeDemo.java 90 2009-12-25 08:12:21Z xylz $

 3  * xylz study project (www.imxylz.cn)

 4  */

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

 6 

 7 import com.google.inject.Binder;

 8 import com.google.inject.Guice;

 9 import com.google.inject.Injector;

10 import com.google.inject.Key;

11 import com.google.inject.Module;

12 import com.google.inject.Provider;

13 import com.google.inject.Scope;

14 

15 /** a demo with thread-scope

16  * @author xylz (www.imxylz.cn)

17  * @version $Rev: 90 $

18  */

19 public class ThreadScopeDemo {

20 

21     static class ThreadServiceScope implements Scope {

22 

23         static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();

24 

25         @Override

26         public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {

27             return new Provider<T>() {

28                 @Override

29                 public T get() {

30                     T instance = (T) threadLocal.get();

31                     if (instance == null) {

32                         instance = unscoped.get();

33                         threadLocal.set(instance);

34                     }

35                     return instance;

36                 }

37             };

38         }

39 

40         @Override

41         public String toString() {

42             return "Scopes.ThreadServiceScope";

43         }

44     }

45     

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

47         final Injector inj=Guice.createInjector(new Module() {

48             @Override

49             public void configure(Binder binder) {

50                 binder.bind(Service.class).to(WwwService.class).in(new ThreadServiceScope());

51             }

52         });

53         for(int i=0;i<3;i++) {

54             new Thread("Thread-"+i) {

55                 public void run() {

56                     for(int m=0;m<3;m++) {

57                         System.out.println(String.format("%s-%d:%d",//

58                                 getName()//

59                                 ,m//

60                                 ,inj.getInstance(Service.class).hashCode()));

61                         try {

62                             Thread.sleep(50L);

63                         } catch (Exception e) {

64                         }

65                     }

66                 }

67             }.start();

68         }

69     }

70 }

71

 

注意,这里用到了《Google Guice 入门教程03 - 依赖注入》的中的两个类Service和WwwService。在本例中ThreadServiceScope类是一个与线程绑定的作用域(利用ThreadLocal特性),当当前线程中没有构造一个对象的时候先构造一个出来,然后放入线程上下文中,以后每次都从线程中获取对象。第50行是将WwwService服务以ThreadServiceScope的作用域绑定到Service服务上。第57-60行输出当前对象的hashCode,如果此类是同一对象的话就应该输出相同的hashCode。为了看到效果,我们使用3个线程,每个线程输出三次来看结果。

 

Thread-0-0:18303751

Thread-1-0:23473608

Thread-2-0:21480956

Thread-1-1:23473608

Thread-0-1:18303751

Thread-2-1:21480956

Thread-1-2:23473608

Thread-2-2:21480956

Thread-0-2:18303751

 

我们看到对于同一个线程(比如说Thread-0)的三次都输出了相同的对象(hashCode为18303751),而与线程2和线程3的hashCode不同。

 

(特别说明:如果两个线程输出了同一个hashCode不必惊慌,那是因为可能前一个线程生成的对象的地址空间被GC释放了,结果下一个线程使用了上一个线程的相同空间,所以这里使用Thread.sleep来降低这种可能性)

 

 

事实上在guice-servlet-2.0.jar中有与request和session绑定的scope。

 

com.google.inject.servlet.ServletScopes.REQUEST

com.google.inject.servlet.ServletScopes.SESSION

 

1.3.6 Eagerly Loading Bindings (立即初始化)

 

 

除了可以绑定scope外,对象默认在第一次调用时被创建,也即所谓的延时加载,Guice也允许对象在注入到Guice容器中时就被创建出来(显然这是针对单例模式才有效)。

 

 1 public class EagerSingletonDemo {

 2 

 3     public EagerSingletonDemo() {

 4         System.out.println(" constuctor:"+System.nanoTime());

 5     }

 6     void doit() {

 7         System.out.println("       doit:"+System.nanoTime());

 8     }

 9     public static void main(String[] args) throws Exception{

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

11             @Override

12             public void configure(Binder binder) {

13                 binder.bind(EagerSingletonDemo.class).asEagerSingleton();

14             }

15         });

16         System.out.println("before call:"+System.nanoTime());

17         Thread.sleep(100L);

18         inj.getInstance(EagerSingletonDemo.class).doit();

19     }

20 }

 

结果输出如下:

 

 constuctor:26996967388652

before call:26996967713635

       doit:26997069993702

 

可以看到我们的对象在调用getInstance之前就已经被构造出来了。

 

 

1.3.7 Stages (运行阶段)

 

Guice还有一个特效,可以指定Guice运行模式来控制Guice的加载速度。在com.google.inject.Stage枚举中提供了TOOL,DEVELOPMENT,PRODUCTION三种模式。

 

TOOL描述的是带有IDE等插件的运行模式;DEVELOPMENT是指在开发阶段只加载自己需要的功能(对于非立即初始化单例对象采用延后加载),这样来降低加载不需要功能的时间;而PRODUCTION模式是指完全加载所有功能(对于单例对象采用立即加载方式),这样可以更早的发现问题,免得等需要某些功能的时候才发现问题(要知道我们某些功能可能需要特定的条件才能触发)。

 

其实只有比较多的单例对象,并且单例对象构造比较耗时的情况下才能有用。大部分情况下这点性能可能都忽略不计了。

 

 

默认情况下Guice采用DEVELOPMENT模式。

 

 

 

 

 

1.3.8 Optional Injection (选项注入 )

 

选项注入描述的是如果不能从Guice容器中注入一个对象,那么可以使用一个默认的对象。看下面的例子。

 

 

 1 public class OptionalInjectionDemo {

 2     @Inject(optional=true)

 3     Service service = new WwwService();

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

 5         Guice.createInjector(new Module() {

 6             public void configure(Binder binder) {

 7                 //binder.bind(Service.class).to(HomeService.class);

 8             }

 9         }).getInstance(OptionalInjectionDemo.class).service.execute();

10     }

11 }

 

上述例子中第2行描述的是选项注入,如果不能从Guice容器中获取一个Service服务那么就使用默认的WwwService,否则就是用获取的服务。如果将第7行注释去掉我们就可以看到实际上调用的是HomeService服务了。

相关文章
|
测试技术 Linux API
mutagen-处理音频元数据的Python模块
Mutagen是处理音频元数据的Python模块。它支持ASF,FLAC,MP4,Monkey's Audio,MP3,Musepack,Ogg Opus,Ogg FLAC,Ogg Speex,Ogg Theora,Ogg Vorbis,True Audio,WavPack,OptimFROG和AIFF音频文件。支持所有版本的ID3v2,并解析所有标准的ID3v2.4帧。它可以读取Xing标头,以准确计算MP3的比特率和长度。无论音频格式如何,都可以编辑ID3和APEv2标签。它还可以在单个数据包/页面级别上处理Ogg流。
2829 0
mutagen-处理音频元数据的Python模块
|
JavaScript 容器
vue-element-admin 综合开发二:搭建首页架子、侧边栏、修改默认样式、menu和路由跳转页面初体验
这篇文章详细介绍了如何使用Vue和Element UI搭建一个后台管理系统,包括首页布局、侧边栏、样式调整、菜单和路由配置,以及解决开发中遇到的问题。
1248 1
vue-element-admin 综合开发二:搭建首页架子、侧边栏、修改默认样式、menu和路由跳转页面初体验
|
存储 负载均衡 监控
何为微服务、网关、服务发现/注册?
随着互联网业务复杂性慢慢提高,单机服务的架构慢慢出现了生产效率问题 微服务架构带来的有优点也有缺点,使用前需要调研清楚 微服务架构的网关设计、服务注册/发现、配置管理都是关键点
何为微服务、网关、服务发现/注册?
|
JavaScript 前端开发 数据可视化
Three.js第2篇,加载glb / gltf模型,Vue加载glb / gltf模型(如何在vue中使用three.js,vue使用threejs加载glb模型)
Three.js 是一个用于在 Web 上创建和显示 3D 图形的 JavaScript 库。它提供了丰富的功能和灵活的 API,使开发者可以轻松地在网页中创建各种 3D 场景、模型和动画效果。可以用来展示产品模型、建立交互式场景、游戏开发、数据可视化、教育和培训等等。这里记录一下如何在Vue项目中使用Three.js
3870 4
Three.js第2篇,加载glb / gltf模型,Vue加载glb / gltf模型(如何在vue中使用three.js,vue使用threejs加载glb模型)
|
存储 算法 Linux
Linux中的硬链接与软链接:原理、应用与最佳实践
Linux中的硬链接与软链接:原理、应用与最佳实践
865 0
|
存储 人工智能 前端开发
Web3.0前端工程师需要具备哪些技术?
最近,Web3.0的声音越来越大,越来越疯狂,对于我们的前端,我们需要具备哪些技术?
Web3.0前端工程师需要具备哪些技术?
|
Python
如何用Python发送通知到微信?
大家好,我是志斌~ 常见的通知方式有:邮件,电话,短信,微信。短信和电话:通常是收费的,较少使用;邮件:适合带文件类型的通知,较正式,存档使用;微信:适合告警类型通知,较方便。这里说的微信,是企业微信。
615 0
如何用Python发送通知到微信?
|
消息中间件 JavaScript 前端开发
基于Springboot+SpringCloud+Vue+Redis+Es的牛逼商城系统
该项目用到的技术非常的多,非常的适合学习,用到的技术有Springboot、SpringCloud、Vue、Redis、Es、MyCat、Nginx、RabbitMQ,如果用于学习应该是非常的全面,如果是用于找工作,可以直接吊打面试官。本系统的资料,包括源码,讲义,视频,资料全部开源。
591 1
基于Springboot+SpringCloud+Vue+Redis+Es的牛逼商城系统
|
Web App开发 编解码 前端开发
vue 接入腾讯实时音视频 trtc-js-sdk 的技术难点与解决方案
1.低延迟,如果要满足比较流畅地进行实时互动,那么单向的端到端的迟延大概要在 400 毫秒以下才能保证流畅沟通; 2.流畅性,你也很难想象在视频过程中频繁卡顿会有良好的互动; 3.回声消除,回声的产生是扬声器播放的声音经过环境反射被麦克风重新采集并传输给对方,这样对方就会一直听到自己的回声,整个互动过程会非常难受; 4.国内外互通,随着现在国内同质化产品越来越多,国内的竞争也异常激烈,很多厂商纷纷选择出海,这时就需要做好海内外的互通; 5.海量并发,当然这不仅仅指实时音视频了,基本对于任何一款互联网产品而言都是必须要考虑的难点。
1247 0