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.println("This is made by Teny (www.teny32.blog.51cto.com).");

    }

}

FieldInjectDemo.java

 5 public class FieldInjectDemo {

 6     @Inject

 7     private Service servcie;

 8     public Service getServcie() {

 9         return servcie;

10     }

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

12         FieldInjectDemo demo = Guice.createInjector().getInstance(FieldInjectDemo.class);

13         demo.getServcie().execute();

14     }

15 }

这个例子比较简单。具体来说就是将接口Service通过@Inject注解注入到FieldInjectDemo类中,然后再FieldInjectDemo类中使用此服务而已。当然Service服务已经通过@ImplementedBy注解关联到ServiceImpl 类中,每次生成一个新的实例(非单例)。注意,这里FieldInjectDemo类没有通过Module等关联到Guice中,具体可以查看《》。

意料之中得到了我们期待的结果。

 

同样,我们通过问答的方式来加深理解(注意,入门教程我们只是强调怎么使用,至于原理和底层的思想我们放到高级教程中再谈)。

问题(1):可以自己构造FieldInjectDemo 对象而不通过Guice么?

 1 /** field inject demo2

 2  * @author Teny (www.teny32.blog.51cto.com)

 3  * @version $Rev: 73 $

 4  */

 5 public class FieldInjectDemo2 {

 6     @Inject

 7     private Service servcie;

 8     public Service getServcie() {

 9         return servcie;

10     }

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

12         FieldInjectDemo2 fd = new FieldInjectDemo2();

13         fd.getServcie().execute();

14     }

15 }

就像上面的例子中一样,然后运行下看看?非常不幸,我们得到了一个谁都不喜欢的结果。

Exception in thread "main" java.lang.NullPointerException

    at cn.imxylz.study.guice.inject.FieldInjectDemo2.main(FieldInjectDemo2.java:22)

很显然,由于FieldInjectDemo2不属于Guice容器(暂且称为容器吧)托管,这样Service服务没有机会被注入到FieldInjectDemo2类中。

 

问题(2):可以注入静态属性么?

 

看下面的代码。

 1 public class FieldInjectDemo2 {

 2     @Inject

 3     private static Service servcie;

 4     public static Service getServcie() {

 5         return servcie;

 6     }

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

 8         FieldInjectDemo2 fd = Guice.createInjector().getInstance(FieldInjectDemo2.class);

 9         FieldInjectDemo2.getServcie().execute();

10     }

11 }

很不幸!运行结果告诉我们Guice看起来还不支持静态字段注入。

好了,上面两个问题我们暂且放下,我们继续学习其它注入功能。

1.2.2 构造函数注入(Constructor Inject)

继续看例子。例子是说明问题的很好方式。

 1     /**

 2      * $Id: ConstructorInjectDemo.java 75 2009-12-23 14:22:35Z xylz $

 3      * xylz study project (www.teny32.blog.51cto.com)

 4      */

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

 6 

 7     import com.google.inject.Guice;

 8     import com.google.inject.Inject;

 9 

10     /** a demo with constructor inject

11      * @author Teny(www.teny32.blog.51cto.com)

12      * @version $Rev: 75 $

13      */

14     public class ConstructorInjectDemo {

15 

16         private Service service;

17         @Inject

18         public ConstructorInjectDemo(Service service) {

19             this.service=service;

20         }

21         public Service getService() {

22             return service;

23         }

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

25             ConstructorInjectDemo cid = Guice.createInjector().getInstance(ConstructorInjectDemo.class);

26             cid.getService().execute();

27         }

28 

29     }

30 

31 

我们在构造函数上添加@Inject来达到自动注入的目的。构造函数注入的好处是可以保证只有一个地方来完成属性注入,这样可以确保在构造函数中完成一些初始化工作(尽管不推荐这么做)。当然构造函数注入的缺点是类的实例化与参数绑定了,限制了实例化类的方式。

 

问题(3):构造函数中可以自动注入多个参数么?

 1     public class ConstructorInjectDemo {

 3         private Service service;

 4         private HelloWorld helloWorld;

 5         @Inject

 6         public ConstructorInjectDemo(Service service,HelloWorld helloWorld) {

 7             this.service=service;

 8             this.helloWorld=helloWorld;

 9         }

10         public Service getService() {

11             return service;

12         }

13         public HelloWorld getHelloWorld() {

14             return helloWorld;

15         }

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

17             ConstructorInjectDemo cid = Guice.createInjector().getInstance(ConstructorInjectDemo.class);

18             cid.getService().execute();

19             System.out.println(cid.getHelloWorld().sayHello());

20         }

21     }

22 

23 

非常完美的支持了多参数构造函数注入。当然了没有必要写多个@Inject,而且写了的话不能通过编译。

1.2.3 Setter注入(Setter Method Inject)

有了上面的基础我们再来看Setter注入就非常简单了,只不过在setter方法上增加一个@Inject注解而已。

 

 

 1     public class SetterInjectDemo {

 2 

 3         private Service service;

 4 

 5         @Inject

 6         public void setService(Service service) {

 7             this.service = service;

 8         }

 9 

10         public Service getService() {

11             return service;

12         }

13 

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

15             SetterInjectDemo sid = Guice.createInjector().getInstance(SetterInjectDemo.class);

16             sid.getService().execute();

17         }

18 

19     }

20 

好了我们再回头看问题2的静态注入(static inject)。下面的例子演示了如何注入一个静态的字段。

 

 1     /** a demo for static field inject

 2      * @author Teny (www.teny32.blog.51cto.com)

 3      * @version $Rev: 78 $

 4      */

 5     public class StaticFieldInjectDemo {

 6 

 7         @Inject

 8         private static Service service;

 9 

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

11             Guice.createInjector(new Module() {

12                 @Override

13                 public void configure(Binder binder) {

14                     binder.requestStaticInjection(StaticFieldInjectDemo.class);

15                 }

16             });

17             StaticFieldInjectDemo.service.execute();

18         }

19     }

20 

21 

非常棒!上面我们并没有使用Guice获取一个StaticFieldInjectDemo实例(废话),实际上static字段(属性)是类相关的,因此我们需要请求静态注入服务。但是一个好处是在外面看起来我们的服务没有Guice绑定,甚至client不知道(或者不关心)服务的注入过程。

 

再回到问题(1),参考上面静态注入的过程,我们可以使用下面的方式来注入实例变量的属性。

 

 

 1     public class InstanceFieldInjectDemo {

 2 

 3         @Inject

 4         private Service service;

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

 6            final InstanceFieldInjectDemo ifid = new InstanceFieldInjectDemo();

 7             Guice.createInjector(new Module() {

 8                 @Override

 9                 public void configure(Binder binder) {

10                     binder.requestInjection(ifid);

11                 }

12             });

13             ifid.service.execute();

14         }

15     }

16 

17 

实际上这里有一种简便的方法来注入字段,实际上此方法也支持Setter注入。

 

 

 1     public class InstanceFieldInjectDemo {

 2 

 3         @Inject

 4         private Service service;

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

 6             InstanceFieldInjectDemo ifid = new InstanceFieldInjectDemo();

 7             Guice.createInjector().injectMembers(ifid);

 8             ifid.service.execute();

 9         }

10     }

11 

12

相关文章
|
监控 Java
如何使用VisualVM分析内存泄漏?具体流程看这里
如何使用VisualVM分析内存泄漏?具体流程看这里
1675 1
|
SQL 资源调度 数据库
数仓学习---14、大数据技术之DolphinScheduler
数仓学习---14、大数据技术之DolphinScheduler
支付宝 - 支付宝怎么解除自动续费?
支付宝 - 支付宝怎么解除自动续费?
6415 1
支付宝 - 支付宝怎么解除自动续费?
|
2月前
|
JavaScript 安全 Java
基于springboot的大学生心理咨询管理系统
本研究针对大学生心理健康问题,构建基于Spring Boot、Vue等技术的心理咨询管理系统,实现心理数据电子化、智能化管理。系统支持在线预约、匿名咨询、心理测评与数据分析,兼具隐私保护与危机预警功能,提升服务可及性与干预精准度,助力高校心理健康工作科学化发展。
|
4月前
|
API vr&ar 索引
1张照片 2秒钟 一键变身3D数字人
LHM是一种基于单视角图像的端到端Transformer模型,结合SMPL-X人体模型与高斯渲染技术,可从一张照片生成可驱动的3D数字人。它采用Vision Transformer和Mae模型提取特征,并通过Body-Head Transformer融合2D与3D信息,输出具有动作能力的高精度3D人体模型。应用于动作重现、游戏角色生成及虚拟现实等领域,代码已开源并提供在线体验入口。
535 1
|
存储 数据采集 JSON
彻底搞懂监控系统,使用Prometheus +Grafana搭建完整的应用监控系统
监控是运维系统的基础,我们衡量一个公司/部门的运维水平,看他们的监控系统就可以了。一个完善的监控系统可以提高应用的可用性和可靠性,在提供更优质服务的前提下,降低运维的投入和工作量,为用户带来更多的商业利益和客户体验。下面就带大家彻底搞懂监控系统,使用Prometheus +Grafana搭建完整的应用监控系统。
16244 1
彻底搞懂监控系统,使用Prometheus +Grafana搭建完整的应用监控系统
|
Ubuntu 网络协议 关系型数据库
|
缓存 监控 安全
有哪些搭建代理服务器的好方法?--代理IP小课堂
今天我们就来说一说,要如何搭建代理服务器,以此来帮助你快速入门代理服务器的搭建和使用。
|
存储 关系型数据库 应用服务中间件
私有云盘:lamp部署nextcloud+高可用集群
lamp部署nextcloud+高可用集群,配置mariadb主从复制,台主机下载mariadb,配置nfs让web服务挂载,web 服务器 配置 lamp,配置nginx反向代理&&haproxy&&keepalived。
843 0