假设我们有这样的一个场景 : 对于一个类的众多方法,有些方法需要从缓存读取数据,有些则需要直接从数据库读取数据。怎样实现呢?
实现方案有多种。下面我说下常见的几种实现方案 :
1、直接采用spring xml、或者 annotation AOP完成。但个人认为这种方案似乎有点不是很完美。
原因 : ①、如果只有针对这个类做切面拦截,这种方案是没有问题的,只需对需要走DB(or 缓存,两者择一)的方法配置切面。
②、那如果是多个类呢?统一做一个切面,对指定方法拦截,如selectXXX。但,还要考虑个特殊场景,每个人的代码风格不一致,你不能限制
别人的风格,查询他就偏偏用queryXXX来命令。你能拦截到么?
2、采用 ProxyFactory 拦截处理, 并且用java自定义的annotation来作为是否需要走缓存的方法唯一标识。(实现得不是很好,后期会持续优化,见谅)
看下代码
1)自定义注解,标识是否需要走缓存
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheAnnotition { }
2)接口定义
public interface UserReadService { @CacheAnnotition
public UserInfo getUserInfoById(Long id); public UserInfo getUserInfoByName(String name);
}
@Component("userReadService")
public class UserReadServiceImpl implements UserReadService { @Override
public UserInfo getUserInfoById(Long id) {
System.out.println("获取用户信息");
return null;
} @Override
public UserInfo getUserInfoByName(String name) {
// TODO Auto-generated method stub
return null;
} }
public interface PeopleReadService { @CacheAnnotition
public UserInfo getPeopleInfoById(Long id); public UserInfo getPeopleInfoByName(String name);
}
@Component("peopleReadService")
public class PeopleReadServiceImpl implements PeopleReadService { @Override
public UserInfo getPeopleInfoById(Long id) {
System.out.println("getPeopleInfoById : 获取用户信息");
return null;
} @Override
public UserInfo getPeopleInfoByName(String name) {
// TODO Auto-generated method stub
return null;
} }
3)拦截处理核心逻辑
public class ProxyFactoryDemo { public static Map<String, Class<?>> beanMap = new HashMap<String, Class<?>>();
public static Map<String, Class<?>> instanceMap = new HashMap<String, Class<?>>(); public static List<Object> proxyObjs = new ArrayList<Object>(); static {
beanMap.put("userReadService", UserReadService.class);
beanMap.put("peopleReadService", PeopleReadService.class); instanceMap.put("userReadService", UserReadServiceImpl.class);
instanceMap.put("peopleReadService", PeopleReadServiceImpl.class);
} public static void main(String[] args) throws Exception {
initProxyObjs(); for(Object proxy : proxyObjs) {
if (proxy instanceof UserReadService) {
UserReadService u = (UserReadService)proxy;
u.getUserInfoById(null);
u.getUserInfoByName(null);
} else if(proxy instanceof PeopleReadService) {
PeopleReadService p = (PeopleReadService)proxy;
p.getPeopleInfoById(null);
p.getPeopleInfoByName(null);
}
}
} public static void initProxyObjs() throws InstantiationException, IllegalAccessException {
Iterator<String> it = beanMap.keySet().iterator();
while (it.hasNext()) {
String beanName = it.next();
Class<?> beanClass = instanceMap.get(beanName);
Object proxy = getProxy(beanClass.newInstance(), beanMap.get(beanName), beanName);
proxyObjs.add(proxy);
}
} public static Object getProxy(final Object target, Class<?> aClass, final String beanName) { ProxyFactory factory = new ProxyFactory(); factory.addInterface(aClass);
factory.setTarget(target);
factory.setOpaque(true);
factory.addAdvice(new MethodInterceptor() { @Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("start");
if (invocation.getMethod().isAnnotationPresent(CacheAnnotition.class)) {
System.out.println(invocation.getMethod().getName() + "需要走缓存");
} else {
System.out.println(invocation.getMethod().getName() + "不需要走缓存");
}
Object obj = invocation.proceed();
System.out.println("end");
return obj;
}
}); return factory.getProxy(factory.getClass().getClassLoader());
}
}