动态代理
概念
动态代理:在运行时,动态的创建一组指定的接口的实现类对象。它的作用和装饰者模式比较相似,但是比装饰者模式要灵活:装饰者模式:增强目标固定,增强内容可变;动态代理:增强目标可变,增强内容可变。
使用方法
在Java中使用动态代理,主要是学习InvocationHandler接口和Proxy类的使用
动态代理实例获取方法
Object proxyObject = Proxy.newProxyInstance(
ClassLoader classLoader,
Class[] interfaces,
InvocationHandler handler);
- 方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!
- 参数:
(1)ClassLoader:类加载器。它是用来加载器的,把.class文件加载到内存,形成Class对象。
(2)Class[] interfaces:指定要实现的接口们
(3)InvocationHandler:代理对象的所有方法(个别不执行,getClass())都会调用InvocationHandler的invoke()方法。
InvocationHandler参数
InvocationHandler是一个抽象类,需要重写。其中有一个抽象方法
public Object invoke(Object proxy, Method method, Object[] args);
这个方法会在调用代理对象所实现接口中的方法时调用。
参数:
目标对象:被增强的对象
代理对象:需要目标对象,然后在目标对象上添加了增强后的对象!
目标方法:增强的内容
实例代码
public class test {
@Test
public void fun(){
/**
* 动态代理:Proxy#newProxyInstance()
* 该方法三个参数:
* ClassLoader 类加载器
* Class[] interfaces 接口类数组
* InvocationHandler 代理类中的所有方法都会调用其的invoke方法(个别函数不调用 getClass())
*/
//得到当前类的类加载器
ClassLoader loader=this.getClass().getClassLoader();
InvocationHandler handler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("你好,动态代理!");
return null;
}
};
//得到Proxy实例
Object o=Proxy.newProxyInstance(loader,new Class[]{A.class,B.class},handler);
A a= (A) o;
B b= (B) o;
a.a();
a.aa();
b.b();
o.getClass();
}
}
interface A{
void a();
void aa(String s,int i);
}
interface B{
void b();
}
输出结果:
你好,动态代理!
你好,动态代理!
你好,动态代理!
对于实例代码中的得到的动态代理对象Object o可以强转成 接口A或接口B 即成功创建了该组接口类对象。
这里盗用崔凡希老师的图来说明目标对象调用的方法与InvocationHandler之间的关系
案例1:增强目标对象
接口Wainter.java
public interface Waiter {
void service();
}
实现类ManWaiter.java
public class ManWaiter implements Waiter{
public void service() {
System.out.println("服务中……");
}
}
测试类test.java
public class test {
@Test
public void Fun(){
ManWaiter waiter=new ManWaiter();
//得到本类的类加载器
ClassLoader loader=this.getClass().getClassLoader();
//得到InvocationHandler重写类WaiterInvocationHander
InvocationHandler handler=new WaiterInvocationHander(waiter);
//得到动态代理
Waiter waiterProxy= (Waiter) Proxy.newProxyInstance(loader,new Class[]{Waiter.class},handler);
//动态代理对象调用增强方法
waiterProxy.service();
}
}
/**
* 重写InvocationHandler
*/
class WaiterInvocationHander implements InvocationHandler{
//底层依赖对象
private Waiter waiter;
//构造器
public WaiterInvocationHander(Waiter waiter){
this.waiter=waiter;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强
System.out.println("您好!");
waiter.service();
//后置增强
System.out.println("再见!");
return null;
}
}
案例中传递的增强对象可以改变,但是增强方法使固定的。
案例2:封装成工厂
在案例1的基础上,进一步优化动态代理
前置增强接口AfterAdvice.java
public interface AfterAdvice {
void after();
}
后置增强接口BeforeAdvice.java
public interface BeforeAdvice {
void before();
}
代理工厂ProxyFactory.java
public class ProxyFactory {
private Object targetObject;//目标对象
private BeforeAdvice beforeAdvice;//前置增强
private AfterAdvice afterAdvice;//后置增强
public Object createProxy(){
//三大参数
ClassLoader loader=this.getClass().getClassLoader();
InvocationHandler handler=new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行前置增强
if (beforeAdvice != null) {
beforeAdvice.before();
}
//执行目标对象的目标函数
Object result=method.invoke(targetObject,args);
//执行后置增强
if (afterAdvice != null) {
afterAdvice.after();
}
//返回目标函数的返回值
return result;
}
};
//得到目标对象的实现接口数组
Class[] interfaces=targetObject.getClass().getInterfaces();
//得到动态代理
Object proxy= Proxy.newProxyInstance(loader,interfaces,handler);
return proxy;
}
public Object getTargetObject() {
return targetObject;
}
public void setTargetObject(Object targetObject) {
this.targetObject = targetObject;
}
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;
}
}
测试类
public class test {
@Test
public void fun(){
//创建工厂
ProxyFactory factory=new ProxyFactory();
//设置目标对象
factory.setTargetObject(new ManWaiter());
//设置前置增强
factory.setAfterAdvice(new AfterAdvice() {
public void after() {
System.out.println("您好!");
}
});
//设置后置增强
factory.setBeforeAdvice(new BeforeAdvice() {
public void before() {
System.out.println("再见!");
}
});
//得到动态代理
Waiter waiter= (Waiter) factory.createProxy();
waiter.service();
}
}
本例中,通过前置和后置接口的方式,可以实现增强方法的可变性。