假设我们有这样的一个场景 : 对于一个类的众多方法,有些方法需要从缓存读取数据,有些则需要直接从数据库读取数据。怎样实现呢?
实现方案有多种。下面我说下常见的几种实现方案 :
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()); } }