代理模式&动态代理

折月煮酒 提交于 2020-03-02 08:20:10

动态代理的用途:

动态代理的用途与装饰模式很相似,就是为了对某个对象进行增强。所有使用装饰者模式的案例都可以使用动态代理来替换,动态代理可以更好的解耦合

增强有3个手段
1. 继承
 被增强对象不能变
 增强内容不能变
2. 装饰者模式
 被增强对象可变
 但增强内容不能变
3. 动态代理
 被增强对象可变
 增强内容也可变

如何实现动态代理?

定义一个接口Interface, 被增强的对象的类都会实现这个接口

 public interface Interface {
 public void fun();
}

实现这个Interface接口:
而这个InterfaceImpl就是动态代理中被增强的内容

 public class InterfaceImpl implements Interface {
 @Override
 public void fun() {
  System.out.println("目标方法调用");
 }
}

定义一个接口Advice, 增强内容的类都会实现这个接口
这个接口有两个未实现的方法:
before()前置增强的方法
after()后置增强的方法

 public interface Advice {
 public void before();
 public void after();
}

而实现了Advice接口的对象就是动态代理中增强内容

JavaAPI:

java.lang.reflect.Proxy

Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);

返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序

参数:
classLoader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口


java.lang.reflect.InvocationHandler

public Object invoke(Object proxy, Method method, Object[] args);

这个invoke()方法在调用代理对象所实现接口中的方法时调用

* Object proxy:当前对象,即代理对象!在调用谁的方法!
* Method method:当前被调用的方法(目标方法)
* Object[] args:目标方法参数

调用proxy实例的方法时, 都会被InvocationHandler所捕获, 因此只要实现InvocationHandler实现类的invoke()方法, 就可以实现目标方法的增强

定义一个类ProxyFactory

该类通过两个参数的public ProxyFactory(target,advice)构造方法构造ProxyFactory实例, 然后通过该实例的getProxy()方法得到代理对象

 public class ProxyFactory {
	private Object target;    // 目标对象
	private Advice advice;    // 增强对象

	public ProxyFactory(Object target, Advice advice) {
		this.target = target;
		this.advice = advice;
	}

	/**
	 * 得到代理对象
	 */
	public Object getProxy() {
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(),
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						// 执行前置增强
						advice.before();
						// 执行目标对象的目标方法, 用result接收返回值
						Object result = method.invoke(target, args);
						// 执行后置增强
						advice.after();
						// 返回目标方法的返回值result
						return result;
					}
				});
	}
}

测试动态代理

public static void main(String[] args) {
	InterfaceImpl target = new InterfaceImpl();
	// 实现一个Advice的实例对象, 这个对象就是动态代理中增强内容
	Advice advice = new Advice() {
		@Override
		public void before() {
			System.out.println("目标方法调用之前, 执行前置增强");
		}

		@Override
		public void after() {
			System.out.println("目标方法调用之后, 执行后置增强");
		}
	};
	ProxyFactory proxyFactory = new ProxyFactory(target, advice);
	Interface proxy = (Interface) proxyFactory.getProxy();
	proxy.fun();
}

Console输出:

方法调用之前, 执行前置增强
目标方法调用
方法调用之后, 执行后置增强

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!