前言
今天在学习Apollo(配置中心)的客户端源码时,发现其中使用到了guice,它是谷歌推出的一个轻量级(相比Spring)的依赖注入框架,在很多开源项目中都有用到,如elasticsearch,maven等。
添加依赖
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.0</version>
</dependency>
简单定义Bean和依赖注入
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
/**
* 测试Guice的依赖注入
*/
public class Client {
public static void main(String[] args) {
Injector injector = Guice.createInjector();
UserService userService = injector.getInstance(UserService.class);
userService.queryUser();
}
@Singleton
private static class AddressService {
public String queryCity() {
return "百度地图";
}
}
@Singleton
private static class UserService {
@Inject
private AddressService addressService;
public void queryUser() {
System.out.println(addressService.queryCity());
}
}
}
使用@Singleton注解定义一个Bean(参考Spring中的叫法),表示它是单例的(不加的话每次都会创建一个新的对象),类似Spring中的@Component注解。使用@Inject注解注入一个Bean,类似Spring中的@Autowired注解。创建一个注射器Injector,根据它拿到相应类型的Bean。(这里为了代码看起来更直观,所以定义成了内部类)
一个接口多个实现的依赖注入
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
/**
* 测试Guice的依赖注入
*/
public class Client {
public static void main(String[] args) {
try {
Injector injector = Guice.createInjector(new MyModule());
UserService userService = injector.getInstance(UserService.class);
userService.queryUser();
} catch (Exception e) {
e.printStackTrace();
}
}
private static interface AddressService {
String queryCity();
}
@Singleton
private static class BaiduAddressService implements AddressService {
@Override
public String queryCity() {
return "百度地图";
}
}
@Singleton
private static class GaodeAddressService implements AddressService {
@Override
public String queryCity() {
return "高德地图";
}
}
@Singleton
private static class UserService {
@Inject
@Named("gaodeAddressService")
private AddressService addressService;
public void queryUser() {
System.out.println(addressService.queryCity());
}
}
private static class MyModule extends AbstractModule {
@Override
protected void configure() {
// bind(AddressService.class).to(GaodeAddressService.class);
bind(AddressService.class).annotatedWith(Names.named("gaodeAddressService"))
.to(GaodeAddressService.class);
bind(AddressService.class).annotatedWith(Names.named("baiduAddressService"))
.to(BaiduAddressService.class);
}
}
}
一个AddressService接口有两个实现类BaiduAddressService和GaodeAddressService。定义一个自己的Module,自定义装配规则,有两个方式来定义使用哪个实现类
bind(AddressService.class).to(GaodeAddressService.class);
表示在注入AddressService类型时找GaodeAddressService。
bind(AddressService.class).annotatedWith(Names.named("gaodeAddressService"))
.to(GaodeAddressService.class);
bind(AddressService.class).annotatedWith(Names.named("baiduAddressService"))
.to(BaiduAddressService.class);
使用@Named注解来给每一个绑定关系添加注解条件,注入时也使用@Named("gaodeAddressService")来标识,类似Spring的@Qualifier注解的功能。我们也可以使用自定义注解
import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 测试Guice的依赖注入
*/
public class Client2 {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new MyModule());
UserService userService = injector.getInstance(UserService.class);
userService.queryUser();
}
private static interface AddressService {
String queryCity();
}
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
@interface Baidu {
}
@Singleton
private static class BaiduAddressService implements AddressService {
@Override
public String queryCity() {
return "百度地图";
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
@interface Gaode {
}
@Singleton
private static class GaodeAddressService implements AddressService {
@Override
public String queryCity() {
return "高德地图";
}
}
@Singleton
private static class UserService {
@Inject
@Baidu
private AddressService addressService;
public void queryUser() {
System.out.println(addressService.queryCity());
}
}
private static class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(AddressService.class).annotatedWith(Gaode.class).to(GaodeAddressService.class);
bind(AddressService.class).annotatedWith(Baidu.class).to(BaiduAddressService.class);
}
}
}
使用Provider来注入
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Singleton;
/**
* 测试Guice的依赖注入
*/
public class Client {
public static void main(String[] args) {
try {
Injector injector = Guice.createInjector(new MyModule());
UserService userService = injector.getInstance(UserService.class);
userService.queryUser();
} catch (Exception e) {
e.printStackTrace();
}
}
private static interface AddressService {
String queryCity();
}
@Singleton
private static class BaiduAddressService implements AddressService {
@Override
public String queryCity() {
return "百度地图";
}
}
@Singleton
private static class GaodeAddressService implements AddressService {
@Override
public String queryCity() {
return "高德地图";
}
}
private static class AddressServiceProvider implements Provider<AddressService> {
@Override
public AddressService get() {
return new BaiduAddressService();
}
}
@Singleton
private static class UserService {
@Inject
private AddressService addressService;
public void queryUser() {
System.out.println(addressService.queryCity());
}
}
private static class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(AddressService.class).toProvider(AddressServiceProvider.class);
}
}
}
将AddressService绑定到指定的Provider,由它来决定具体使用哪个实现类,类似Spring中的FactoryBean或ObjectFactory。
AOP使用
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.google.inject.matcher.Matchers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* 测试Guice的AOP
*/
public class Client {
public static void main(String[] args) {
try {
Injector injector = Guice.createInjector(new MyModule());
UserService userService = injector.getInstance(UserService.class);
userService.queryUser();
AddressService addressService = injector.getInstance(AddressService.class);
addressService.queryAddress();
} catch (Exception e) {
e.printStackTrace();
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Log {
}
@Singleton
public static class UserService {
@Log
public void queryUser() {
System.out.println("this is lisi");
}
}
@Singleton
public static class AddressService {
public void queryAddress() {
System.out.println("this is 上海");
}
}
private static class MyInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("method before");
Object result = invocation.proceed();
System.out.println("method after");
return result;
}
}
private static class MyModule extends AbstractModule {
@Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Log.class), new MyInterceptor());
}
}
}
进行AOP拦截的类必须修饰为public或default(包内可见),底层是使用cglib创建代理来实现的,核心类为ProxyFactory。绑定拦截器需要指定类匹配器(拦截哪些类)和方法匹配器(拦截那些方法),Matchers工具类提供了一些匹配器,我们也可以自己定义。
总结
Guice相比Spring少了很多功能,如自动扫描,但也因此更加的灵活和轻便,更多关于Guice的用法,可以查看官方文档。