public class FooApplication {
public static void main(String[] args) {
Injector injector = Guice.createInjector(
new ModuleA(),
new ModuleB(),
. . .
new FooApplicationFlagsModule(args)
);
// Now just bootstrap the application and you're done
FooStarter starter = injector.getInstance(FooStarter.class);
starter.runApplication();
}
}
Guice.createInjector(Stage.PRODUCTION, new ModuleA());
Guice.createInjector(new ModuleA());//默认DEVELOPMENT
public class EventModule extends AbstractModule {
@Override
protected void configure() {
// 绑定接口与实现
bind(EventBusManager.class).annotatedWith(Names.named("eventBusManager")).to(EventBusManager.class);
}
}
bind(EventService.class).to(SpringEventService.class);
bind(EventService.class).toInstance(new SpringEventService());
bind(SpringEventService.class).asEagerSingleton();
bind(EventService.class).toProvider(new Provider(){
@Override
public EventService get(){
return new SpringEventService();
}
});
bind(EventService.class).toConstructor((Constructor)SpringEventService.class.getConstructors()[0]);
@Singleton
public class MyHandler {
@Inject
@Named("springEventService")
private EventService eventService;
@Subscribe
public void handleEvent(MyEvent event) {
eventService.post("MyHandler",event);
}
}
FooStarter starter = injector.getInstance(FooStarter.class);
先根据指定的class类new Key(),Key包括class信息和注解信息,class的hashcode和注解的hashcode决定了Key的hashcode,getProvider时是根据Key的hashcode来判断是否是同一个Key,然后取到Provider,由Provider提供最终的instance
注意:无注解时会有一个默认的hashcode
class.hashcode * 31 + annotation.hashcode
会出现多个组合得到的hashcode是相同的情况么?
2 * 31 + 3 = 65
1 * 31 + 34 = 65
为什么用这样的公式?(java中String是如何计算hashcode的?)
Joshua Bloch's Effective Java中是这样解释的:
The value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting. The advantage of using a prime is less clear, but it is traditional. A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31 * i == (i <<5) - i. Modern VMs do this sort of optimization automatically.(from Chapter 3, Item 9: Always override hashcode when you override equals, page 48)
选择值31是因为它是奇数。 如果是偶数并且乘法溢出,则信息将丢失,因为乘以2等效于移位。 使用素数的优点不太清楚,但它是传统的。 31的一个好的属性是乘法可以由移位和减法替换以获得更好的性能:31 * i ==(i <<5) - i。 现代虚拟机自动进行这种优化。(从第3章,项9:覆盖equals时始终覆盖hashcode,第48页)
参考:
http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier
https://www.cs.cmu.edu/~adamchik/15-121/lectures/Hashing/hashing.html
由于一个class被加载后是否唯一由加载的classloader决定,所以不同的classloader加载同一个class会生成两个class实例(反射中一个class也会有一个实例),两个不同的class生成的Key的hashcode则不同,所以在Guice中根据Key来获取时必须要用同一个classloader加载的类,否则获取不到,所以在OSGI方式下用Guice需要注意
Injector injectorBase = Guice.createInjector(new EventModule());用一个已经有的实例,但依赖的对象为null,这时可以用injector注入依赖对象,但这个实例不会有绑定关系,所以如果其他有需要依赖这个实例的也无法注入这个实例
Injector injector = injectorBase.createChildInjector(new SpringModule());
MyHandler handler = new MyHandler();// eventService is null
injector.injectMembers(handler);// eventService use instance
Injector parent = Guice.createInjector(new EventModule());child 可以依赖parent ,但反过来则不可以
Injector child = parent .createChildInjector(new SpringModule());
一个Injector中如果包含了多个Module,各Module中的是可以相互使用的,也就是可以相互依赖
如果一个Injector想依赖另一个Injector中的实例,那就要通过继承了,例如功能模块想要依赖基础模块,那功能模块可以继承基础模块
Binder#bindInterceptor(Matcher super Class>> classMatcher, Matcher super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors)Matcher通过Matchers来生成
bindInterceptor(Matchers.any(),Matchers.annotatedWith(Named.class),new MethodInterceptor(){
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("do something before...");
Object result = invocation.proceed();
System.out.println("do something after...");
return result;
}
});
如何解决这种相互依赖?
达到的效果:
处理过程:
代码:
将spring中的bean暴露给Guice:
public class SpringModule extends AbstractModule {将Guice里的beans暴露给spring:
private ConfigurableListableBeanFactory beanFactory;
public SpringModule(ConfigurableListableBeanFactory beanFactory){
this.beanFactory = beanFactory; }
@Override
protected void configure() {
bind(BeanFactory.class).toInstance(this.beanFactory);
String[] names = this.beanFactory.getBeanDefinitionNames();
for (String name : names) {
try {
Object instance = this.beanFactory.getBean(name);
Class clazz = instance.getClass();
bind(clazz).toInstance(instance);
Class[] intefaces = clazz.getInterfaces();
for (Class inteface: intefaces) {
if (!inteface.getName().contains("com.xxxxxx")) {
continue;
}
bind(inteface).annotatedWith(Names.named(name)).toInstance(instance);
}
bind(clazz).annotatedWith(Names.named(name)).toInstance(instance);
} catch (Exception e) {
}
}
}
}
@Componentpublic class PbfInitProcesser implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // map injector to spring beanFactory Injector spring = Guice.createInjector(new SpringModule(beanFactory)); Injector injector = spring.createChildInjector(new ProductModule()); PbfEnvInitUtil.shareGuiceToSpring("injector", beanFactory, injector); }}
public class PbfEnvInitUtil { public static final void refresh(ApplicationContext context) { // refresh inject bean to autowire String names[] = context.getBeanDefinitionNames(); for (String name : names) { context.getAutowireCapableBeanFactory().autowireBean(context.getBean(name)); } } public static void shareGuiceToSpring(String bizName, ConfigurableListableBeanFactory beanFactory, Injector injector) { Map, Binding>> map = injector.getAllBindings(); Iterator , Binding>>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry , Binding>> entry = iterator.next(); Binding> binding = entry.getValue(); Object listener = binding.getProvider().get(); Annotation annotation = entry.getKey().getAnnotation(); if (null != annotation && annotation instanceof Named) { String name = ((Named)annotation).value(); try { beanFactory.registerSingleton(name, listener); } catch (Exception e) { } } } beanFactory.registerSingleton(bizName, injector); }}
ApplicationContext cOntext= SpringApplication.run(Application.class, args);
PbfEnvInitUtil.refresh(context);