一、依赖引入 (包括 spring-aop 以及 aspectj)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
二、切面配置代码 (使用 javaConfig实现)
package com.weker.service.aspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* 启用AspectJ注解的自动代理
*
* Created by barnabas on 2018/4/10
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class aspectConfig {
@Bean
public RoomUserInfoAspect roomInfoAspect() {
return new RoomUserInfoAspect();
}
}
三、创建切面
package com.weker.service.aspect;
import com.weker.domain.model.CommunityResidentDo;
import com.weker.domain.model.CommunityRoomDo;
import com.weker.domain.param.CommunityResidentQueryParam;
import com.weker.service.common.RedisService;
import com.weker.service.community.CommunityResidentService;
import com.weker.service.community.CommunityRoomService;
import com.weker.service.model.CommunityResidentInfo;
import com.weker.service.model.RedisKeys;
import com.weker.service.model.TransmissionCmd;
import com.weker.service.model.UserBaseInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* 用户房间信息切面
*
* Created by barnabas on 2018/4/10
*/
@Aspect
@Component
public class RoomUserInfoAspect {
@Resource
private CommunityRoomService communityRoomService;
@Resource
private CommunityResidentService communityResidentService;
@Resource
private RedisService redisService;
//多线程异步执行
private ExecutorService work = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "ROOMUSERINFO-ASPECT");
}
});
//添加住户(使用切点 userId)
@Pointcut("execution(* com.weker.service.community.CommunityResidentService.addCommunityResidentInfo(..)) && args(userId)")
public void PointCutAddResident(Long userId) {}
//创建前置通知(通知方法会在目标方法调用之前执行)
@Before(value = "PointCutAddResident(userId)")
public void beforeAddResident(Long userId) {
try {
//方法开始前执行
String hashName = RedisKeys.CacheHashName.ROOM_INFO.getKey();
List<Long> roomIdList = getRoomIdListByUserId(userId);
for (Long roomId : roomIdList) {
redisService.delete(hashName, roomId+"");
}
} catch (Throwable e) {
System.out.println(e.getMessage());
}
}
//创建后置通知(通知方法会在目标方法返回后调用)
@AfterReturning(value = "PointCutAddResident(userId)",returning ="roomId")
public void afterReturningAddResident(Long roomId) {
afterReturningResident(roomId);
}
//创建环绕通知
@Around(value = "PointCutAddResident(userId)")
public void aroundAddResident(ProceedingJoinPoint joinPoint,Long userId) {
try {
//方法开始前执行
String hashName = RedisKeys.CacheHashName.ROOM_INFO.getKey();
List<Long> roomIdList = getRoomIdListByUserId(userId);
for (Long roomId : roomIdList) {
redisService.delete(hashName, roomId+"");
}
//将控制权交给被通知的方法(一定需要)
joinPoint.proceed();
//方法结束后执行
for (Long roomId : roomIdList) {
afterReturningResident(roomId);
}
} catch (Throwable e) {
System.out.println(e.getMessage());
}
}
//根据用户id获取房间号Idlist
private List<Long> getRoomIdListByUserId(Long userId) {
List<Long> roomIdList = new ArrayList<Long>();
CommunityResidentQueryParam param = new CommunityResidentQueryParam();
param.setIsMoveout(2);
param.setUserId(userId);
List<CommunityResidentDo> residentDoList = communityResidentService.getCommunityResidentListByParam(param);
if (!CollectionUtils.isEmpty(residentDoList)) {
for (CommunityResidentDo residentDo : residentDoList) {
roomIdList.add(residentDo.getRoomnoId());
}
}
return roomIdList;
}
//根据住户id获取房间号id
private Long getRoomIdByResidentId(Long residentId) {
Long roomId = 0L;
CommunityResidentDo residentDo = communityResidentService.getCommunityResidentByPrimaryKey(residentId);
if (null != residentDo) {
roomId = residentDo.getRoomnoId();
}
return roomId;
}
//开辟新的线程执行aop 修改住户之后返回 (由于对应的方法需要处理的内容比较多,比较耗时,因此开辟一个新新的线程来执行对应的方法,方便对应的目标方法可以先返回)
public void afterReturningResident(final Long roomId) {
work.execute(new Runnable() {
@Override
public void run() {
try {
communityRoomService.updateRoomInfoCacheByRoomId(roomId);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
小结
这篇文章主要是讲述spring集成aop的实战,可以直接使用。因为spring集成aop执行通知方法完成之后才会返回给目标方法,因此增加了多线程内容,来实现目标方法接口的返回。文章里面包含@Before、@AfterReturning、@Around三种通知方式,在我们平时的aop使用中基本可以满足要求,如有错误,欢迎指教!