专业的编程技术博客社区

网站首页 > 博客文章 正文

Java代理那些事儿之CGLIB代理模式及几种代理的性能PK

baijin 2024-09-04 02:03:19 博客文章 10 ℃ 0 评论

1、JDK 动态代理的问题

JDK 动态代理要求真实类必须实现接口。而 CGLIB 与 JDK 动态代理不同是,真实类不用实现接口,生成代理类的代码不一样且代理类会继承真实类。

2、CGLIB 动态代理 API

org.springframework.cglib.proxy.Enhancer,类似 JDK 中 Proxy,用来生成代理类创建代理对象的。

org.springframework.cglib.proxy.InvocationHandler,类似 JDK 中 InvocationHandler,让使用者自定义做什么事情,对原来方法增强。

3、操作步骤

3.1、修改 TransactionHandler 实现 org.springframework.cglib.proxy.InvocationHandler 接口,其他不变。

3.2、修改单元测试类中的测试方法,改用 Enhancer 来生成代理类创建代理对象的。

4、代码实现

代理执行处理器类:

@Component(value="txx")
public class TxInvocationHandler implements org.springframework.cglib.proxy.InvocationHandler{
	@Autowired
	private Object service;
	
	public Object getService() {
		return service;
	}

	@Autowired
	private MyTx tx;
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object ret = null;
		tx.begin();
		try {
			ret = method.invoke(service, args);
			tx.commit();
		} catch (Exception e) {
			tx.rollback();
		}
		return ret;
	}
	
}

其他的组件和JDK动态代理一样!参考上篇文章《Java代理那些事儿(中)》

测试用例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-cglib_proxy.xml")
public class Cglib_ProxyTest {
	//注入代理执行处理器对象
	@Autowired
	private TxInvocationHandler handler;
	@Test
	public void testCglib_Proxy() {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(handler.getService().getClass().getClass());//设置代理类的父类对象为真实对象
		enhancer.setCallback(handler);//设置真实对象方法增强
		EmployeeServiceImpl proxy = (EmployeeServiceImpl)enhancer.create();//根据提供的条件生成动态代理类及其对象
		proxy.save("HelloWorld!");//调用代理对象方法
		proxy.update("HelloWorld!");
	}

}

5、调用流程

动态代理总结

1、动态代理图示:

2、JDK动态代理总结

2.1、Java 动态代理是使用 java.lang.reflect 包中的 Proxy 类与 InvocationHandler 接口这两个来完成的。

2.2、要使用 JDK 动态代理,真实类必须实现接口。

2.3、JDK 动态代理将会拦截所有 pubic 的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。

2.4、动态代理的最小单位是类(类中某些方法都会被处理),如果只想拦截一部分方法,可以在 invoke 方法中对要执行的方法名进行判断。

3、CGLIB 动态代理总结

3.1、CGLIB 可以生成真实类的子类,并重写父类非 final 修饰符的方法。

3.2、要求类不能是 final 的,要拦截的方法要是非 final、非 static、非 private 的。

3.3、动态代理的最小单位是类(类中某些方法都会被处理),如果只想拦截一部分方法,可以在 invoke 方法中对要执行的方法名进行判断。

4、关于性能

JDK 动态代理是基于实现接口的,CGLIB 和 Javassit 是基于继承委托类的。

从性能上考虑:Javassit > CGLIB > JDK。

MyBatis 延迟加载对象,采用的是 Javassit 的方式。

对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统,也更符合面向接口编程规范。

若委托类实现了接口,优先选用 JDK 动态代理。

若委托类没有实现任何接口,使用 Javassit 和 CGLIB 动态代理。

动态代理问题:对多个 service 对象增强配置太多,还有要手动创建代理对象,在使用时不是面向接口,还要编写 InvocationHandler 接口的实现类。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表