代理有感:就是通过代理对象返回一个实例化的目标对象,然后当这个目标对象执行某方法时,先执行代理对象的默认的invoke()方法,再通过invoke执行需要的方法。
在文章代理模式之静态代理(2)中我们了解到静态代理的运行机制.同时在文章的尾部看到了静态代理的不足.而动态代理可以弥补那些不足,接下来我们将详细的来了解一下动态代理.
在Java的Java.lang.reflect包中提供Proxy类和InvocationHandler.我们可以通过他们两个生成动态的JDK动态代理类或者动态代理对象.
一个类:Proxy(动态生成一个代理对象)必须这个类实现了接口才可以生成代理,如果没有接口的话就不能生成代理.它是通过接口在内存中建立一个类.
一个接口:Interface InvocationHandler.系统生成的每个代理对象都有一个与之相对应的InvocationHandler对象.
具体代码示例:
由于在上文中的接口类和目标类没有进行更改,这里不再赘述.需要更改的是将原来的静态代理中手动添加的代理类删除.取而代之的是一个实现InvocationHandler接口的LogHandler类;
LogHandler类:(在原有的基础之上添加日志功能)
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.text.SimpleDateFormat;
- public class LogHandler implements InvocationHandler {
- //对目标对象生成代理对象,需要将目标对象传过来.可以使用构造方法和下面的方法
- private Object targetObject;
- public Object newProxyInstance(Object targetObject){
- this.targetObject=targetObject;
- //根据传来的对象动态生成代理
- //第一个参数是类加载器,需要和目标对象的类加载器一样.
- //第二个参数是目标类的所有接口.会根据接口创建出代理类,代理类具有目标类的所有方法,但是方法里没有任何东西.
- //第三个参数需要回调InvocationHandler中的invoke方法.也就是实现InvocationHandler的对象.
- return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
- }
- /**
- * method表示代理目标的方法,可以动态进行获取
- */
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- //获得当前时间
- SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- String datetime = tempDate.format(new java.util.Date());
- //方法开始日志记录
- System.out.println("startTime: "+datetime+" start-->>"+method.getName());
- //方法的相关参数
- for(int i=0;i<args.length;i++){
- System.out.println(args[i]);
- }
- //方法的返回值
- Object result=null;
- try{
- //调用目标的方法
- result =method.invoke(targetObject, args);
- //方法成功日志记录
- System.out.println("successTime: "+datetime+" success-->>"+method.getName());
- }catch(Exception e){
- e.printStackTrace();
- //方法失败日志记录
- System.out.println("errorTime: "+datetime+" error-->>"+method.getName());
- throw e;
- }
- return result;
- }
- }
客户端代码:
- /**
- * 添加一个用户
- */
- public class Client {
- public static void main(String[] args){
- LogHandler logHandler=new LogHandler();
- UserManager userManager=(UserManager)logHandler.newProxyInstance(new UserManagerImpl());
- userManager.addUser("00001", "刘德华");
- }
- }
执行结果如下:
startTime: 2012-08-10 16:49:37 start-->>addUser
00001
刘德华
UserManagerImpl.addUser()userId-->00001
successTime: 2012-08-10 16:49:37 success-->>addUser
使用动态代理,我们可以看到非常好的解耦效果.当然,在我们使用Proxy的时候也不是随意的用的,通常都是为一个指定的目标对象来生成动态代理.这种动态代理在AOP(AspectOrient Program)面向切面编程中称之为AOP代理.AOP代理可以替代目标对象,并且包含目标对象的全部方法,同时在已有方法的基础之上向前,向后加入一些通用处理的方法,例如上例中的日志处理.
通过对动态代理模式的研究和学习可以看到编程的艺术性,同时也在演绎着面向对象的核心思想