一、什麼是Guice?
Guice是谷歌(Google)開發的一個輕量級依賴注入框架,它幫助我們更容易地編寫模塊化的代碼,同時提高了代碼的可測試性和可復用性。
Guice通過定義模塊(module)以及注入註解(injection annotations)的方式實現依賴注入(dependency injection),表示一個組件(Component)可以Inject(被注入)依賴實現類以滿足它的need(需求) 。Guice使用注入註解來指示它應該在何處注入依賴項,比如@Inject、@Provides、@singleton等等。
Guice框架解決了很多傳統JavaEE組件交互性的問題,例如模塊初始化的異常、資源泄漏、Factory實現冗長等等。而且,Guice不僅能夠輕鬆自然地解決依賴注入的問題,還能夠更好的支持模塊化開發。
二、Guice核心組件
1. 模塊(Module)
Module可以理解為一個程序組的某一特定部分,它定義了組件的綁定以及如何將組件組裝在一起。每個模塊提供一定的服務(Service):業務功能、DAO、工具類等。Guice框架根據傳好的Module實例(或模塊類)來組裝這些Service。
為了減少無用的啟動時間,Guice的Module是惰性加載的。Guice在運行時會根據實際需要去加載Module。
public class ExampleModule extends AbstractModule { @Override protected void configure() { bind(MyService.class).annotatedWith(Red.class).to(RedServiceImpl.class); // 綁定RedServiceImpl bind(MyService.class).annotatedWith(Green.class).to(GreenServiceImpl.class); // 綁定GreenServiceImpl bind(MyService.class).annotatedWith(Blue.class).to(BlueServiceImpl.class); // 綁定BlueServiceImpl } }
2. 組件(Component)
組件(Component)是我們自己開發的應用程序中的類。Guice能夠實現依賴注入,應用程序中的組件需要標記如何注入這些依賴項。
組件可以使用Guice的注入註解,如@Inject、@Provides和@Singleton等。@Inject表示組件需要一個依賴項,Guice會自動為組件注入它所需要的依賴項;@Provides是使用方法來提供依賴項;@Singleton標誌着這個類的實例應該是單例的,只有一個實例。
public class MyServiceComponent { private final MyService redService; private final MyService greenService; private final MyService blueService; @Inject public MyServiceComponent( @Red MyService redService, @Green MyService greenService, @Blue MyService blueService) { this.redService = redService; this.greenService = greenService; this.blueService = blueService; } }
3. 組件初始化器(Injector)
Injector表示一個類實例(Element),該實例包含有從module中綁定的類的實例。Injector使我們能夠自動將依賴項注入組件中,從而讓組件能夠使用它們所依賴的其他組件實例。
所有的Injector都需要一個Module實例,所有綁定都要在Module的configure()方法中完成。可以在一個應用程序中定義多個Injector,每個Injector可以使用特定的Module實例。Injector可以理解為是一種靜態工廠方法,創建的每個對象都具有相同的依賴項。
Injector injector = Guice.createInjector(new ExampleModule()); MyServiceComponent myComponent = injector.getInstance(MyServiceComponent.class);
三、Guice實戰
1. 使用Guice的依賴注入機制
Guice可以很輕鬆地構建高內聚、低耦合的組件,提高我們代碼的可維護性和可擴展性。下面是一個使用Guice的代碼示例:
public interface MyService { String getName(); } public class MyServiceImpl implements MyService { @Override public String getName() { return "My Service is Running"; } } public class MyComponent { private final MyService myService; @Inject public MyComponent(MyService myService) { this.myService = myService; } public void doSomething() { System.out.println(myService.getName()); } } public class MyModule extends AbstractModule { @Override protected void configure() { bind(MyService.class).to(MyServiceImpl.class); } } public class MyApp { public static void main(String[] args) { Injector injector = Guice.createInjector(new MyModule()); MyComponent myComponent = injector.getInstance(MyComponent.class); myComponent.doSomething(); } }
2. 使用Guice的AOP機制
Guice支持AOP(面向切面編程),它可以使我們更加輕鬆地插入通用的一致性功能,比如日誌記錄、異常處理、緩存管理等。下面是一個使用Guice AOP的代碼示例:
// 實現一個簡單的日誌切面類 @Singleton public class LoggingAspect { @Inject public LoggingAspect() { } @AroundInvoke public Object profile(InvocationContext context) throws Exception { long startTime = System.currentTimeMillis(); try { return context.proceed(); } finally { long totalTime = System.currentTimeMillis() - startTime; System.out.println( context.getMethod().getName() + " in " + totalTime + " millis"); } } } public interface MyService { String getName(); } public class MyServiceImpl implements MyService { @Override public String getName() { return "My Service is Running"; } } public class MyComponent { private final MyService myService; @Inject public MyComponent(MyService myService) { this.myService = myService; } @Log public void doSomething() { System.out.println(myService.getName()); } } public class MyModule extends AbstractModule { @Override protected void configure() { bind(MyService.class).to(MyServiceImpl.class); bindInterceptor(Matchers.any(), Matchers.annotatedWith(Log.class), new LoggingAspect()); } } public class MyApp { public static void main(String[] args) { Injector injector = Guice.createInjector(new MyModule()); MyComponent myComponent = injector.getInstance(MyComponent.class); myComponent.doSomething(); } }
3. 使用Guice的多線程機制
Guice對線程間通信提供了一個簡單的解決方案。Guice中有一個ThreadLocal子類,在注入的時候動態創建和存儲實例,每個線程都有各自的實例。下面是一個使用Guice多線程的代碼示例:
public class MyService { private final ThreadLocal message = new ThreadLocal(); public String getMessage() { return message.get(); } public void setMessage(String message) { this.message.set(message); } } public class MyComponent { private final MyService myService; @Inject public MyComponent(MyService myService) { this.myService = myService; } public void doSomething() { System.out.println(myService.getMessage()); } } public class MyModule extends AbstractModule { @Override protected void configure() { bind(MyService.class); } @Provides public String provideString(MyService myService) { String message = "Hello from " + Thread.currentThread().getName(); myService.setMessage(message); return message; } } public class MyApp { public static void main(String[] args) { Injector injector = Guice.createInjector(new MyModule()); Runnable task = () -> { MyComponent myComponent = injector.getInstance(MyComponent.class); myComponent.doSomething(); }; ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(task); executorService.submit(task); executorService.shutdown(); } }
四、總結
Guice是一個輕量級依賴注入框架,它通過定義模塊和注入註解的方式實現依賴注入,並且幫助我們更容易地編寫模塊化的代碼,提高了代碼的可測試性和可復用性。同時,Guice還支持AOP和多線程機制。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/159342.html