springboot利用切面记录在线人数

众所周知springboot两大特性,ioc和aop即控制反转和面向切面编程。
aop的用处主要是横向截取公有功能。比如管理事务,处理异常等
目前在做一个论坛系统,需要统计在线人数。
有两个方案:
1、就是利用Session会话机制,通过监听器判断是否有新的会话生成,这种的好处是即使参数中没有用户信息也可以正常收集信息,缺点是如果同一个用户打开多个会话,那么会重复记录。
2、就是利用一个Set集合。每次有用户触发接口,记录用户ID,最后Set.size()即是在线人数
springboot集成aop的注解实现主要有两种
一种是正常的切点注入
首先pom文件添加依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
然后是切面类
package com.hqjl.communityserv.aspect;

import com.hqjl.communityserv.request.RequestParamInfo;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * @author chunying
 * @Date: 2019/11/6 0006
 */
@Aspect
@Component
public class UserLine {

    private final Logger LOG = LoggerFactory.getLogger(UserLine.class);
    private static Set<String> onLineUsers = new HashSet<>();

    @Pointcut("execution(* com.hqjl.communityserv.controller..*(..))")
    public void addOnlineUser(){}

    @Around(addOnlineUser())
    public Object interceptor(ProceedingJoinPoint point) {
        Object result = null;
        Object[] args = point.getArgs();
        if (args != null && args.length > 0) {
            RequestParamInfo arg = (RequestParamInfo)args[0];
            String userID = arg.getUserID();
            if (!onLineUsers.contains(userID)) {
                onLineUsers.add(userID);
            }
        }
        try {
            result = point.proceed();
        }catch(Throwable e) {
            LOG.error(e.getMessage(), e);
        }
        return result;
    }

    public static Integer getOnlineCount() {
        return onLineUsers.size();
    }

}
Aspect注解:表明这是一个切面类
Component注解:不用多说吧 注入到spring中
Pointcut注解:切点配置  我这里配置的表示 controller包下的所有类会被这个切面影响。具体写法可查切面表达式
Around注解:和我们用xml配置文件一样 表示advice。还有Before After等
参数ProceedingJoinPoint  这个是必须的  这个类继承了JoinPoint
其中proceed()方法表示执行方法。这个里面有许多方法
大概列一下
//拦截的实体类
Object target = point.getTarget();
//拦截的方法名称
String methodName = point.getSignature().getName();
//拦截的方法参数
Object[] args = point.getArgs();
//拦截的放参数类型
Class[] parameterTypes = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes();
Method m = null;
try {
//通过反射获得拦截的method
m = target.getClass().getMethod(methodName, parameterTypes);
//如果是桥则要获得实际拦截的method
if(m.isBridge()){
for(int i = 0; i < args.length; i++){
//获得泛型类型
	Class genClazz = GenericsUtils.getSuperClassGenricType(target.getClass());
	//根据实际参数类型替换parameterType中的类型
	if(args[i].getClass().isAssignableFrom(genClazz)){
		parameterTypes[i] = genClazz;
	}
}
		//获得parameterType参数类型的方法
		m = target.getClass().getMethod(methodName, parameterTypes);
	}
} catch (SecurityException e) {
	e.printStackTrace();
} catch (NoSuchMethodException e) {
	e.printStackTrace();
	}
}

这是第一种方法
如果觉得不够灵活 我们可以用第二种
基于注解的配置
首先创建注解

package com.hqjl.communityserv.annotation;

import java.lang.annotation.*;

/**
 * @author chunying
 * @Date: 2019/11/6 0006
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface UserOnline {
}

然后配置切面类

package com.hqjl.communityserv.aspect;

import com.hqjl.communityserv.request.RequestParamInfo;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * @author chunying
 * @Date: 2019/11/6 0006
 */
@Aspect
@Component
public class UserLine {

    private final Logger LOG = LoggerFactory.getLogger(UserLine.class);
    private static Set<String> onLineUsers = new HashSet<>();

    @Around(value = "@annotation(com.hqjl.communityserv.annotation.UserOnline)")
    public Object interceptor(ProceedingJoinPoint point) {
        Object result = null;
        Object[] args = point.getArgs();
        if (args != null && args.length > 0) {
            RequestParamInfo arg = (RequestParamInfo)args[0];
            String userID = arg.getUserID();
            if (!onLineUsers.contains(userID)) {
                onLineUsers.add(userID);
            }
        }
        try {
            result = point.proceed();
        }catch(Throwable e) {
            LOG.error(e.getMessage(), e);
        }
        return result;
    }

    public static Integer getOnlineCount() {
        return onLineUsers.size();
    }

}

把这个注解配置到方法上 就会被切面注入了。

另外如果报了这个错
Caused by: java.lang.IllegalArgumentException: error at ::0 can’t find referenced pointcut
有两种可能 一种jdk版本与aop不兼容
第二种 请检查你得pointcut 和 around 拼写有没有错误

你可能感兴趣的:(springboot,springboot,aop使用,springboot配置切面,springboot,切面编程,统计在线人数,Caused,by:)