java动态代理

代理模式是一种应用非常广泛的设计模式,当客户端代码需要调用某个对象时,客户端实际上不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时,我们就可以返回该对象的代理。

通常情况下,适用代理模式的情况有两种:

1.创建对象开销很大,可以创建一个代理对象,推迟真正的对象创建。大家所熟悉的Hibernate延迟加载策略就是使用动态代理,当A实体关联B实体时,在获取A实体时不需要立即获得与A实体关联的B实体,因为有可能客户端根本不需要B实体数据,当客户端真正需要这部分数据时,再加载B实体的数据。这样就节省了资源。

2.所创建的对象不能满足客户端需求,比如说我们需要为某个方法运行前加入一些验证或者过滤,这时我们就需要创建一个代理对象,增强原来对象的功能。


java实现动态代理有两种方法:jdk代理和cglib。

jdk动态代理

jdk代理需要使用一个接口( InvocationHandler)和一个类( Proxy
InvocationHandler接口定义如下:
public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
} 
代理类要实现这个接口,并实现Invoke方法,这个就是代理方法,当客户端调用委托对象方法时,实际上执行Invoke方法。
Proxy类提供了静态方法来获取动态代理对象:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) throws IllegalArgumentException
下面看一个jdk动态代理的例子:
首先定义一个接口
public interface IPerson {

	void walk();
}
定义实现类
public class Person implements IPerson {

	@Override
	public void walk() {
		System.out.println("walk");
	}

}
定义代理实现类
public class MyInvokationHandler implements InvocationHandler {

	private Object target;
	public void setTarget(Object target) {
		this.target=target;
	}
	/**
	 * 执行动态代理对象的所有方法时,都会被替换执行如下的invoke方法
	 * Proxy:代表动态代理的对象
	 * method:代表正在执行的方法
	 * args:代表调用目标方法时传入的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("正在执行的方法:"+method);
		method.invoke(target, args);
		return null;
	}

}

main函数
public class ProxyTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		MyInvokationHandler handler =new MyInvokationHandler();
		Person person=new Person();
		handler.setTarget(person);
		IPerson p=(IPerson)Proxy.newProxyInstance(Person.class.getClassLoader(), Person.class.getInterfaces(), handler);
		p.walk();
	}

}

这就是jdk动态代理的基本用法,是不是显的很麻烦,必须要使用接口,如果程序很简单,不想用接口,那么就不能使用jdk动态代理技术。

为什么jdk动态代理必须要使用接口呢?

原因是,jdk动态代理实际是要根据接口创建新的实现类,来实现代理方法。那么对于不是面向接口编程的程序,就无法使用jdk动态代理了,这时cglib解决了这个问题,cglib使用继承来创建代理类,因此可以传入普通类而不是接口来实现代理类,但是对于final类,无法实现动态代理。

cglib动态代理

和jdk动态代理使用方法类似,示例如下:

1、创建一个实现net.sf.cglib.proxy.MethodInterceptor接口的实例来为目标业务类加入进行代理时要进行的操作或增强:

import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
/**
 *CGlib采用非常底层的字节码技术,可以为一个类创建子类,
 并在子类中采用方法拦截技术拦截父类方法的调用,并顺势进行增强,即是织入横切逻辑
 * @author tufu
 */
public class CglibProxy implements MethodInterceptor{
    private Enhancer enhancer = new Enhancer();
    //覆盖MethodInterceptor接口的getProxy()方法,设置
    public Object getProxy(Class clazz){
        enhancer.setSuperclass(clazz); //设者要创建子类的类
        enhancer.setCallback(this); //设置回调的对象
        return enhancer.create(); //通过字节码技术动态创建子类实例,
    }

    public Object intercept(Object obj,Method method,Object[] args,
            MethodProxy proxy) throws Throwable {
        System.out.println("模拟代理增强方法");

        //通过代理类实例调用父类的方法,即是目标业务类方法的调用
        Object result = proxy.invokeSuper(obj, args);

        System.out.println("模拟代理增强方法结束");
        return result;
    }
}


2、通过java.lang.reflect.Proxy的getProxy()动态生成目标业务类的子类,即是代理类,再由此得到代理实例:

import com.proxy.ForumServiceImpl;
import java.lang.reflect.Proxy;

public class TestCglibProxy {
    public static void main(String args[]){
        CglibProxy proxy = new CglibProxy();

        //动态生成子类的方法创建代理类
        ForumServiceImpl fsi =
                (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);

        fsi.removeForum(10);
        fsi.removeTopic(2);
    }
}






你可能感兴趣的:(java动态代理)