一、类所在位置
Proxy类在java.lang.reflect包下
java.lang.Object java.lang.reflect.Proxy所有已实现的接口:
二、该类的主要方法
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;
}
}
但是,这种方式好像不是特别灵活,因为增强的方式都写死了,不够灵活。
这个时候,就可以使用代理工厂来实现生产代理对象
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();
}
}
如果我想修改前置增强的方法,只需新建一个类继承前置增强的接口就行了,后置增强同理,被增强的目标对象也可以切换,这样就灵活很多了。