【java-之路】学习动态代理[基础]

什么是代理

代理模式英语:Proxy Pattern)是程序设计中的一种设计模式。

所谓的代理者是指一个类可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。

著名的代理模式例子为引用计数(英语:reference counting)指针对象。

当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除--引自维基百科

所谓代理就通过引用一个新的对象来实现对真实对象的操作或者将新的对象当做真实对象的一个替身,这种实现的机制就是代理模式,通过引用代理对象来访问真实对象就是代理模式的设计动机。(起到偷梁换柱的效果)

代理模式一般涉及到的角色有

抽象角色:声明真实对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
 * 
 *          代理角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,
 *          以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象,同时,
 *          代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
 * 
 *          真实角色:定义了代理对象所代表的目标对象,代理角色所代表的真实对象,是我们最终要引用的对象,定义了代理对象所代表的目标对象。
 

通过代码来实现代理


public class TestProxy {

	public static void main(String[] args) {
		new RealSubject().doSometing();
		new SubjectProxy(new RealSubject()).doSometing();
	}
}

interface Subject {
	void doSometing();
}

class RealSubject implements Subject {

	@Override
	public void doSometing() {
		System.out.println("运行了");

	}

}

class SubjectProxy implements Subject {

	private Subject subject;

	public SubjectProxy(Subject subject) {
		this.subject = subject;
	}

	@Override
	public void doSometing() {
		System.out.println("before");
		subject.doSometing();
		System.out.println("after");
	}

}

  运行结果

运行了
before
运行了
after

动态代理的例子

public class TestProxy {

	public static void main(String[] args) {
		RealSubject real = new RealSubject();
		// 1、类加载器(ClassLoader)用来加载动态代理类。 
		//2、一个要实现的接口的数组。 
		//3、一个 InvocationHandler
		// 把所有方法的调用都转到代理上。 如下例:
		// Subject subj = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, new ProxyHandler(real));
		Subject subj = (Subject) new ProxyHandler().bind(real);
		subj.doSometing("123");
	}
}

public class ProxyHandler implements InvocationHandler {

	private Object tar;

	public ProxyHandler() {
		super();
	}

	public ProxyHandler(Object tar) {
		this.tar = tar;

	}

	public Object bind(Object tar) {
		this.tar = tar;
		return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
	}

	/**
	 * invoke()方法同样有三个参数:
	 * 
	 * 1. 动态代理类的引用,通常情况下不需要它。但可以使用getClass()方法,得到proxy的Class类从而取得实例的类信息,如方法列表,
	 * annotation等。
	 * 
	 * 2. 方法对象的引用,代表被动态代理类调用的方法。从中可得到方法名,参数类型,返回类型等等
	 * 
	 * 3. args对象数组,代表被调用方法的参数。注意基本类型(int,long)会被装箱成对象类型(Interger, Long)
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		return method.invoke(tar, args);
	}

}

public interface Subject {

	public void doSometing(String str);
}

public class RealSubject implements Subject {

	@Override
	public void doSometing(String str) {
		System.out.println(str);

	}

}

运行结果:
123
总结:
通过动态代理我们能够起到获得真实角色调用的具体方法 并对方法做到拦截 实现在不改变源码的情况下对方法进行增强 


你可能感兴趣的:(【java-之路】学习动态代理[基础])