八: 动态代理的几种实现方式及优缺点

本文详细介绍了JDK动态代理和CGLIB动态代理的原理及应用,通过具体代码示例展示了如何使用动态代理增强UserService接口的实现,以确保用户实体类在写入数据库前进行有效的校验。

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

  1. 动态代理

    在这里插入图片描述
    学的有点蒙,。。。。。后续再写吧。。。。。。

JDK 代码示例: 需求, user 实体类 值写入到数据库时, 校验name 长度不能小于1
无侵入性增强

  1. 有个接口 UserService
package com.enjoylearning.dynamic.proxy.jdk;

import com.enjoylearning.dynamic.proxy.User;

public interface UserService {
	
	void addUser(User user);

}
  1. 被增强的类必须要继承接口
package com.enjoylearning.dynamic.proxy.jdk;

import com.enjoylearning.dynamic.proxy.User;

public class UserServiceImpl implements UserService {

	@Override
	public final void addUser(User user) {
		System.out.println("用户数据入库成功,数据为:" + user.toString());
	}

}

3.拦截器

package com.enjoylearning.dynamic.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Logger;

import com.enjoylearning.dynamic.proxy.User;

public class UserServiceInterceptor implements InvocationHandler{

	private Object realObj;
	
	private static Logger logger = Logger.getLogger(UserServiceInterceptor.class.getName());
	
	public Object getRealObj() {
		return realObj;
	}

	public void setRealObj(Object realObj) {
		this.realObj = realObj;
	}


	public UserServiceInterceptor(Object realObj) {
		super();
		this.realObj = realObj;
	}


	public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
		if(args!=null && args.length>0 && args[0] instanceof User){
			User user = (User) args[0];
			if(user.getName().trim().length()<=1){
				throw new RuntimeException("用户姓名输入长度需要大于1!");
			}
		}
		Object ret = method.invoke(realObj, args);
		logger.info("数据库操作成功!");
		return ret;
	}
	
	

}

4.测试方法

package com.enjoylearning.dynamic.proxy.jdk;

import java.lang.reflect.Proxy;

import com.enjoylearning.dynamic.proxy.User;

public class Client {

	public static void main(String[] args) {
		User user = new User();
		user.setAddress("地址");
		user.setAge(20);
		user.setName("1ison");
		UserService us = new UserServiceImpl();
		UserServiceInterceptor usi = new UserServiceInterceptor(us);
		//1.类加载器
		//2. 服务接口信息
		//3. invocationhandler 本身
		UserService proxy = (UserService) Proxy.newProxyInstance(us.getClass().getClassLoader(), us.getClass().getInterfaces(), usi);
		//通过动态代理增强业务
		proxy.addUser(user);
//		System.out.println("---------------------");
//		System.out.println(proxy.hashCode());
	}
}

CGLIB 动态代理

在这里插入图片描述
1.被增强的 方法, 不需要继承接口

package com.enjoylearning.dynamic.proxy.cglib;

import com.enjoylearning.dynamic.proxy.User;

public class UserServiceImpl {
	


	public final void addUser(User user) {
		System.out.println("用户数据入库成功,数据为:"+user.toString());
	}

}

2.拦截器 实现intercept 方法

package com.enjoylearning.dynamic.proxy.cglib;

import java.lang.reflect.Method;
import java.util.logging.Logger;

import com.enjoylearning.dynamic.proxy.User;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class UserServiceInterceptor implements MethodInterceptor {

	private static Logger logger = Logger.getLogger(UserServiceInterceptor.class.getName());

	public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
		if(args!=null && args.length>0 && args[0] instanceof User){
			User user = (User) args[0];
			if(user.getName().trim().length() <= 1){
				throw new RuntimeException("用户姓名输入长度需要大于1!");
			}
		}
		Object ret = proxy.invokeSuper(obj, args);
		logger.info("数据库操作成功!");
		return ret;
	}

}

  1. 测试类
package com.enjoylearning.dynamic.proxy.cglib;

import com.enjoylearning.dynamic.proxy.User;

import net.sf.cglib.proxy.Enhancer;

public class Client {
	
	public static void main(String[] args) {
		User user = new User();
		user.setAddress("地址");
		user.setAge(20);
		user.setName("lison");
		Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class);
        enhancer.setCallback(new UserServiceInterceptor());
        UserServiceImpl usi1 = (UserServiceImpl) enhancer.create();
        usi1.addUser(user);
//		System.out.println("---------------------");
//		System.out.println(usi.hashCode());
        
//        UserServiceImpl us = new UserServiceImpl();
//        enhancer.setCallback(new UserServiceDelegateInterceptor(us));
//        UserServiceImpl usi2 = (UserServiceImpl) enhancer.create();
//        usi2.addUser(user);
	}

}

在这里插入图片描述

<think>好的,我现在需要回答用户关于前端埋点实现方式及其优缺点的问题。首先,我得回忆一下之前提供的引用内容,看看有没有相关的信息可以引用。用户提到了引用1、2、3,其中引用3详细讨论了前端埋点SDK的实现,特别是私有化项目中的情况。用户的问题是要了解前端埋点的常见实现方式及各自的优缺点分析。根据我的知识,前端埋点主要有手动埋点、可视化埋点、全埋点(无埋点)三种方式。需要确认每种方式实现原理、适用场景以及优缺点。首先,手动埋点是最基础的方式,开发者需要在代码中插入埋点代码,比如在按钮点击事件里添加数据上报函数。优点是灵活、精准,但缺点是工作量大,维护成本高,容易出错。引用3中提到公司内部使用统一的埋点产品,可能涉及手动埋点,但后来私有化项目需要简化,可能转向更轻量的方案。 然后是可视化埋点,通过可视化工具配置埋点,无需修改代码。优点是减少开发量,适合非技术人员操作,但可能存在兼容性问题,不能覆盖所有场景。引用2提到埋点要追踪用户行为,可视化埋点可能在这方面受限,尤其是复杂的交互路径。全埋点则是自动采集所有用户行为,比如页面访问、点击等。优点是无需手动添加,数据全面,但缺点数据量大,冗余多,后期处理复杂。引用1中提到的埋点作用包括用户行为追踪,全埋点可能在这方面有优势,但需要处理大量数据。 另外,引用3提到在私有化项目中开发了一个轻量级SDK,可能结合了手动和简单的自动埋点,强调简洁和自定义存储。这说明在实际应用中,可能需要根据项目需求选择或混合不同的埋点方式。在整理回答时,需要结构清晰,分点说明每种方式优缺点对比,并适当引用提供的资料来支持分析。同时,确保使用正确的LaTeX格式,比如行内公式用$...$,独立公式用$$...$$,但在这个问题中可能涉及较少数学公式,但如果有提到数据量计算等,可能需要应用。不过当前问题可能不需要数学表达式,所以重点放在结构化和引用上。 最后,生成的相关问题需要围绕前端埋点的技术选型、优化方案、数据清洗等,确保问题与主题相关,帮助用户深入理解。</think>### 前端埋点的常见实现方式优缺点分析 前端埋点主要通过以下三种方式实现,每种方式在技术方案、适用场景和数据质量上存在差异: --- #### **1. 手动埋点(代码埋点)** **实现方式**:开发者在代码中**显式插入埋点逻辑**,例如在按钮点击、页面跳转等事件中调用数据上报函数。 **示例代码**: ```javascript button.addEventListener('click', () => { trackEvent('button_click', { page: 'home', button_id: 'submit' }); }); ``` **优点**: - **精准控制**:可针对特定事件或业务逻辑定制埋点[^1]; - **灵活性高**:支持复杂参数(如用户属性、页面状态)的传递[^2]; - **数据质量可靠**:直接关联业务逻辑,减少噪声数据。 **缺点**: - **开发成本高**:需修改代码并维护埋点逻辑,易与业务代码耦合[^3]; - **迭代困难**:需求变更时需重新发布版本(如App需审核); - **遗漏风险**:依赖人工操作,易漏埋关键事件。 --- #### **2. 可视化埋点(无代码埋点)** **实现方式**:通过**可视化工具**(如Mixpanel、GrowingIO)选择页面元素并配置埋点规则,由SDK自动监听事件。 **技术原理**: - 利用DOM事件代理监听用户交互; - 通过元素唯一标识(如XPath)关联埋点配置。 **优点**: - **零代码侵入**:非技术人员可直接操作,降低开发负担[^2]; - **快速迭代**:埋点配置实时生效,无需发版; - **兼容性强**:适用于多端(Web、H5、小程序)。 **缺点**: - **灵活性受限**:仅支持基础事件(点击、曝光),无法捕获动态参数; - **性能损耗**:全量监听页面元素可能影响页面加载速度; - **兼容性问题**:复杂页面结构(如动态渲染)可能导致埋点失效[^3]。 --- #### **3. 全埋点(无埋点)** **实现方式**:SDK**自动采集所有用户行为**(如点击、页面停留、滑动),无需手动配置。 **技术方案**: - 监听全局事件(如`click`、`pageview`); - 结合用户ID、设备信息生成行为日志。 **优点**: - **数据全面性**:覆盖所有用户行为,避免遗漏[^1]; - **实施成本低**:接入SDK后无需额外开发; - **回溯分析**:可基于历史数据挖掘新指标。 **缺点**: - **数据冗余**:产生大量无效数据,增加存储和分析成本; - **隐私风险**:需谨慎处理敏感信息(如表单内容); - **后期处理复杂**:需通过ETL清洗数据才能用于分析[^2]。 --- ### **技术选型建议** | **场景** | **推荐方案** | **关键考量** | |-----------------------|---------------------|--------------------------------| | 精细化运营(如转化率分析) | 手动埋点 | 数据精准性、参数定制化 | | 快速验证产品假设 | 可视化埋点 | 迭代速度、跨团队协作 | | 用户行为全链路追踪 | 全埋点 | 数据全面性、长期价值 | | 私有化部署(如低代码需求) | 轻量SDK(手动+自动化) | 数据存储自主性、性能与功能平衡[^3] | ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值