zookeeper分布式锁和切面编程

参考文章

zookeeper分布式锁

使用切面注解编程实现redis模糊删除数据之二使用spel表达式

之前实现了zookeeper分布式锁,但是使用的时候比较麻烦,还要try{}catch{}包住要加锁的代码,就像这样

DistributedLock dlock = DistributedLockFactory.createLock(lockstr);
dlock.lock();
try {
    process();
    dlock.unlock();
}catch (Exception e) {
    dlock.unlock();
    throw e;
}

这无疑是非常麻烦的,所以结合之前使用@CacheRemove清除缓存的经验,我尝试使用切面编程在service层上加锁。

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class DistributedLockFactory {
    private static String serverList;
    static {
    	try {
    		InputStream is = DistributedLockFactory.class.getClassLoader().getResourceAsStream("application.properties");
    		Properties property = new Properties();
			property.load(is);
			serverList = property.getProperty("regCenter.serverList");
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    public static DistributedLock createLock(String lockName) {
    	return new DistributedLock(serverList, lockName);
    }
}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ java.lang.annotation.ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ZookeeperLock {
	String value();
}
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import com.kq.highnet2.framework.base.common.annotation.ZookeeperLock;
import com.kq.highnet2.framework.base.common.lock.DistributedLock;
import com.kq.highnet2.framework.base.common.lock.DistributedLockFactory;

@Aspect
@Component
public class ZookeeperLockAspect {
    Logger logger=LoggerFactory.getLogger(this.getClass());
	@Resource(name = "redisTemplate") 
	RedisTemplate redis;
	@Pointcut(value = "(execution(* *.*(..)) && "//截获标有@ZookeeperLock的方法
			+ "@annotation(com.kq.highnet2.framework.base.common.annotation.ZookeeperLock))")
    private void pointcut() {}
	@Around(value = "pointcut()")//切面在方法返回值之后
	private Object process(ProceedingJoinPoint joinPoint) throws Throwable{
	    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
	    Object[] args = joinPoint.getArgs();//切面方法的参数
	    Method method = signature.getMethod();//切面方法
	    ZookeeperLock zookeeperLock = method.getAnnotation(ZookeeperLock.class);//获得注解
    	String value = zookeeperLock.value();//获取锁值的表达式
    	String lockKey = parseKey(value, method, args);
    	DistributedLock lock = DistributedLockFactory.createLock(lockKey);
        Object proceed = null;
    	if(lock !=null) {
    		lock.lock();
    		try {
    			proceed = joinPoint.proceed();//执行代码
    			lock.unlock();
    		} catch (Throwable e) {
    			lock.unlock();
    			logger.error(e.getMessage(), e);
    			throw e;
    		}
    	}else {
    		try {
    			proceed = joinPoint.proceed();
    		} catch (Throwable e) {
    			logger.error(e.getMessage(), e);
    			throw e;
    		}
    	}
        return proceed;
	}
    /** 
     *    key 定义在注解上,支持SPEL表达式 
     * @param pjp 
     * @return 
     */  
    private String parseKey(String key,Method method,Object [] args){           
        //获取被拦截方法参数名列表(使用Spring支持类库)  
        LocalVariableTableParameterNameDiscoverer u =     
            new LocalVariableTableParameterNameDiscoverer();    
        String [] paraNameArr=u.getParameterNames(method);  
          
        //使用SPEL进行key的解析  
        ExpressionParser parser = new SpelExpressionParser();   
        //SPEL上下文  
        StandardEvaluationContext context = new StandardEvaluationContext();  
        //把方法参数放入SPEL上下文中  
        for(int i=0;i pList = descFormat(key);//获取#p0这样的表达式
        //将p0作为参数放入SPEL上下文中
        for(String p:pList) {
        	context.setVariable(p.substring(1), args[Integer.valueOf(p.substring(2))]);
        }
        return parser.parseExpression(key).getValue(context,String.class);  
    } 
    /**
     * 提取出#p[数字]这样的表达式
     * @param desc
     * @return
     */
    private static List descFormat(String desc){  
        List list = new ArrayList<>();  
        Pattern pattern = Pattern.compile("#p[0-9]+");   
        Matcher matcher = pattern.matcher(desc);   
        while(matcher.find()){   
            String t = matcher.group(0);   
            list.add(t);  
        }  
        return list;  
    }
}

DistributedLock 锁的具体实现代码在链接里面有。

然后使用zookeeper分布式锁就只要这样就可以用了

@ZookeeperLock(value="'process'+#companyId")
public void process(String userId, String companyId) {
	System.out.println("代码执行中");
}

是不是就方便多了?虽然只不过是把过去的知识拼凑组合一下而已。。

你可能感兴趣的:(zookeeper,分布式锁,切面编程,zookeeper,切面编程)