一、什么是动态代理
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
代理模式UML图:
简单结构示意图:
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。
二、AOP(JDK的动态代理模式)
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1)Interface InvocationHandler:该接口中仅定义了一个方法
public object invoke(Object obj,Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。
这个抽象方法在代理类中动态实现。
(2) Proxy:该类即为动态代理类
调用newProxyInstance方法
-
三个参数
-
ClassLoader:类加载器
-
类:增强方法所在的类 ,支持多个接口(数组形式)
-
InvocationHandler:实现该接口,创建代理对象,通过该方式增强实际对象
-
动态代理步骤:
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法
三、JDK的动态代理的使用
-
创建动态代理接口
package test_AOP; public class USErDaoImp implements USErDao{ @Override public int add(int a, int b) { System.out.println("add方法-------"); return a+b; } @Override public String update(String id) { System.out.println("update方法-------"); return id; } }
-
创建需要代理的实现对象
package test_AOP; public class USErDaoImp implements USErDao{ /** * 返回a+b的和 * @param a * @param b * @return a+b */ @Override public int add(int a, int b) { return a+b; } /** * 返回id值 * @param id * @return id */ @Override public String update(String id) { return id; } }
-
调用处理器实现类
/** * 调用处理器实现类 * 每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象 */ class InvocationHandlerImpl implements InvocationHandler{ /** * 这个是需要代理的真实对象 */ private Object object; /** * 构造方法,传入真正需要的代理对象 * @param object */ public InvocationHandlerImpl(Object object) { this.object = object; } /** * 该方法负责集中处理动态代理类上的所有方法调用。 * 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行 * 方法内部可以实现增强逻辑 * @param proxy 代理类实例 * @param method 被调用的方法对象 * @param args 调用参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在代理真实对象前我们可以添加一些自己的操作 System.out.println("在调用之前-------"+" Method:"+method.getName()); //真正被增强的方法 Object res = method.invoke(object, args); //方法执行后,也可以添加自己的操作 System.out.println("在调用之后-------"+object); return res; } }
-
测试
package test_AOP; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 USErDaoImp daoImp = new USErDaoImp(); /** * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用. * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法 */ InvocationHandlerImpl handler = new InvocationHandlerImpl(daoImp); ClassLoader classLoader=handler.getClass().getClassLoader(); Class[] interfaces={USErDao.class}; //该方法用于指定 类加载器、一组接口、调用处理器生成动态代理的实例 USErDao dao = (USErDao) Proxy.newProxyInstance(classLoader, interfaces, handler); int result = dao.add(1, 3); System.out.println(result); } }
-
输出结果
四、结论
通过分析代码可以看出Java 动态代理,具体有如下四步骤:
1.通过实现 InvocationHandler 接口创建自己的调用处理器;
2.通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
3.通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
4.通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。