当前位置:首页 > CN2资讯 > 正文内容

Java动态代理、cglib动态代理java动态代理

2天前CN2资讯


说动态代理,需要先清楚静态代理。所谓静态代理就是程序员提前实现好的代理类,编译后class文件是已经存在的。

实现原理,利用Java代理模式,由一个代理类持有委托类的实例,并实现委托类一样的接口,来实现增强方法的目的。

我们主要用它来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情,甚至根本不去执行这个方法。因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象。比如可以添加调用日志,做事务控制,对方法进行缓存等。

Spring容器代替工厂,Spring AOP代替JDK动态代理,让面向切面编程更容易实现。在Spring的帮助下轻松添加,移除动态代理,且对源代码无任何影响。

本文给出静态代理、JDK动态代理、CGLIB动态代理的三种例子。

一、静态代理

在了解代理模式的情况下看下面的代码,没什么可说的。

package com.shanhy.demo.proxy;

public interface Account {

public void queryAccount();

public void updateAccount();

}package com.shanhy.demo.proxy;

public class AccountImpl implements Account {

@Override
public void queryAccount() {
System.out.println("查看账户");
}

@Override
public void updateAccount() {
System.out.println("修改账户");
}

}package com.shanhy.demo.proxy;

public class AccountProxy implements Account {

private Account account;

public AccountProxy(Account account) {
super();
this.account = account;
}

@Override
public void queryAccount() {
System.out.println("代理before");
account.queryAccount();
System.out.println("代理after");
}

@Override
public void updateAccount() {
System.out.println("代理before");
account.updateAccount();
System.out.println("代理after");
}

}package com.shanhy.demo.proxy;

public class AccountProxyTest {

public static void main(String[] args) {
// AccountProxy为自己实现的代理类,可以发现,一个代理类只能为一个接口服务。
Account account = new AccountImpl();
AccountProxy proxy = new AccountProxy(account);
proxy.queryAccount();
proxy.updateAccount();
}
}

二、JDK动态代理

使用JDK动态代理使用到一个Proxy类和一个InvocationHandler接口。

Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它仅支持interface代理(也就是代理类必须实现接口),因为它的设计注定了这个遗憾。

package com.shanhy.demo.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class AccountProxyFactory implements InvocationHandler {

private Object target;

public Object bind(Object target){
// 这里使用的是Jdk的动态代理,其必须要绑定接口,在我们的业务实现中有可能是没有基于接口是实现的。所以说这个缺陷cglib弥补了。
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println(Proxy.isProxyClass(proxy.getClass()));
boolean objFlag = method.getDeclaringClass().getName().equals("java.lang.Object");

Object result = null;
if(!objFlag)
System.out.println("代理before");
result = method.invoke(this.target, args);
if(!objFlag)
System.out.println("代理after");
return result;
}


}package com.shanhy.demo.proxy;

public class AccountProxyTest {

public static void main(String[] args) {
// 下面使用JDK的代理类,一个代理就可以代理很多接口
Account account1 = (Account)new AccountProxyFactory().bind(new AccountImpl());
System.out.println(account1);
account1.queryAccount();
}

三、CGLIB动态代理

对于上面说到JDK仅支持对实现接口的委托类进行代理的缺陷,这个问题CGLIB给予了很好的补位,解决了这个问题,使其委托类也可是非接口实现类。

CGLIB内部使用到ASM,所以我们下面的例子需要引入asm-3.3.jar、cglib-2.2.2.jar

package com.shanhy.demo.proxy;

import java.lang.reflect.Method;

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

public class AccountCglibProxyFactory implements MethodInterceptor{

private Object target;

public Object getInstance(Object target){
this.target = target;
return Enhancer.create(this.target.getClass(), this);

// Enhancer enhancer = new Enhancer();//该类用于生成代理对象
// enhancer.setSuperclass(this.target.getClass());//设置父类
// enhancer.setCallback(this);//设置回调用对象为本身
// return enhancer.create();
}

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 排除Object类中的toString等方法
boolean objFlag = method.getDeclaringClass().getName().equals("java.lang.Object");
if(!objFlag){
System.out.println("before");
}
Object result = null;
// 我们一般使用proxy.invokeSuper(obj,args)方法。这个很好理解,就是执行原始类的方法。还有一个方法proxy.invoke(obj,args),这是执行生成子类的方法。
// 如果传入的obj就是子类的话,会发生内存溢出,因为子类的方法不挺地进入intercept方法,而这个方法又去调用子类的方法,两个方法直接循环调用了。
result = methodProxy.invokeSuper(obj, args);
// result = methodProxy.invoke(obj, args);
if(!objFlag){
System.out.println("after");
}
return result;
}

}package com.shanhy.demo.proxy;

public class Person {

public void show(){
System.out.println("showing");
}
}package com.shanhy.demo.proxy;

public class AccountProxyTest {

public static void main(String[] args) {
// 下面是用cglib的代理
// 1.支持实现接口的类
Account account2 = (Account)new AccountCglibProxyFactory().getInstance(new AccountImpl());
account2.updateAccount();

// 2.支持未实现接口的类
Person person = (Person)new AccountCglibProxyFactory().getInstance(new Person());
System.out.println(person);
person.show();
}
}



    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/24006.html

    分享给朋友:

    “Java动态代理、cglib动态代理java动态代理” 的相关文章

    探索锡考克斯:舒适的居住地与丰富的旅游体验

    锡考克斯(Secaucus)是一个坐落于新泽西州的小镇,距离繁华的纽约市仅有不到10公里的路程。这使得锡考克斯成为一个非常吸引人的居住地和旅游目的地。首先,锡考克斯的地理坐标是纬度40.782和经度-74.0676,位于北纬40°46′55″和西经74°4′3″之间。这种优越的地理位置无疑为它的经济...

    莱卡云:高性价比云服务器解决方案,助力企业发展

    莱卡云概述 莱卡云,这个名字你或许已经听说过。成立于2019年,它在云计算服务领域迅速崭露头角,成为一些企业的首选合作伙伴。凭借持有的多个《中华人民共和国增值电信业务经营许可证》,莱卡云有效地展开了多种多样的服务,充分满足了市场需求。与三大公有云的合作让它在竞争激烈的市场中站稳了脚跟,提供的解决方案...

    物语云:为游戏行业提供高效安全的云计算解决方案

    物语云概述 物语云是北京物语云联网络科技有限公司旗下的云计算品牌。这一品牌专注于为游戏行业提供一系列数据中心基础服务和互联网业务解决方案,其产品线包括专属服务器租用、云服务器、虚拟主机、服务器托管及带宽租用等。物语云的目标在于为客户提供高效、安全、经济的云计算服务,从而帮助他们在激烈的市场竞争中立足...

    服务器租用的全面指南:如何选择和管理最合适的服务器

    1. 服务器租用概述 服务器租用是许多企业和个人在建设网站或部署应用时的首选方式,指的是用户支付一定的费用来获得服务器的使用权。这样的模式让用户不需要高额的初始投资,可以随时按需租用相应配置的服务器。这在当今快速发展的数字时代尤为重要,无论是初创企业还是成熟企业,都能从中获得灵活性和成本效益。 想象...

    如何使用Windows网络诊断工具查找服务器地址和解决网络问题

    在当今这个网络无处不在的时代,能够快速诊断网络问题已变得尤为重要。作为Windows用户,我们的设备中自带了一个非常实用的工具——Windows网络诊断工具。说到这个工具,许多人可能不太了解它的具体功能和用途。 Windows网络诊断工具是一个集成在Windows操作系统中的应用,专门用于帮助用户识...

    搬瓦工the plan限量版套餐详解:高性能与性价比的完美结合

    搬瓦工the plan限量版套餐概述 当我第一次听说搬瓦工的“the plan”限量版套餐时,心里忍不住很好奇。这种套餐究竟有什么特别之处?在我深入了解后,发现它不仅仅是一个普通的套餐,而是经过精心设计,专为追求高性能和稳定性的用户打造的。它的背景源于搬瓦工希望为用户提供更优质的服务,满足日益增长的...