JDK中的Poxy类简单实现动态代理

一、类所在位置

Proxy类在java.lang.reflect包下

java.lang.Object
  继承者 java.lang.reflect.Proxy
所有已实现的接口:

Serializable


二、该类的主要方法

Object proxyObject = Proxy.newProxyInstance(loader , interfaces, h);

三个参数的意义

1.classLoader 类加载器,将class文件加载到内存中,形成class对象
2.Class[] interfaces 需要实现的接口
3.InvocationHandler 调用处理器,代理对象的所实现的所有接口的方法,内容都是调用InvocationHandler
的invoke()方法

现在写代码测试下这个类,现有接口A,B,动态生成一个类同时实现A和B接口,代码如下
package org.edu.proxy;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
  
import org.junit.Test;  
  
public class Demo1 {  
    interface A {  
        void a();  
        void aa();  
    }  
    interface B {  
        void b();  
        void bb();  
    }  
    @Test  
    public void test1() {  
        /* 
         * 给出三大参数,然后动态生成这个类,这个类实现了提供的接口,然后生成这个类的对象 
         * 1.classLoader 类加载器 
         * 2.Class[] interfaces 需要实现的接口 
         * 3.InvocationHandler 调用处理器,代理对象的所实现的所有接口的方法,内容都是调用InvocationHandler 
         * 的invoke()方法 
         */  
          
        ClassLoader loader = this.getClass().getClassLoader();  
        Class[] interfaces = {A.class, B.class};  
        InvocationHandler h = new InvocationHandler() {  
              
            @Override  
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
                // TODO Auto-generated method stub  
                System.out.println("你好动态代理");  
                return null;  
            }  
        };  
        Object proxyObject = Proxy.newProxyInstance(loader , interfaces, h);  
        A a = (A) proxyObject;  
        a.a();  
        a.aa();  
        B b = (B) proxyObject;  
        b.b();  
        b.bb();  
    }  
}


单元测试结果如下

从结果中可以看出两个问题。
1.将代理对象强转成A接口和B接口没有报错,说明生成的代理对象同时实现了A接口和B接口。
2.调用代理对象的a()方法、aa()方法、b(),还有bb()方法,结果都是调用了InvocationHandler的invoke()方法,说明执行代理的对象的方法都是通过执行InvocationHandler的invoke()方法来实现的。

好,这是我们再测试下是不是所有方法都是这样呢?
结果发现,在执行toStirng()方法的时候执行了invoke()
在执行getClass()方法的时候没有执行,在执行hashcoe()方法的时候抛出了异常,这个不知道为什么。看了Object类的源码,发现getClass()方法是final和native修饰的,说明是本地方法,是用底层的c写的,不涉及到java代码,没有被重写。

我们想知道这个类的类型到底是什么,于是加入
System.out.println(a.getClass().getName());
结果是 org.edu.proxy.$Proxy4

说明生成的对象的类型是一个代理类,为什么叫这个名字,who konws!


三、InvocationHandler的invoke()方法

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

现在解释下这个方法的参数和返回值

Object proxy:代理对象。
Method method:调用的方法
Object[] args:实参,调用接口方法传进来的的参数
Object返回值:接口方法的返回值

四、动态代理的简单实现

动态代理的作用,增强
将原有的对象和需要增强的功能结合成一个代理对象,从而达到增强的效果。
代理对象=目标对象+增强
比如现在我有一个服务员接口,接口有服务方法,一个男服务员继承了这个接口,这个男服务员很呆板,只会服务,现在我需要让他变得礼貌一点,开始说您好,结束时说再见。我该怎么实现呢?

服务员接口
package org.edu.proxy;
/**
 * 服务员类
 * @author ZGJ
 * @date 2016年12月4日
 */
public interface Waiter {
	/**
	 * 服务方法
	 */
	void serve();

}

男服务员类
package org.edu.proxy;
/**
 * 男服务员
 * @author ZGJ
 * @date 2016年12月4日
 */
public class ManWaiter implements Waiter{


@Override
public void serve() {
// TODO Auto-generated method stub
System.out.println("服务中......");
}
}


实现如下
package org.edu.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;
/**
 * 
 * @author ZGJ
 * @date 2016年12月4日
 */
public class Demo2 {
	@Test
	public void fun() {
		ManWaiter manWaiter = new ManWaiter();
		ClassLoader loader = this.getClass().getClassLoader();
		Class[] interfaces = {Waiter.class};
//		传入目标对象
		InvocationHandler h = new WaiterInvocationHandler(manWaiter);
//		得到增强的代理对象
		Waiter waiterProxy = (Waiter) Proxy.newProxyInstance(loader , interfaces, h);
//		开始时说您好,结束时说再见
		waiterProxy.serve();
	}
}
class WaiterInvocationHandler implements InvocationHandler{
	private Waiter Waiter;
	public WaiterInvocationHandler(Waiter waiter) {
		// TODO Auto-generated constructor stub
		this.Waiter = waiter;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("您好!");
		Waiter.serve();
		System.out.println("再见!");
		return null;
	}
	
}

在创建InvocationHandler的时候,传入Waiter的对象,在invoke方法中,先执行前置增强,再调用waiter的server()方法,再执行后置增强,从而达到增强的效果。
但是,这种方式好像不是特别灵活,因为增强的方式都写死了,不够灵活。
这个时候,就可以使用代理工厂来实现生产代理对象
1.现在写两个接口
BeforeAdvice 前置增强
package org.edu.proxy.demo3;
/**
 * 前置增强
 * @author ZGJ
 * @date 2016年12月4日
 */
public interface BeforeAdvice {
	void before();
}

AfterAdvice 前置增强
package org.edu.proxy.demo3;
/**
 * 后置增强
 * @author ZGJ
 * @date 2016年12月4日
 */
public interface AfterAdvice {
	void after();
}

ProxyFactory代理工厂类
package org.edu.proxy.demo3;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理工厂类
 * @author ZGJ
 * @date 2016年12月4日
 */
public class ProxyFactory {
	private Object target;//目标对象
	private BeforeAdvice beforeAdvice;//前置增强
	private AfterAdvice afterAdvice;//后置增强
	
	
	/**
	 * 用来生成代对象
	 * @return
	 */
	public Object createProxy() {
		ClassLoader loader = this.getClass().getClassLoader();
		Class<?>[] interfaces = target.getClass().getInterfaces();
		InvocationHandler h = new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				// TODO Auto-generated method stub
				//执行前置增强
				if(beforeAdvice != null) {
					beforeAdvice.before();
				}
				//调用目标方法
				Object result = method.invoke(target, args);
				//执行后置增强
				if(afterAdvice != null) {
					afterAdvice.after();
				}
				return result;
			}
		};
		/*
		 * 三大参数
		 */
		Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
		return proxyObject;
	}

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

	public BeforeAdvice getBeforeAdvice() {
		return beforeAdvice;
	}

	public void setBeforeAdvice(BeforeAdvice beforeAdvice) {
		this.beforeAdvice = beforeAdvice;
	}

	public AfterAdvice getAfterAdvice() {
		return afterAdvice;
	}

	public void setAfterAdvice(AfterAdvice afterAdvice) {
		this.afterAdvice = afterAdvice;
	}
	
}

Demo3实现了目标对象和增强都可以切换
package org.edu.proxy.demo3;

import org.junit.Test;

/**
 * 目标对象和增强都可以切换的动态代理
 * @author ZGJ
 * @date 2016年12月4日
 */
public class Demo3 {
	@Test
	public void fun() {
		Waiter waiter = new ManWaiter();
		ProxyFactory factory = new ProxyFactory();//创建工厂
		factory.setTarget(waiter);//设置目标对象
		factory.setBeforeAdvice(new BeforeAdvice() {
			
			@Override
			public void before() {
				// TODO Auto-generated method stub
				System.out.println("您好");
			}
		});
		factory.setAfterAdvice(new AfterAdvice() {
			
			@Override
			public void after() {
				// TODO Auto-generated method stub
				System.out.println("再见");
			}
		});
		Waiter waiterProxy = (Waiter) factory.createProxy();
		waiterProxy.serve();
	}
}

如果我想修改前置增强的方法,只需新建一个类继承前置增强的接口就行了,后置增强同理,被增强的目标对象也可以切换,这样就灵活很多了。



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值