一、作用域(控制对象生命周期)
利用上文业务,插入一个缓存类来说明作用域
/** * 实现cache,使用谷歌类库 * * @author lg * */ public class GuiceDemoCache extends AbstractCache<String, String> { private final Map<String, String> keyValues = new HashMap<>(); @Override public String getIfPresent(Object key) { return keyValues.get(key); } @Override public void put(String key, String value) { keyValues.put(key, value); } }
paymentServiceImpl部分代码:
public class PaymentServiceImpl implements PaymentService { private final Cache<String, String> cache; @Inject private PaymentServiceImpl(Cache<String, String> cache) { this.cache = cache; } void putCache(String key, String value) {//同一个包下可用 cache.put(key, value); }
PriceServiceImpl部分代码
private PrinceServiceImpl implements PrinceService{ private final Cache<String,String> cache; @Inject public PriceServiceImpl(Set<String> supportedCurrenties, Cache<String,String> cache) { this.supportedCurrenties = supportedCurrenties; this.cache = cache; } String getCache(String key) { return cache.getIfPresent(key);// 如果存在获取 }
测试类:
public class CacheTests { //由于没有实现接口,是写于类内部,故注入实现类 @Inject private PaymentServiceImpl paymentServiceImpl; @Inject private PriceServiceImpl priceServiceImpl; @Before public void setUp() { Guice.createInjector(new ServerModule()) .injectMembers(this); } @Test public void test() { paymentServiceImpl.putCache("Test","hahah"); String cache = priceServiceImpl.getCache("Test"); Assert.assertEquals(cache, "hahah"); } }
得出的结果是,他们的作用域仅局限于其方法内,每次获取仍需获取新的cache。
(一)单例(Singleton)
要使其全局唯一,
(1)@Singleton注解,javax.inject.Singleton;下;
(2)bind(new TypeLiteral<Cache<String,String>>(){})
.to(GuiceDemoCache.class).in(Singleton.class);;
(3)@Provides @Singleton Cache<String,String> getCache(){
return new GuiceDemoCache();
}
但是对于多线程而言,这样的单例并不能满足我们需要,因为缓存用的是HashMap,改成ConcurrentHashMap即可;
二、AOP
AOP: Aspect Oriented Programming
Aspect: 一般针对日志,安全(全局拦截)、Transaction.....
Guice有一个Methodinterceptor 接口:
将方法拦截下来,来做Aspect所要做的事情,拦截下来后:
(1)可以获得各种信息; 函数调用类、方法、参数。。。。
(2)控制是否函数调用; 比如是否拥有权限访问。。。
eg:
OrderServerImpl.class中定义一个注解,仅需运行时即可
@Override @Logged 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); }
ServerModule.class
bindInterceptor(Matchers.any(), //所有类别 Matchers.annotatedWith(Logged.class),//注释为Logged的方法 new MethodInterceptor() {//拦截处理 @Override public Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); System.out.println(String.format("calling %s#%s(%s)", method.getDeclaringClass().getName(), method.getName(), Joiner.on(",").join( invocation.getArguments()))); return invocation.proceed(); } });
调用测试类:
calling CoffeeAndIce.GuiceDemo.server.impl.OrderServerImpl#sendToPayment(789) //日志打印成功
tips: requestInjection(instance);//可以用来要求注入某个类
总结流程:
1、绑定Methodinterceptor
2、实现Methodinterceptor
3、在Methodinterceptor 中注入Dependency
warm:但是guice的Aop必须使用在通过guice创建的对象上,比如我们手工创建一个对象,添加日志AOP,这时,guice也是没有办法去拦截的,必须通过guice从头开始inject开始的才可以进行AOP处理