google(轻量级依赖注入框架)Guice学习 (四) guice与springboot简单协作、总结

        对于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<String> stringProvider;

	@Inject
	public StringWtringApplet(MyDestination destination, 
			@OutPut Provider<String> 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.

               还有就是注意对象的生命周期,这个是生产环境最容易出问题的地方。


两者区别

    一、guice并不是Spring的重制版
    二、绑定

        spring:

            --    配置文件体现完整装配结构。       细致地来进行描述每个地方的组装

            --    总的来说使用字符串   实例名:属性名           描述的时候

            --    在Config Time 完成对象组装            run的时候,在读取的时候就搭建出来整个结构,整个过程叫Config Time


        guice:

            --     java代码来描述绑定的规则    

            --     每个依赖/注入只描述局部的依赖

            --     没有Config Time    仅记录下来并验证规则,需要的时候才去加载

        三、优点
                guice
                   --       代码量少
                   --       性能优异
                  --        泛型支持     --spring虽然3.0后加入了,但是内部数据结构还是没有泛型结构
                  --        通过Constructor 绑定  Immutable    Object(不可变),不需要getter/setter
                                好处,可以在内存中仅放一份,不需要拷来拷去,且线程安全。
                  --         强类型     容易判断错误
                  --        易于重构    都是绑定java的类,易于Refactor
          四、缺点
                   guice 
                    --    Module绑定的规则不容易理解,要求我们guice的开发者做一个容易理解的包装
                    --     文档教程、社区资源少
                    --    无法搭出特殊结构:循环依赖。。。。。

           五、不建议从Spring迁移到guice

                    --        好处小于代价,虽然他们其实并不冲突

                

        新项目上可以尝试,但与其他组件整合的时候务必注意生命周期,如果现有的Scope不满足,可以自己来实现,当然官网有实例,如果有什么不理解的可以提出,共同讨论

猜你喜欢

转载自blog.csdn.net/CoffeeAndIce/article/details/80323931