由浅入深学习java的代理机制

java中的代理(静态代理与动态代理)

静态代理

静态代理通常用于对原有业务逻辑的扩充,其实也就是代理模式的一种实现,通过对真实对象的封装,来实现扩展性。

缺点:同时代理多个方法时候冗余。

class StaticUserDaoProxy implements IUserDao {
    //接收保存目标对象
    private IUserDao target;

    public StaticUserDaoProxy(IUserDao target) {
        this.target = target;
    }

    public void save() {
        System.out.println("before StaticUserDaoProxy...");
        target.save();//执行目标对象的方法
        System.out.println("after StaticUserDaoProxy...");
    }
}

动态代理

动态代理的好处:实现无侵入式的代码扩展,也就是方法的增强,也就是说让程序员在不用修改源码的情况下,增强一些方法;

(1)jdk动态代理:

jdk动态代理是通过实现java中的InvocationHandler通过反射的方式来进行方法的调用。

//定义接口
public interface Subject {
    public void doSomething();
}
//要被代理的类
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("call doSomething()");
    }
}
//代理类
public class ProxyHandler implements InvocationHandler {

    private Object tar;

    public Object bind(Object tar)
    {
        this.tar = tar;
        //绑定该类实现的所有接口,取得代理类
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
    {
        Object result = null;
        //这里就可以进行所谓的AOP编程了
        //在调用具体函数方法前,执行功能处理
        System.out.println("start time:"+System.currentTimeMillis());
        result = method.invoke(tar,args);
        //在调用具体函数方法后,执行功能处理
        System.out.println("end time:"+System.currentTimeMillis());
        return result;
    }
}
//测试类
public class TestDynamicProxy {
    public static void main(String args[]){
        ProxyHandler proxy = new ProxyHandler();
        //绑定该类实现的所有接口
        Subject sub = (Subject) proxy.bind(new RealSubject());
        sub.doSomething();
    }
}

上面的main方法代码中,有proxy.bind()的方法调用了Proxy类的静态方法newProxyInstance()。proxy类中的newProxyInstance方法就是在创建代理类实例对象。

Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);

newProxyInstance有三个参数:

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h>

  • loader,被代理类的类加载器。
  • interfaces,被代理的类所实现的接口,这个接口可以是多个。
  • h,绑定代理类的一个方法。

具体的来说,这个方法执行了下面三步:

1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。

2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的实现类传入,自定义的InvocationHandler中的invoke方法里放入需要增强的功能。

3.返回这个代理类实例,因为我们构造的代理类实现了参数中的接口组,可以将newProxyInstance生成的对象强制转换为被代理对象的接口实现类。这也是jdk代理会出现的弊端,被代理的类必须实现了接口,否则无法被动态代理。

(2)cglib动态代理:

CGLIB与JDK代理不同,是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。 

//首先定义业务类,无需实现接口
public class BookFacadeImpl1 {  
    public void addBook() {  
        System.out.println("新增图书...");  
    }  
} 
//实现 MethodInterceptor方法代理接口,创建代理类
public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;//业务类对象,供代理方法中进行真正的业务方法调用
  
    //相当于JDK动态代理中的绑定
    public Object getInstance(Object target) {  
        this.target = target;  //给业务对象赋值
        Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类
        enhancer.setSuperclass(this.target.getClass());  //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this); 
       // 创建动态代理类对象并返回  
       return enhancer.create(); 
    }
    // 实现回调方法 
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
        System.out.println("预处理——————");
        proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
        System.out.println("调用后操作——————");
        return null; 
    }
//创建业务类和代理类对象,然后通过代理类对象.getInstance(业务类对象)  返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。最后通过动态代理类对象进行方法调用。
public static void main(String[] args) {      
        BookFacadeImpl1 bookFacade=new BookFacadeImpl1();
        BookFacadeCglib  cglib=new BookFacadeCglib();  
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(bookFacade);  
        bookCglib.addBook();  
    }  

(3)两种方式的比较

jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。

JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;

CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值