Java 动态代理以及Cglib代理

代理为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式通常也作为AOP(面向切面编程)的底层技术实现。通过AOP可以有效的降低模块间的耦合,也可以进一步补充了OOP。

Java本身提供了Proxy和InvocationHandler实现了动态的代理。

InvocationHandler接口中声明了一个方法:

   /**
     * @param proxy 被代理的对象
     * @param method 要调用的方法
     * @param args 调用方法所需的参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;

Proxy,通过该类配合InvocationHandler可以生成目标对象的代理。

/**
     *
     * @param loader 被代理对象的类加载器
     * @param interfaces 被代理对象所实现的接口
     * @param h 方法调用处理器
     * @return
     * @throws IllegalArgumentException
     */
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
            throws IllegalArgumentException


代码示例:

首先定义一个接口,Animal:包含吃东西和睡觉两个动作。

package org.antstudio;

/**
 * Created by Gavin on 14-7-27.
 */
public interface Animal {

    public void eat();
    public void sleep();

}


然后定义一个Person,实现Animal接口:

package org.antstudio;

/**
 * @author Gavin
 * @date 14-7-27 下午2:09
 */
public class Person implements Animal{

    private String name;

    public Person(String name){
        this.name = name;
    }
    public void eat(){
        System.out.println(name+" Eating...");
    }

    public void sleep(){
        System.out.println(name+" Sleeping...");
    }

}


Person代理类:

package org.antstudio.proxy;

import org.antstudio.Animal;
import org.antstudio.Person;

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

/**
 * @author Gavin
 * @date 14-7-27 13:45
 */
public class SimpleProxy implements InvocationHandler{

    private Object target;

    public Animal getProxy(Animal o){
        this.target = o;
        return (Animal)Proxy.newProxyInstance(o.getClass().getClassLoader(), new Class[]{Animal.class}, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        System.out.println("Simple Proxy before method:"+methodName);
        Object result = method.invoke(target,args);
        //这里如果使用proxy来处理方法的调用会抛出异常,因为proxy方法的调用,会触发拦截器,而拦截器又会触发方法调用,产生死循环
        System.out.println("Simple Proxy after method:"+methodName);
        return result;
    }

    public static void main(String[] args) throws IOException {
        Person person = new Person("Gavin");
        Animal proxy = new SimpleProxy().getProxy(person);
        proxy.eat();
        proxy.sleep();

    }
}


输出:

Simple Proxy before method:eat
Gavin Eating...
Simple Proxy after method:eat
Simple Proxy before method:sleep
Gavin Sleeping...
Simple Proxy after method:sleep

可以看到,调用代理Person的方法,都会经过InvocationHandler里的invoke方法。 

Proxy.newProxyInstance 创建的代理类是class sun.proxy.$Proxy,它具有所有Person的方法,其方法内部则是直接调用InvocationHandler.invoke(xxx)函数。


Cglib动态代理,Java本身提供的动态代理使用也很方便,但有一个缺点,就是被代理的对象必须实现接口。也就是说Java本身的代理不能代理没有实现接口的对象。Cglib是基于ASM字节码操作框架的动态代理生成框架。它可以对没有接口实现的对象进行代理。

Cglib需要使用MethodInterceptor方法拦截器进行,示例代码如下:

AnimalMethodInterceptor 定义一个Animal方法的拦截器:

package org.antstudio.proxy;

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

import java.lang.reflect.Method;

/**
 * @author Gavin
 * @date 14-7-27 下午4:43
 */
public class AnimalMethodInterceptor implements MethodInterceptor{


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib proxy before method:"+method.getName());
        Object result =  methodProxy.invokeSuper(o, objects);
        //如果这里调用  method.invoke(o,objects)-->会抛出异常,因为调用method时,会触发拦截器,在拦截器里又调用method,会产生死循环
        System.out.println("Cglib proxy after method:"+method.getName());
        return result;
    }
}

代理类:

package org.antstudio.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import org.antstudio.Person;

/**
 * @author Gavin
 * @date 14-7-27 下午5:05
 */
public class CglibProxy {

    private MethodInterceptor methodInterceptor;

    public CglibProxy(MethodInterceptor methodInterceptor){
        this.methodInterceptor = methodInterceptor;
    }

    public <T> T getProxy(T o){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(o.getClass());
        enhancer.setCallback(methodInterceptor);
        return (T) enhancer.create(new Class[]{String.class},new Object[]{"Gavin"});
    }

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy(new AnimalMethodInterceptor());
        Person person = (Person) cglibProxy.getProxy(new Person("Gavin"));
        person.eat();
    }
}

输出:

Cglib proxy before method:eat
Gavin Eating...
Cglib proxy after method:eat

可以看到Cglib主要以继承的形式进行代理,那么Cglib就相应的无法对final类进行代理了,因为final类无法继承。


源码地址:https://github.com/gavincook/proxy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值