静态代理JDK和CGLib动态代理模式示例代码

Java两种动态代理JDK动态代理和CGLIB动态代理

静态代理(需要一个目标类写一个代理类)

使用代理模式可以在不影响原有代码(目标类方法)的情况下,增强功能逻辑

实现步骤

1. 相同接口
public interface Caculator {
    int add(int x,int y);
}
2. 目标类,实现接口
public class TargetCaculatorImpl implements Caculator{
    @Override
    public int add(int x, int y) {
        System.out.println("目标类方法执行了!");
        return x+y;
    }
}
3. 代理类,实现接口
public class ProxyCaculatorImpl implements Caculator{
	//持有目标类
    private TargetCaculatorImpl target;
    public ProxyCaculatorImpl(TargetCaculatorImpl target){
        this.target = target;
    }
    
    @Override
    public int add(int x, int y) {
        //目标类方法之前
        System.out.println("目标类方法之前:增强功能");
        
        //执行目标类方法
        int sum = targetCaculator.add(x, y);

        //目标类方法之后
        System.out.println("目标类方法之后:增强功能");
        return sum;
    }
}
4. 创建代理对象,传入目标对象
Caculator caculator = new ProxyCaculatorImpl(new TargetCaculatorImpl);
System.out.println(caculator.add(1,3));

动态代理(适用给不同类方法添加相同功能逻辑)

JDK动态代理

实现步骤
1.接口
public interface Caculator {
    int add(int x,int y);
    int multiply(int x,int y);
}
2.目标类,实现接口
public class TargetCaculatorImpl implements Caculator {
    //方法只返回两数之和
    @Override
    public int add(int x, int y) {
        System.out.println("目标类方法执行了");
        return x+y;
    }
    @Override
    public int multiply(int x, int y) {
        System.out.println("目标类multiply方法执行了");
        return x*y;
    }
}
3.创建包装类,实现InvocationHandler接口,重写方法
//包装类
public class MyProxy implements InvocationHandler {
    private Object target;  //目标对象,任意类型
    public MyProxy(Object target){
        this.target = target;
    }
    
    //自定义方法:返回目标类的代理类实例对象
    public Object getProxyInsatnce(){
        //JDK提供的newProxyInstance(ClassLoader,Interface,InvocationHandler)方法
        //获取目标类的接口信息,就可以获得目标类信息,主要是目标类方法
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }
    
    
    //所有Target的所有方法的调用入口(invoke)
    //执行目标类的方法,在方法前后可以添加功能,不影响原有方法执行
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
        System.out.println("方法前操作:");
        
        //获得目标类方法,执行结果
        Object result = method.invoke(target,args);

        System.out.println("方法后操作:");
        return result;
    }

}
4.创建包装类,生产代理类,调用方法
//创建包装类对象
MyProxy myProxy = new MyProxy(new TargetCaculatorImpl());
//获得目标类的代理类对象
Caculator caculator = (Caculator) myProxy.getProxyInsatnce();
//执行接口方法(目标类和代理类的方法都执行)
System.out.println(caculator.add(11,3));
method.getName()

可以获取方法名最当前方法做判断,是否添加逻辑,调用时加try,catch捕获空指针异常

CGLib动态代理(无需接口)

通过“继承”可以继承父类所有的公开方法,然后可以重写这些方法,在重写时对这些方法增强,这就是cglib的思想。

1. 创建目标类
public class TargetCaculator {
    public int add(int x,int y){
        return x+y;
    }
    public int multiply(int x,int y){
        return x*y;
    }
}
2. 创建Cglib动态代理类,实现MethodInterceptor接口

cglib之Enhancer

public class CglibProxy implements MethodInterceptor {

    public Object createProxyInstance(Class<?> clazz){
    	//字节码增强器,可以用来为无接口的类创建代理。
    	//它的功能与java自带的Proxy类挺相似的。
    	//它会根据某个给定的类创建子类,并且所有非final的方法都带有回调钩子。
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("增强");
        return methodProxy.invokeSuper(o,objects);
    }
}
区别

经测试,jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。
cglib执行速度略大于jdk,所以比较适合单例模式。
另外由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。
如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。
spring默认使用jdk动态代理,如果类没有接口,则使用cglib。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值