动态代理的用途:
动态代理的用途与装饰模式很相似,就是为了对某个对象进行增强。所有使用装饰者模式的案例都可以使用动态代理来替换,动态代理可以更好的解耦合
增强有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输出:
方法调用之前, 执行前置增强
目标方法调用
方法调用之后, 执行后置增强