Hook~Java用钩子实现代码注入(埋点方案)

本文介绍了一种基于SpringBoot的功能插件机制实现方案。通过FunctionPluginManager管理器统一管理各类业务插件,并利用Functionable抽象类规范插件行为。文章详细展示了插件的生命周期管理及如何针对不同业务场景(如购买会员、用户注册)动态加载和执行相应的业务逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


公共Hook文件:
1、FunctionPluginManager文件:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
public class FunctionPluginManager implements CommandLineRunner {

    @Autowired
    private ApplicationContext appContext;

    private static List<Functionable> plugins = new ArrayList<>();

    public static void processBeforeAction(BusinessPoint businessPoint, Object parameter) {
        plugins.stream().filter(b -> b.isEnable() && b.getBusinessPoint() == businessPoint).forEach(b -> b.before(parameter));
    }

    public static void processAfterAction(BusinessPoint businessPoint, Object parameter) {
        plugins.stream().filter(b -> b.isEnable() && b.getBusinessPoint() == businessPoint).forEach(b -> b.after(parameter));
    }


    @Override
    public void run(String... args) throws Exception {
        // 查找代码中所有Functionable的子类
        Map<String, Functionable> beans = appContext.getBeansOfType(Functionable.class);
        beans.forEach((key, bean) -> plugins.add(bean));

        // 倒叙排列,优先级高的先执行
        plugins.sort((s1, s2) -> {
            if (s1.getPriority() > s2.getPriority()) {
                return -1;
            } else if (s1.getPriority() == s2.getPriority()) {
                return 0;
            } else {
                return 1;
            }
        });
    }
}

2、Functionable文件:

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import org.apache.commons.lang3.StringUtils;

public abstract class Functionable<T, K> {

    /**
     * 插件名称
     * @return
     */
    public abstract String getName();

    /**
     * 插件优先级,数字越大优先级越高,优先级高的会先执行
     * @return
     */
    public abstract int getPriority();

    /**
     * 获取阿波罗中是否启用该插件的Key,需开发人员在子类中定义
     * @return
     */
    public abstract String getApolloEnableKey();

    public boolean isEnable() {
        Config config = ConfigService.getAppConfig();

        String key = this.getApolloEnableKey();
        String value = config.getProperty(key, "0");

        if (StringUtils.isBlank(value) || "0".equals(value) || "false".equals(value)) {
            return false;
        }
        return true;
    }

    /**
     * 业务注入点
     * @return
     */
    public abstract BusinessPoint getBusinessPoint();

    /**
     * 业务处理前
     * @param t
     */
    public abstract void before(T t);

    /**
     * 业务处理后
     * @param t
     */
    public abstract void after(K t);
}

3、BusinessPoint文件:

/**
 * 业务注入点
 */
public enum BusinessPoint {
    BUY_MEMBER, // 购买会员
    USER_REGIST // 用户注册
}

4、parameter相关参数文件:
4.1、BuyMemberParameter文件:

public class BuyMemberParameter {
    private Long userId;
    private Integer orderId;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Integer getOrderId() {
        return orderId;
    }

    public void setOrderId(Integer orderId) {
        this.orderId = orderId;
    }
}

4.2、RegisterParameter文件:

public class RegisterParameter {
    private Long userId;
    private String phone;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

用户服务相关埋点插件文件:
BuyMemberSendMemberPlugin文件:

import com.sxapp.commons.plugin.BusinessPoint;
import com.sxapp.commons.plugin.Functionable;
import com.sxapp.commons.plugin.parameter.BuyMemberParameter;
import com.sxapp.commons.util.DateUtil;
import com.sxapp.user.constant.RoleEnum;
import com.sxapp.user.dto.user.SendMemberRequest;
import com.sxapp.user.dto.user.UserRequest;
import com.sxapp.user.dto.user.UserRoleRequest;
import com.sxapp.user.service.IUserRoleService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class BuyMemberSendMemberPlugin extends Functionable<BuyMemberParameter, BuyMemberParameter> {
    @Reference
    private IUserRoleService iUserRoleService;
    /**
     * 时效性--开始时间
     */
    @Value("${plugin.buyMember.sendMember.startTime}")
    private String startTime;
    /**
     * 时效性--结束时间
     */
    @Value("${plugin.buyMember.sendMember.endTime}")
    private String endTime;
    /**
     * 活动唯一标识 UUID
     */
    private static final String uniqueCode = "b7d0d091-082d-4ef1-99d8-96a02a63cbb5";

    /**
     * 插件名称
     *
     * @return
     */
    @Override
    public String getName() {
        return "购买会员买一赠一活动";
    }

    /**
     * 插件优先级,数字越大优先级越高,优先级高的会先执行
     *
     * @return
     */
    @Override
    public int getPriority() {
        return 100;
    }

    /**
     * 获取阿波罗中是否启用该插件的Key,需开发人员在子类中定义
     *  plugin.buyMember.sendMember.enable
     *  1开启 0关闭
     * @return
     */
    @Override
    public String getApolloEnableKey() {
        return "plugin.buyMember.sendMember.enable";
    }

    /**
     * 业务注入点
     *
     * @return
     */
    @Override
    public BusinessPoint getBusinessPoint() {
        return BusinessPoint.BUY_MEMBER;
    }

    /**
     * 业务处理前
     *
     * @param buyMemberParameter
     */
    @Override
    public void before(BuyMemberParameter buyMemberParameter) {

    }

    /**
     * 业务处理后
     *
     * @param buyMemberParameter
     */
    @Override
    public void after(BuyMemberParameter buyMemberParameter) {
        Long uid = buyMemberParameter.getUserId();
        Long orderId = buyMemberParameter.getOrderId().longValue();
        Byte status = 0;
        Byte isSend = 1;
        String note = "购买会员买一赠一活动";
        /*
         * 活动时间范围
         * 时效性--开始时间
         * 时效性--结束时间
         */
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //开始时间
        long ts1 = 0;
        try {
            ts1 = simpleDateFormat.parse(startTime).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //结束时间
        long ts2 = 0;
        try {
            ts2 = simpleDateFormat.parse(endTime).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //当前时间
        long ts3 = System.currentTimeMillis();
        if (ts1 <= ts3 && ts2 > ts3) {
            //判断是否参加过活动
            SendMemberRequest sendMemberRequest = new SendMemberRequest();
            sendMemberRequest.setUid(uid);
            sendMemberRequest.setUniqueCode(uniqueCode);
            boolean resCan = iUserRoleService.isSendMember(sendMemberRequest);
            if (!resCan) {
                /*
                 * 会员到期时间增加1年
                 */
                UserRequest userRequest = new UserRequest();
                userRequest.setUid(uid);
                //获取用户角色过期时间
                Date expireTime = iUserRoleService.getExpireTime(userRequest);
                //更新用户角色表
                UserRoleRequest userRoleRequest = new UserRoleRequest();
                userRoleRequest.setRole(RoleEnum.MEMBER);
                userRoleRequest.setUid(uid);
                userRoleRequest.setNote(note);
                userRoleRequest.setExpireTime(DateUtil.getDateAfterYear(expireTime, 1));
                userRoleRequest.setStatus(status);
                userRoleRequest.setOrderId(orderId);
                userRoleRequest.setIsSend(isSend);
                userRoleRequest.setUniqueCode(uniqueCode);
                iUserRoleService.updateUserRole(userRoleRequest);
            }
        }
    }
}

RegisterSendMemberPlugin文件:

import com.sxapp.commons.plugin.BusinessPoint;
import com.sxapp.commons.plugin.Functionable;
import com.sxapp.commons.plugin.parameter.RegisterParameter;
import com.sxapp.commons.util.DateUtil;
import com.sxapp.user.constant.RoleEnum;
import com.sxapp.user.dto.user.SendMemberRequest;
import com.sxapp.user.dto.user.UserRequest;
import com.sxapp.user.dto.user.UserRoleRequest;
import com.sxapp.user.service.IUserRoleService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class RegisterSendMemberPlugin extends Functionable<RegisterParameter, RegisterParameter> {
    @Reference
    private IUserRoleService iUserRoleService;
    /**
     * 时效性--开始时间
     */
    @Value("${plugin.register.sendMember.startTime}")
    private String startTime;

    /**
     * 时效性--结束时间
     */
    @Value("${plugin.register.sendMember.endTime}")
    private String endTime;


    /**
     * 赠送的天数
     */
    @Value("${plugin.register.sendMember.days}")
    private String days;

    /**
     * 活动唯一标识 UUID
     */
    private static final String uniqueCode = "479e278c-2364-40dd-8286-05b427e43fd6";

    /**
     * 插件名称
     *
     * @return
     */
    @Override
    public String getName() {
        return "新注册用户赠送" + days + "天会员";
    }

    /**
     * 插件优先级,数字越大优先级越高,优先级高的会先执行
     *
     * @return
     */
    @Override
    public int getPriority() {
        return 99;
    }

    /**
     * 获取阿波罗中是否启用该插件的Key,需开发人员在子类中定义
     * 	plugin.register.sendMember.enable
     * 	1开启 0关闭
     * @return
     */
    @Override
    public String getApolloEnableKey() {
        return "plugin.register.sendMember.enable";
    }

    /**
     * 业务注入点
     *
     * @return
     */
    @Override
    public BusinessPoint getBusinessPoint() {
        return BusinessPoint.USER_REGIST;
    }

    /**
     * 业务处理前
     *
     * @param registerParameter
     */
    @Override
    public void before(RegisterParameter registerParameter) {

    }

    /**
     * 业务处理后
     *
     * @param registerParameter
     */
    @Override
    public void after(RegisterParameter registerParameter) {
        Long uid = registerParameter.getUserId();
        Long orderId = 0L;
        Byte status = 0;
        Byte isSend = 1;
        String note = this.getName();
        /*
         * 活动时间范围
         * 时效性--开始时间
         * 时效性--结束时间
         */
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //开始时间
        long ts1 = 0;
        try {
            ts1 = simpleDateFormat.parse(startTime).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //结束时间
        long ts2 = 0;
        try {
            ts2 = simpleDateFormat.parse(endTime).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //当前时间
        long ts3 = System.currentTimeMillis();
        if (ts1 <= ts3 && ts2 > ts3) {
            //判断是否参加过活动
            SendMemberRequest sendMemberRequest = new SendMemberRequest();
            sendMemberRequest.setUid(uid);
            sendMemberRequest.setUniqueCode(uniqueCode);
            boolean resCan = iUserRoleService.isSendMember(sendMemberRequest);
            if (!resCan) {
                /*
                 * 新注册用户赠送7天会员活动
                 */
                UserRequest userRequest = new UserRequest();
                userRequest.setUid(uid);
                //获取用户角色过期时间
                Date expireTime = iUserRoleService.getExpireTime(userRequest);
                //更新用户角色表
                UserRoleRequest userRoleRequest = new UserRoleRequest();
                userRoleRequest.setRole(RoleEnum.MEMBER);
                userRoleRequest.setUid(uid);
                userRoleRequest.setNote(note);
                userRoleRequest.setExpireTime(DateUtil.getDateAfterDay(expireTime, 7));
                userRoleRequest.setStatus(status);
                userRoleRequest.setOrderId(orderId);
                userRoleRequest.setIsSend(isSend);
                userRoleRequest.setUniqueCode(uniqueCode);
                iUserRoleService.updateUserRole(userRoleRequest);
            }
        }
    }
}

KafkaOrderNotifyConsumer文件:
主要相关引用代码:

@Component
public class KafkaOrderNotifyConsumer {	
	// 先构建参数
	BuyMemberParameter buyMemberParameter = new BuyMemberParameter();
	buyMemberParameter.setUserId(orderInfoResponse.getUid());
	buyMemberParameter.setOrderId(orderInfoResponse.getId());
	// 执行功能插件链中的所有功能
	FunctionPluginManager.processBeforeAction(BusinessPoint.BUY_MEMBER, buyMemberParameter);
   // TODO: 2020/9/22  
	// 执行功能插件链中的所有功能
	FunctionPluginManager.processAfterAction(BusinessPoint.BUY_MEMBER, buyMemberParameter);

UserAccountServiceImpl文件:
主要相关引用代码:

@Service(timeout = 10000)
public class UserAccountServiceImpl implements IUserAccountService {
	// 先构建参数
	RegisterParameter registerParameter = new RegisterParameter();
	registerParameter.setPhone(account);
	// 执行功能插件链中的所有功能
	FunctionPluginManager.processBeforeAction(BusinessPoint.USER_REGIST, registerParameter);
	// TODO: 2020/9/22  
	// 执行功能插件链中的所有功能
	FunctionPluginManager.processAfterAction(BusinessPoint.USER_REGIST, registerParameter);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值