1、什么是 AOP?Spring AOP 和 AspectJ AOP 有什么区别?有哪些实现 AOP 的方式?
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程思想,可以在不修改原有业务逻辑代码的情况下,动态地增加新的行为和功能。它通过将横切关注点(cross-cutting concerns)从业务逻辑中分离出来,以切面(aspect)的形式进行封装,实现了系统功能的模块化。
Spring AOP 和 AspectJ AOP 都是基于 AOP 思想的实现方式,其中 Spring AOP 是 Spring 框架提供的轻量级 AOP 框架,主要基于动态代理技术,可以对方法进行拦截和切入增强等操作。而 AspectJ AOP 则是基于 AspectJ 编译器独立的 AOP 框架,提供了更加强大的AOP能力,支持静态代理和动态代理两种方式,可以在编译期、类加载期、运行期等多个层面进行增强操作。
它们的主要区别在于:
- Spring AOP 只支持方法级别的切面,而 AspectJ AOP 支持更加细粒度的切面,包括方法、属性、构造函数等。
- Spring AOP 只支持运行时织入(runtime weaving),而 AspectJ AOP 支持编译时织入(compile-time weaving)和类加载时织入(load-time weaving),可以更加灵活地进行切面的织入。
除了 Spring AOP 和 AspectJ AOP,还有其他一些实现 AOP 的方式:
- 使用动态代理实现 AOP,这是一种比较轻量级的方式,可以实现对类的方法进行切面织入。
- 使用字节码增强技术实现 AOP,这种方式可以实现更加细粒度的切面织入,但相对比较复杂。
- 使用自定义类来实现AOP:主要是利用Java中的反射机制或者字节码工具,在运行时动态生成代理类实现AOP功能。
- 使用注解处理器实现 AOP,这是一种基于编译时的技术,可以通过注解来指定切面的织入点,比较灵活方便。
2、如何使用 Redis 实现分布式锁?
使用 Redis 实现分布式锁的核心思想是利用 Redis 的原子性操作,对Redis中特定的key进行setnx(set if not exists)操作,如果成功返回true表示获取到了锁,否则返回false表示没有获取到锁。在获取到锁的情况下,需要设置过期时间和在释放锁之前判断当前锁是否是自己持有的,以防出现死锁等问题。
具体实现步骤如下:
- 生成一个唯一的锁标识key,并设置锁的过期时间。
- 使用 setnx 命令尝试获取锁,如果返回结果为1,则表示获取锁成功,进入下一步;否则等待一段时间重试,直到获取到锁为止。
- 在持有锁的时间内,执行相关业务逻辑操作,并定时更新锁的过期时间,防止锁时间过长而导致锁自动失效。
- 释放锁,通过比较锁的持有者是否是自己来判断是否能够释放锁。
public class RedisDistributedLock {
private static final String LOCK_PREFIX = "redis_lock_";
private static final int EXPIRE_TIME = 5; // 锁过期时间5秒
private RedisTemplate<String, Object> redisTemplate;
private String lockKey;
private String lockValue;
// 构造函数
public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate, String lockKey) {
this.redisTemplate = redisTemplate;
this.lockKey = LOCK_PREFIX + lockKey;
this.lockValue = UUID.randomUUID().toString();
}
// 获取锁
public boolean lock() {
try {
String result = redisTemplate.execute((RedisCallback<String>) connection -> {
JedisCommands commands = (JedisCommands) connection.getNativeConnection();
return commands.set(lockKey, lockValue, "NX", "EX", EXPIRE_TIME);
});
return StringUtils.isNotBlank(result);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
// 释放锁
public boolean unlock() {
try {
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
Long result = redisTemplate.execute((RedisCallback<Long>) connection -> {
JedisCommands commands = (JedisCommands) connection.getNativeConnection();
return (Long) commands.eval(script, Collections.singletonList(lockKey), Collections.singletonList(lockValue));
});
return result != null && result > 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
3、什么是分布式的 BASE 理论,它与 CAP 理论有什么联系?
分布式的BASE理论是建立在BASE理论(Basically Available, Soft State, Eventually Consistent)的基础上,针对分布式系统而提出的一种指导思想。它强调在分布式系统中,为了实现高可用性和可扩展性,有时需要牺牲一致性,通过异步复制、副本同步、冲突解决等方式来实现最终一致性。在这种情况下,系统的基本可用性和性能应该得到保障,并在最终一致性的前提下,尽量减少一致性等待时间。
区别:
CAP理论(Consistency, Availability, Partition Tolerance)是严格的理论限制。在分布式系统中,无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition Tolerance)三个条件,只能选择其中两个进行保障。由于在分布式系统中,节点之间可能会出现网络分区(Partition)导致通信中断,从而需要在可用性和一致性之间做出取舍。
- Consistency:所有节点在同一时间看到相同的数据,即数据在多个节点间保持强一致性。
- Availability:系统能够在有限时间内对外提供服务,即系统具有高可用性。
- Partition Tolerance:系统能够在节点之间发生网络分区时继续工作,即系统具有分区容错性。
分布式的BASE理论认为,在分布式系统中,一致性不是绝对必须的,如果系统能够满足基本可用性和最终一致性,就可以放宽一致性要求,实现更高的性能和可扩展性。
两者的联系:
CAP理论和BASE理论都是面向分布式系统的理论,而且都关注系统的可用性。但它们关注的方面不同:
- CAP理论关注分布式系统中数据的一致性和可用性,强调一致性和可用性之间需要进行取舍;
- BASE理论关注分布式系统中数据的最终一致性和可用性,强调最终一致性和可用性之间的平衡。
场景:
- 当需要保证强一致性和数据安全性时,可以采用CAP理论,例如金融交易系统、电商系统等;
取舍; - BASE理论关注分布式系统中数据的最终一致性和可用性,强调最终一致性和可用性之间的平衡。
场景:
- 当需要保证强一致性和数据安全性时,可以采用CAP理论,例如金融交易系统、电商系统等;
- 当需要追求高性能和可扩展性时,可以采用BASE理论,例如社交网络、日志系统等。