您的位置:首页 > 编程语言 > Java开发

Java 动态代理以及Cglib代理

2014-07-27 20:43 218 查看
代理为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式通常也作为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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: