java动态代理

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class)

动态代理的通俗化解释A接口有c方法,类B实现A接口,原本应该是执行B类中的c方法,可现在不这样做;我声明产生B类的代理类B',由它来冒充B类的“兄弟”并“实现”A接口,对外界来说B'应该也有c方法,可当真正调用它的时候,

它会去执行与它关联InvocationHandler的invoke()方法,在这个方法里面你可以做很多事情。这样,这个请求就被“代理”到其它地方去了。


InvocationHandler:

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个类,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

proxy:  指代我们所代理的那个真实对象

method:  指代的是我们所要调用真实对象的某个方法的Method对象

args:  指代的是调用真实对象某个方法时接受的参数

Proxy

动态创建一个代理对象的类,用的最多的就是 newProxyInstance 这个方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException { 
    // 检查 h 不为空,否则抛异常
    if (h == null) { 
        throw new NullPointerException(); 
    } 

    // 获得与指定类装载器和一组接口相关的代理类类型对象
    Class cl = getProxyClass(loader, interfaces); 

    // 通过反射获取构造函数对象并生成代理类实例
    try { 
        Constructor cons = cl.getConstructor(constructorParams); 
        return (Object) cons.newInstance(new Object[] { h }); 
    } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); 
    } catch (IllegalAccessException e) { throw new InternalError(e.toString()); 
    } catch (InstantiationException e) { throw new InternalError(e.toString()); 
    } catch (InvocationTargetException e) { throw new InternalError(e.toString()); 
    } 
}

Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载

interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

实例:

定义接口

public interface UserDao {
	public void save(User user);
}

定义接口实现

public class UserDaoImpl implements UserDao {

	//@Override
	public void save(User user) {
		System.out.println("usersaved!!!");

	}
}

定义代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;


public class DebugInterceptor implements InvocationHandler {
	private Object target;

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}
	
	private void operate(Method m){
		System.out.println(m.getName()+" start!!!");
	}

	/*
	 * proxy:  指代我们所代理的那个真实对象
	 * method: 指代的是我们所要调用真实对象的某个方法的Method对象
	 * args:  指代的是调用真实对象某个方法时接受的参数
	 * 
	 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
	 * java.lang.reflect.Method, java.lang.Object[])
	 */
	//@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		operate(method);
		method.invoke(target, args);
		return null;
	}

}

测试程序

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		UserDao userDao = new UserDaoImpl();
		DebugInterceptor di = new DebugInterceptor();
		di.setTarget(userDao);
		//Proxy.newProxyInstance(loader, interfaces, h)参数分别表示调用函数的类加载器,调用函数的全部接口,实现此代理的类
		UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao
				.getClass().getClassLoader(), userDao.getClass()
				.getInterfaces(), di);
		System.out.println(userDaoProxy.getClass().getName());
		System.out.println(userDaoProxy.getClass().getMethods());
		userDaoProxy.save(new User());

	}

}

output:

com.sun.proxy.$Proxy0

[Ljava.lang.reflect.Method;@feb48

save start!!!

usersaved!!!

com.sun.proxy.$Proxy0是由以下代码生成的对象的名称

UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao
				.getClass().getClassLoader(), userDao.getClass()
				.getInterfaces(), di);

由此可以看到通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口(userDao)的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号

在真正通过代理对象来调用真实对象的方法的时候,我们可以在该方法前后添加自己的一些操作,这就是我们的java动态代理机制


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