egret+java小游戏服务端07-lombok引入及整合Spring实现的AOP日志


前言

前言

服务端GitHub地址:https://github.com/griii/Hak-Server
小游戏网址:https://www.guorii.cn/hak

一、引入lombok

pom依赖

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
</dependency>

注意,lombok引入的版本过低会和maven打包版本不匹配出现无法打包的问题:
在这里插入图片描述
将lombok改为新版即可解决。

<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
</dependency>

idea配置

在Setting-Plugins中下载安装lombok相关支持即可

@Date、@Slf4j使用

在entity类上添加
@Date注解,lombok将自动生成getter、setter方法

@Data
public abstract class PlayerPeople implements IPlayer {

    private double x;
    private double y;
    private int uid;
    private int token;
    private String name;
    private boolean move = false;
    private double angle;
    private float speed = 30;
    private long time;

二、AOP配置

pom文件引入AOP

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

配置AOP类

先创建LogInstructAspect类,这里的@Slf4j注解由lombok提供,将会自动注入一个log对象


@Aspect
@Slf4j
@Component
public class LogInstructAspect {
}

加入切点

@Pointcut("execution(* com.guorui.hak.entity.instruct..*.*(..))")
    public void instructLog(){
    }

切点匹配语法:

 *:匹配任何数量字符;

 ..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。

 +:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

由于需要方法参数来输出,因此使用@Around环绕切面

@Around("instructLog()")
    public void aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
        StringBuilder logInfor = new StringBuilder();
        joinPoint.proceed();//先执行
        //System.out.println("切面执行...");
        for (Object arg : joinPoint.getArgs()) {
            if (arg instanceof Instruct){
                Instruct ins = (Instruct)arg;
                logInfor.append("用户: [" + ins.getRoomId() + ":" + ins.getUid() + "]" +  "执行:" + ((Instruct) arg).getOrder());
            }else if(arg instanceof PlayerPeople){
                log.info(logInfor + "用户状态:{}",arg.toString());
            }
        }
    }

但是这里出现了一个很严重的问题:由于之前netty的handler并没有作为Spring的组件,因此后续的MsgManage以及Strategy都无法正常调用。

之后将整个netty注册流程均以组件的形式运行,并且把策略的初始化方式交由Spring的IOC实现,通过注入ApllicationContext获取。

@Component
public class MsgManage{

    @Autowired
    private ApplicationContext applicationContext;

    private static final String STRATEGY = "Strategy";

    public void addInstruct(Instruct instruct) throws NoSuchMethodException {
        //instructs.offer(instruct);
        //对指令解析order后调用对应Player的对应逻辑函数
        PlayerPeople player = Room.players.get(instruct.getUid()+"");
        if (player == null){
            System.out.println("没有找到该用户!");
            return;
        }
        String order = instruct.getOrder();
        try {
            //通过Spring的BeanFactory获取
            String strategyName = order + STRATEGY;
            System.out.println(applicationContext.getBean("moveStrategy"));
            InstructStrategy is = (InstructStrategy) applicationContext.getBean(order + STRATEGY);
            //InstructStrategy is = (InstructStrategy)(Class.forName("com.guorui.hak.entity.instruct.strategy.impl." + strategyName).getConstructor().newInstance());
            is.instructOrder(instruct,player);
            //player.getClass().getMethod(order, Instruct.class).invoke(player,instruct);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("指令调用失败!该用户没有使用该指令的权限!");
        }
    }
  }

原先的策略的调用是通过反射获取构造器每次新建一个对象来调用,一方面客户端需要注重于构造策略,另一方面每次都需要构造出一个新的实例(原先应当用单例模式更好一些),但使用Spring就摈弃了这些劣势,这个改动非常好的体现了Spring的IOC的好处。

测试后切面日志成功执行
在这里插入图片描述

但显然,这里输出的信息太过繁琐了,主要是用户状态过多,先重写用户的toString方法

@Override
    public String toString() {
        return "[" +
                String.format("%5.2f",x) + "," +
                String.format("%5.2f",y) + "]" + "{" +
                (move?"T":"F") + "," +
                String.format("a:%3.1f",angle) +
                ",s:" + speed +
                '}';
    }

在这里插入图片描述

这样就简洁多了。

另外,没有配置输出到日志文件中持久化,因此还需要配置logback

配置logback的xml文件

在resource目录下创建logback-spring.xml文件
先配置一个简单的

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="/HakLogHome" />
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level- %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 按照每天生成日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/HakLog%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <!--日志文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>1000MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>

    <root level="INFO">
        <appender-ref ref="FILE" />
    </root>
</configuration>

在这里插入图片描述

成功输出在txt文件中了,但是SpringBoot启动时的日志也输出在文件中了,应当配置使得玩家的操作日志输出与其他日志隔离,仅输出在一个文件中。

<appender name="PLAYER_INSTRUCT" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${LOG_HOME}/HakPlayerInstructLog%d{yyyy-MM-dd}.log</FileNamePattern>
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern>
        </encoder>
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>1000MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!-- 默认控制台日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>

    <!-- 玩家指令专属的日志输出 -->
    <logger name="com.guorui.hak.config.aspectConfig.LogInstructAspect" level="INFO" additivity="false">
        <appender-ref ref="PLAYER_INSTRUCT" />
    </logger>

在这里插入图片描述
成功输出了简洁明了并且与其他日志隔离的日志文件,并且控制台不再输出该日志。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值