Guice与Spring 相比,属于轻量级框架,更轻,帮助我们解决Java项目中的依赖注入问题。如果仅需要解决依赖和注入问题的话,就应该考虑一下它,而不是直接Spring走起
谈论:注入首先来设定场景,假设有一个订单场景,当然,我们只为了展示注入而设定一个微小的代码段;
ps: 文中所用maven配置
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>com.google.inject.extensions</groupId> <artifactId>guice-multibindings</artifactId> <version>4.2.0</version> </dependency> </dependencies>(Guice的扩展Multibindings,可以做到多个Module共同Bind一个Set)
建立一个业务接口:OrderService.class 用于描述场景
public interface OrderService { void sendToPayment(long orderId); }
业务实现类:OrderServerImpl.class
import javax.inject.Inject; //引用javax的是因为guice已经对其进行实现 import CoffeeAndIce.GuiceDemo.server.OrderService; import CoffeeAndIce.GuiceDemo.server.PaymentService; import CoffeeAndIce.GuiceDemo.server.PriceService; public class OrderServerImpl implements OrderService { //Dependencies private final PriceService priceService; private final PaymentService paymentService; private final SessionManager sessionManager; //States private Long ordersPaid = 0L; @Inject public OrderServerImpl(PriceService priceService, PaymentService paymentService, SessionManager sessionManager) { super(); this.priceService = priceService; this.paymentService = paymentService; this.sessionManager = sessionManager; } public void sendToPayment(long orderId) { long price = priceService.getPrice(orderId); paymentService.pay(orderId, price, sessionManager.getSessionId()); ordersPaid = ordersPaid + 1; throw new RuntimeException("Price" + price + ".SessionId=" + sessionManager.getSessionId() + "orderPaid=" + ordersPaid); } }
其余实现类仅返回一个简单Long,接口有了,实现类也有了,接下来就是如何将接口和实现类关联的问题了,在Guice中需要定义Module来进行关联,注入的配置是自写的Java类,必须继承AbstractModule抽象类,实现configure()方法
public class ServerModule extends AbstractModule{ @Override protected void configure() { bind(OrderService.class).to(OrderServerImpl.class);//相当于将实现类注入 bind(PaymentService.class).to(PaymentServiceImpl.class); bind(PriceService.class).to(PriceServiceImpl.class); } }
对于SessionManager,我们也可以这样注入:
(一)纯类型注入(单一类型)
public class SessionManager { private final Long sessionId; @Inject public SessionManager(Long sessionId) { super(); this.sessionId = sessionId; } public Long getSessionId() { // TODO Auto-generated method stub return sessionId; } }
public class ServerModule extends AbstractModule{ @Override protected void configure() { bind(OrderService.class).to(OrderServerImpl.class); bind(PaymentService.class).to(PaymentServiceImpl.class); bind(PriceService.class).to(PriceServiceImpl.class); // bind(Long.class).toInstance(1234L); //方式一 ; } @Provides Long generateSessionId(){//方式二,名字可以随便起,当且仅有一个类型注入 return 1234L; }
(二)Provider注入(单一类型):是一个很灵活的接口
private final Provider<Long> SessionIdProvider; @Inject public SessionManager(Provider<Long> SessionIdProvider) { super(); this.SessionIdProvider = SessionIdProvider; } public Long getSessionId() { // TODO Auto-generated method stub return SessionIdProvider.get(); }
@Override protected void configure() { bind(OrderService.class).to(OrderServerImpl.class); bind(PaymentService.class).to(PaymentServiceImpl.class); bind(PriceService.class).to(PriceServiceImpl.class); // bind(Long.class).toInstance(1234L);//方式一 bind(Long.class).toProvider(new Provider<Long>() {//方式二 @Override public Long get() { return 1234L; } }); } // @Provides @SessionId Long generateSessionId(){//方式三,名字可以随便起,当且仅当仅一个类型时 // return 1234L; // }
(三)命名注入:多个同类型注入分辨(引入注解)
可以直接用@Named("getCurrentTimes") ,内容自填,注入的时候只关注名字与类型匹配
还可以自定义:
@SessionId
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import com.google.inject.BindingAnnotation; @Retention(RetentionPolicy.RUNTIME)//运行时起作用 @BindingAnnotation //让其绑定注释 public @interface SessionId { }
SessionManager.class
public class SessionManager { private final Provider<Long> SessionIdProvider; @Inject public SessionManager(@SessionId Provider<Long> SessionIdProvider) { super(); this.SessionIdProvider = SessionIdProvider; } public Long getSessionId() { // TODO Auto-generated method stub return SessionIdProvider.get(); } }
ServerModule.class
public class ServerModule extends AbstractModule{ @Override protected void configure() { bind(OrderService.class).to(OrderServerImpl.class); bind(PaymentService.class).to(PaymentServiceImpl.class); bind(PriceService.class).to(PriceServiceImpl.class); // bind(Long.class).annotatedWith(SessionId.class).toInstance(1234L);;//方式一 ,用这种方式,生成configure的时候已经固定数值 // bind(Long.class).annotatedWith(SessionId.class).toProvider(new Provider<Long>() {//方式二 // // @Override // public Long get() { // return 1234L; // } // }); } @Provides @SessionId Long generateSessionId(){//方式三,名字可以随便起,当且仅当仅一个类型时 return 1234L; } }
(四)测试类
public class OrderServerTest { @Inject private OrderService orderService; @Before public void SetUp() { //利用injectMembers,将当前所需的类具现化 Guice.createInjector(new ServerModule()).injectMembers(this);; } @Test public void testSendToPayment() { // 旧方法,将所需的类具现化 // OrderService orderService = Guice.createInjector(new ServerModule()) // .getInstance(OrderService.class); orderService.sendToPayment(789L); } }github: guice系列的测试类都在