google guice 简洁的依赖注入框架

一、前言

google guice是一款简洁的依赖注入框架,如果你想要依赖注入功能,以及AOP功能,又不想引入庞大的Spring Framework,可以考虑使用guice.

下面我会简单翻译github上guice的wiki。

二、依赖注入的好处

考虑一个支付服务:


public interface PayService {
	boolean pay(long userId, double money);
}

一个简单实现如下:

public class RealPayService implements PayService {

	@Override
	public boolean pay(long userId, double money) {
		//编译期硬编码,难以测试
		PayProcessor payProcessor = new BankPayProcessor();
		TransactionLog log = new DbTransactionLog();
		try {
			//支付
			payProcessor.doPay(userId, money);
			//打日志
			log.log("user[" + userId + "]支付了[" + money + "]");
			return true;
		} catch (Exception e) {
			log.log("系统错误:" + e.getMessage());
			return false;
		}
	}

}

由于BankPayProcessor和DbTransactionLog以局部变量形式创建,使得代码难以测试(无法使用Mock实现替换)。

使用依赖注入:

public class RealPayService implements PayService {
	private PayProcessor payProcessor;
	private TransactionLog log;
	
	//从外部注入依赖
	public RealPayService(PayProcessor payProcessor, TransactionLog log) {
		super();
		this.payProcessor = payProcessor;
		this.log = log;
	}

	@Override
	public boolean pay(long userId, double money) {
		try {
			//支付
			payProcessor.doPay(userId, money);
			//打日志
			log.log("user[" + userId + "]支付了[" + money + "]");
			return true;
		} catch (Exception e) {
			log.log("系统错误:" + e.getMessage());
			return false;
		}
	}

}

于是单元测试可编写如下:

public class RealPayServiceTest {
	
	@Test
	public void testPay() throws Exception {
		//创建依赖对象
		PayProcessor payProcessor = new MockPayProcessor();
		TransactionLog log = new MockTransactionLog();
		//注入
		RealPayService payService = new RealPayService(payProcessor, log);
		assertTrue(payService.pay(1L, 100.0));
	}
	
}

解决了代码可测试性,模块化的问题,但创建依赖对象,以及执行注入的代码非常繁琐枯燥。

三、guice实现依赖注入

  1. 配置依赖关系
public class PayModule extends AbstractModule {

	@Override
	protected void configure() {
		//配置接口对应的实现类,依赖注入时将实例化对应的实现类
		bind(PayService.class).to(RealPayService.class);
		bind(PayProcessor.class).to(BankPayProcessor.class);
		bind(TransactionLog.class).to(DbTransactionLog.class);
	}

}
  1. 在需要注入的地方提供注解
	//从外部注入依赖
	@Inject
	public RealPayService(PayProcessor payProcessor, TransactionLog log) {
		super();
		this.payProcessor = payProcessor;
		this.log = log;
	}
  1. 使用guice获取实例
	public static void main(String[] args) {
		//应用生命周期通常只调用一次
		Injector payInjector = Guice.createInjector(new PayModule());
		//获取实例,依赖注入由Guice完成
		PayService payService = payInjector.getInstance(PayService.class);
		payService.pay(1L, 100.0);
	}

四、guice的AOP支持

guice可以定义匹配规则,匹配要拦截的方法,实现AOP编程。

接续上面的例子,假设周四无法支付(今天刚好周四)。

  1. 定义注解
/**
 * 	标注到要拦截的方法上
 * @author ljf
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotOnThursday {
}

  1. 在方法上标注注解
public class RealPayService implements PayService {

	@NotOnThursday
	@Override
	public boolean pay(long userId, double money) {
	}

}

  1. 定义方法拦截器
public class ThursdayBlocker implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Calendar calendar = Calendar.getInstance();
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) {
			throw new IllegalStateException("周四无法调用" + invocation.getMethod().getName());
		}
		return invocation.proceed();
	}

}
  1. 定义匹配规则

public class PayModule extends AbstractModule {

	@Override
	protected void configure() {
		//配置对pay方法的拦截规则
		bindInterceptor(Matchers.any(), Matchers.annotatedWith(NotOnThursday.class), new ThursdayBlocker());
	}

}

5.运行效果

Exception in thread "main" java.lang.IllegalStateException: 周四无法调用pay
	at otaku.dogdog.ThursdayBlocker.invoke(ThursdayBlocker.java:14)

五、更多

移步 guice wiki

你可能感兴趣的:(Java最佳实践)