代理的概念
代理提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。
************************************************
静态代理
目标对象实现的接口
interface Operation{
void download();
}
目标对象实现类
class RealObject implements Operation{
@Override
public void download() {
System.out.println("执行业务逻辑...");
}
}
代理类:
通过实现与目标对象相同的接口
并维护一个代理对象,通过构造器传入实际目标对象并赋值
执行代理对象实现的接口方法,实现对目标对象实现的干预
class ProxyObject implements Operation{
private Operation operation;
public ProxyObject(Operation operation) {
this.operation = operation;
}
@Override
public void download() {
System.out.println("前拦截...");
operation.download();//通过代理来调用实际对象的方法
System.out.println("后拦截...");
}
}
主类
public class TestProxy {
public static void main(String[] args) {
Operation operation = new ProxyObject(new RealObject());//把实际对象传入代理
operation.download();
}
}
静态优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。
***************************************************
动态代理:
动态的在内存中构建代理对象(需要我们制定要代理的目标对象实现的接口类型),即利用JDK的API生成指定接口的对象,也称之为JDK代理或者接口代理。
public class ProxyFactory {
private Object targetObject;
public ProxyFactory(Object targetObject) {
this.targetObject = targetObject;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(), //和目标对象的类加载器保持一致
targetObject.getClass().getInterfaces(), //目标对象实现的接口,因为需要根据接口动态生成对象
new InvocationHandler() { //InvocationHandler:事件处理器,即对目标对象方法的执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前拦截...");
Object result = method.invoke(proxy, args);
System.out.println("后拦截...");
return result;
}
});
}
}
指定的接口在系统运行期间动态的生成代理对象。
实现主要由 java.lang.reflect.Proxy 类和java.lang.reflect.InvocationHandler接口。
动态代理的缺点:动态代理只能对实现了相应Interface的类使用,如果某个类没有实现任何的Interface,就无法使用动态代理对其产生相应的代理对象!
因此:在默认情况下,如果Spring AOP发现目标实现了相应的Interface,则采用动态代理为其生成代理对象实例;
而如果目标对象没有实现任何的Interface,Spring AOP会尝试使用CGLIB动态字节码生成类库,为目标对象生成代理对象实例!
CGLIB动态字节码生成
CGLIB扩展对象行为的原理是:对目标对象进行继承扩展,为其生成相应的子类,而子类可以通过覆写来扩展父类的行为,只要将横切逻辑的实现放到子类中,然后让系统使用扩展后的目标对象的子类,就可以达到与代理模式相同的效果了。 相比于动态代理,CGLIB的优势就是,可以为没有实现任何接口的类进行扩展。
public class Requestable {
public void request() {
System.out.println("requestable without implementint any interface");
}
}
要对该类进行继承扩展,所以我们要使用CGLIB类库,
实现一个net.sf.cglib.proxy.Callback,或者使用net.sf.cglib.proxy.MethodInterceptor(继承自Callback)
import java.lang.reflect.Method;
import org.joda.time.TimeOfDay;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class RequestCallback implements MethodInterceptor {
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if(method.getName().equals("request")) {
System.out.println("你调用了request方法")
return proxy.invokeSuper(object, args);
}
return null;
}
}
我们使用MethodInterceptor为request方法实现了对request请求进行控制的逻辑
然后我们现在通过Enhancer为目标对象动态生成一个子类,将RequestCallback的横切逻辑附加到该子类中:
import net.sf.cglib.proxy.Enhancer;
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(Requestable.class);
//设置Callback
enhancer.setCallback(new RequestCallback());
Requestable proxy = (Requestable) enhancer.create();
proxy.request();
}
}
缺点:使用 CGLIB 对类进行扩展的唯一限制就是 无法对 final 方法进行覆写
动态代理、动态字节码生成:就是 Spring AOP 所使用的核心技术,也就是 Spring AOP 的Weaving And Weaver 的实现原理了。