在Spring AOP中,用到了代理模式,本文将讲解代理模式在Spring AOP中的应用
文章有参考其他博主文章:
- https://www.jianshu.com/p/a10d7917e0e6
- https://www.jianshu.com/p/9cdcf4e5c27d
- https://www.jianshu.com/p/269afd0a52e6
一、代理模式的定义
-
代理模式(Proxy Pattern)也称委托模式(Delegate Pattern),是一种结构型设计模式,也是一项基础设计技巧
-
代理模式用于解决两种问题:控制对原有对象的访问、增加额外的功能。可以说保护了原有对象
-
按照
代理创建的时期
来进行分类的话, 可以分为两种:静态代理、动态代理
二、静态代理
静态代理是由程序开发者或者工具生成的源代码 ,然后对其进行编译。在编译期代理类.class文件就已被创建。
静态代理示例:
-
首先定义一个接口和实现类,实现类有若干个方法
// 操作接口 public interface Operate { void doSomething(); }
// 操作者 public class Operator implements Operate { @Override public void doSomething() { System.out.println("I'm doing something"); } }
-
然后定义一个代理类,也实现了Operate接口
public class OperationProxy implements Operate { private Operator operator = null; @Override public void doSomething() { beforeDoSomething(); if(operator == null){ operator = new Operator(); } operator.doSomething(); afterDoSomething(); } private void beforeDoSomething() { System.out.println("before doing something"); } private void afterDoSomething() { System.out.println("after doing something"); } }
-
最后测试一下
public class StaticProxyTest { public static void main(String[] args) { Operate operate = new OperationProxy();//使用OperationProxy代替Operator operate.doSomething(); //代理者代替真实者做事情 } }
以上就是静态代理的实现,静态代理让调用者不用再直接持有操作者的引用,而是将一切操作交由代理者去完成。
静态代理有它的局限性:
- 如果我们新增加了需要代理的方法,代理类的代码也必须进行新的改动
- 如果有多个接口和实现类,我们又需要代理类,同样需要对代理者进行扩展并且更加麻烦
三、动态代理
-
从静态代理发现,每个代理类只能为一个接口服务,这样开发中会产生很多代理类。假如通过一个代理类就能完成全部的代理功能,那么我们就需要动态代理
-
常见的动态代理有:Java的JDK动态代理、Spring的CGLIB代理等
1.JDK动态代理
- JDK动态代理是基于Java的反射机制实现的,在Java中要想实现动态代理机制,需要java.lang.reflect.Invoca-tionHandler接口和 java.lang.reflect.Proxy类的支持
(1)InvocationHandler接口
package java.lang.reflect;
/**
* @author Peter Jones
* @see Proxy
* @since 1.3
*/
public interface InvocationHandler {
// Object proxy -> 被代理的对象
// Method method -> 要调用的方法
// Object[] args -> 方法调用时所需要的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
(2)Proxy类源码(部分)
这里只贴出创建代理newProxyInstance()的方法,以后会进行详细的解读
package java.lang.reflect;
import ... ;
public class Proxy implements java.io.Serializable {
// ClassLoader loader -> 使用的类加载器
// Class<?>[] interfaces —> 得到的全部接口
// InvocationHandler h -> 得到InvocationHandler接口的子类的实例
@CallerSensitive
public static Object newProxyInstance(
ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException{
.....
}
}
JDK动态代理代码示例:
-
创建接口和实现类,模拟业务实现
public interface UserService{ void add(String name); }
public class UserServiceImpl implements IUserService{ @Override public void add(String name) { System.out.println("向数据库中插入名为: "+name+" 的用户"); } }
-
创建InvocationHandler接口实现类
public class MyInvocationHandler implements InvocationHandler { //被代理对象,Object类型 private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始执行方法..."); Object returnvalue = method.invoke(target, args); System.out.println("方法执行完毕..."); return returnvalue; } }
-
测试使用,通过newProxyInstance创建 代理对象
public class DynamicProxyTest { public static void main(String[] args) { IUserService target = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(target); // 第一个参数是指定代理类的类加载器(我们传入当前测试类的类加载器) // 第二个参数是代理类需要实现的接口(我们传入被代理类实现的接口,这样生成的代理类和被代理类就实 // 现了相同的接口) // 第三个参数是invocation handler,用来处理方法的调用。这里传入我们自己实现的handler IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), target.getClass().getInterfaces(), handler); proxyObject.add("蓝蓝路"); } }
以上就是动态代理的简单例子,我们并没有像静态代理那样去自己定义一个代理类,并实例化代理对象。实际上,动态代理的代理对象是在内存中的,是JDK根据我们传入的参数生成好的。
2.Cglib动态代理
- 和JDK代理不同的是,JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现。
- 不能对final类以及final方法进行代理
- cglib动态代理是采用ASM字节码框架来修改字节码达到代理效果
- 关于cglib源码分析可以参考:https://blog.csdn.net/yu_kang/article/details/88530016
Cglib动态代理代码示例:
-
被代理类,这里目标类没有实现任何接口
public class HelloServiceImpl { public void sayHello(){ System.out.println("Hello Zhanghao"); } public void sayBey(){ System.out.println("Bye Zhanghao"); } }
-
类似与jdk动态代理,这里需要实现一个叫做MethodInterceptor的接口,生成一个方法拦截器
public class HelloMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Before: " + method.getName()); Object object = methodProxy.invokeSuper(o, objects); System.out.println("After: " + method.getName()); return object; } }
-
测试类测试调用结果
public class TestClinet { Enhancer enhancer = new Enhancer(); //继承被代理类 enhancer.setSuperclass(HelloServiceImpl.class); //设置回调 enhancer.setCallback(new HelloMethodInterceptor()); //设置代理类对象 HelloServiceImpl helloService = (HelloServiceImpl) enhancer.create(); //在调用代理类中方法时会被我们实现的方法拦截器进行拦截 helloService.sayBey(); }
我们可以从上面的代码示例中看到,代理类是由enhancer.create()创建的。Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展