对于guice,经过前文的叙述,应该有了相对清晰的了解guice,那么我们归根到底技术还是要结合业务的,因此,与时下流行的springboot进行协作处理,加深理解。开始,spring与guice的出发点是一样的,但是后来spring逐渐形成一个技术栈,但他们并不冲突。不慌。
回顾一下springboot rest Controller
springboot这套东西呢,用来监听网络端口,起一个servlet,将自己注册进去等等网络相关的事情,然后把网络上的responses 放到我们java具体的类中,map下来之后,我们通过一系列框架或自己的方法来搭建业务逻辑,本文利用guice来搭建业务逻辑,将这些业务逻辑当作一个模块,inject到springboot框架去中,当然只是业务逻辑的入口,暴露给控制层。
当然,我们利用spring的Jpa来处理Dao数据,并包装成guice的一个依赖注入到我们业务逻辑的框架中。整体如下:
springboot官网复制一套快速helloworld,guice部分pom复制 学习(一) 的内容.
在本章中,我想要的是将简单的helloworld来阐述guice与spring的整合,以及有关作用域的问题。用到了之前章节helloworld的部分代码;
先铺垫代码,后解释:
@RestController
@SpringBootApplication
public class SimpleController {
@Bean
Injector injector(){
return Guice.createInjector(new HelloWorldWebModule());
}
@Bean
RequestParams requestParam(Injector injector){
return injector.getInstance(RequestParams.class);
}
@Bean
WebDestination desdestination(Injector injector){
return injector.getInstance(WebDestination.class);
}
@Bean
MyApplet applet(Injector injector){
return injector.getInstance(MyApplet.class);
}
@Autowired MyApplet applet;//调用helloworld
@Autowired WebDestination destination;//组合字符串
@Autowired RequestParams requestParam;//仅仅将name设置进到局部变量
@GetMapping("/hello")
String home(@RequestParam String name) {
requestParam.setMessage(name);
applet.run();
return destination.getResult();
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SimpleController.class, args);
}
}
控制层,对象使用Autowire进行自动装配,@SpringBootApplication内含有@Configuration,故可以自己定义@Bean让spring进行注入,然后注入我们建立的类,同时参数引用guice的Injector,并建立。
public class HelloWorldWebModule extends AbstractModule {
@Override
public void configure() {
bind(MyApplet.class).to(StringWtringApplet.class);
bind(MyDestination.class).to(WebDestination.class);
}
@Provides @OutPut String getOutputString(RequestParams requestParams){
return requestParams.getMessage();
}
}
public class RequestParams {
private String message;
public RequestParams() {
System.out.println("RequestParams constroct");
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
public class WebDestination implements MyDestination {
private final StringBuilder sb = new StringBuilder();
public WebDestination() {
System.out.println("WebDestination constroct");
}
@Override
public void write(String string) {
sb.append(string);
}
public String getResult() {
return sb.toString();
}
}
上述加构造函数方便我们观看其生命周期和对象。执行后,我们会发现
WebDestination constroct 会打印,两次,RequestParams constroct一次
虽然Spring创建的都是SingleTon,但是在建立MyApplet时,会建立一个MyDestination,然后spring也建立了一个MyDestination,因此会出2次,而RequestParams constroct,是因为
public class StringWtringApplet implements MyApplet {
private MyDestination destination;
private Provider stringProvider;
@Inject
public StringWtringApplet(MyDestination destination,
@OutPut Provider stringProvider) {
super();
this.destination = destination;
this.stringProvider = stringProvider;
}
private void writerString() {
destination.write(stringProvider.get());//get(),只有get的时候才会建立,因此每次访问的时候就会建立一次。
}....
然后因为
@Provides @OutPut String getOutputString(RequestParams requestParams){
return requestParams.getMessage();
}
看到他需要requestParams一次就建立一次,因此我们永远拿不到输出,因为不是同一个对象。
我们可以在RequestParams.class 和WebDestination.class上加上@Singleton,当然是给guice看的,这样就可以保证destination不建立2次。这样我们就能准确输出了
总结:
整个小项目:
通过Springboot进行总控,然后各自做各自事情,guice做依赖注入,springboot做技术栈的事情
互相怎么获得对方的Instance?各自绑定Guice的Injector 和 Application Context.
还有就是注意对象的生命周期,这个是生产环境最容易出问题的地方。
spring:
-- 配置文件体现完整装配结构。 细致地来进行描述每个地方的组装
-- 总的来说使用字符串 实例名:属性名 描述的时候
-- 在Config Time 完成对象组装 run的时候,在读取的时候就搭建出来整个结构,整个过程叫Config Time
guice:
-- java代码来描述绑定的规则
-- 每个依赖/注入只描述局部的依赖
-- 没有Config Time 仅记录下来并验证规则,需要的时候才去加载
-- 好处小于代价,虽然他们其实并不冲突
新项目上可以尝试,但与其他组件整合的时候务必注意生命周期,如果现有的Scope不满足,可以自己来实现,当然官网有实例,如果有什么不理解的可以提出,共同讨论