1.动态代理
动态代理还是属于设计模式--代理模式的一种,代理类在程序运行时创建的代理方式被成为动态代理。动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。现在有一个非常流行的名称叫做面向横切面编程,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制。
类图:
很简单,两条独立发展的线路。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。
2.举个例子
两条线,首先创建业务逻辑这条线,创建一个抽象主题类
package com.wx.dynamicproxy.base;
/*
抽象主题
*/
public interface Subject {
public void doSomething(String string);
}
创建具体的主题类,实现抽象主题接口
package com.wx.dynamicproxy.imp;
import com.wx.dynamicproxy.base.Subject;
/*
真实主题
*/
public class RealSubject implements Subject {
/*
业务操作
*/
@Override
public void doSomething(String string) {
System.out.println("真实主题的业务操作"+string);
}
}
第二条线,动态代理实现代理的职责。
创建动态代理类:DynamicProxy,这个类中使用JDK提供的Proxy类来动态创建对象,这里也是动态代理和静态代理的区别,静态代理这个Proxy需要自己写。需要传入一下三个参数
loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
interfaces:目标对象实现的接口的类型(所以目标对象如果不实现接口就无法使用动态代理),使用泛型方式确认类型
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的
package com.wx.dynamicproxy.imp;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/*
动态代理类
方法作为参数传入
*/
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h){
//执行目标,并返回结果,
return (T)Proxy.newProxyInstance(loader,interfaces, h);
}
}
代理类的三个参数中,只有InvocationHandler 需要自己写,所以创建动态代理的动态代理的MyInvocationHandler类。实现接口InvocationHandler,这个类中持有一个被代理对象的实例target,并且所有通过动态代理实现的方法全部通过invoke方法调用。
package com.wx.dynamicproxy.imp;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/*
动态代理的MyInvocationHandler类,
*/
public class MyInvocationHandler implements InvocationHandler {
//这个类中持有一个被代理对象的实例target
private Object target=null;
//通过构造函数传递一个对象
public MyInvocationHandler(Object o)
{
this.target=o;
}
//代理方法,非常简单,所有通过动态代理实现的方法全部通过invoke方法调用。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行被代理的方法
return method.invoke(target,args);
}
}
测试:代理的过程是没有问题的了
package com.wx.dynamicproxy.test;
import com.wx.dynamicproxy.base.Subject;
import com.wx.dynamicproxy.imp.DynamicProxy;
import com.wx.dynamicproxy.imp.MyInvocationHandler;
import com.wx.dynamicproxy.imp.RealSubject;
import com.wx.dynamicproxy.imp.SubjectDynamicProxy;
public class Client {
public static void main(String[] agrs)
{
//定义一个主题
Subject subject=new RealSubject();
//定义一个Handler
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(subject);
//定义主题的代理
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),myInvocationHandler);
/*Subject proxyInstance = SubjectDynamicProxy.newProxyInstance(subject);*/
proxy.doSomething("hello");
}
}
实现了一个简单的横切面编程,我们来看通知Advice,也就是我们要切入的类。
创建一个通知接口IAdvice
package com.wx.dynamicproxy.base;
public interface IAdvice {
//通知只有一个方法,执行即可
public void exec();
}
实现这个接口:
package com.wx.dynamicproxy.imp;
import com.wx.dynamicproxy.base.IAdvice;
public class BeforeAdvice implements IAdvice {
@Override
public void exec() {
System.out.println("我是前置通知,我被执行了");
}
}
在动态代理类中把它切进去
package com.wx.dynamicproxy.imp;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/*
动态代理类
loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
*/
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h){
//寻找JoinPoint连接点,AOP框架使用元数据
if(true){
//执行一个前置通知
(new BeforeAdvice()).exec();
}
//执行目标,并返回结果,
return (T)Proxy.newProxyInstance(loader,interfaces, h);
}
}
测试:
代理模式应用得非常广泛,大到一个系统框架、企业平台,小到代码片段、事务处理,稍不留意就用到代理模式。可能该模式是大家接触最多的模式,而且有了AOP大家写代理就更加简单了,有类似Spring AOP和AspectJ这样非常优秀的工具,拿来主义可!不过,大家可以看看源代码,特别是调试时,只要看到类似$Proxy0这样的结构,你就应该知道这是一个动态代理了。
友情提醒,在学习AOP框架时,弄清楚几个名词就成:切面(Aspect)、切入点(JoinPoint)、通知(Advice)、织入(Weave)就足够了,理解了这几个名词,应用时你就可以游刃有余了!