前言
在Spring或者SpringBoot中,可以通过@Aspect注解和切点表达式等配置切面,实现对某一功能的织入。然而其内部到底是如何实现的呢?
实际上,Spring在启动时为切点方法所在类生成了代理类,通过操作代理类代替操作实际类,从而实现在真正调用方法之前或之后,插入一些我们自定义的逻辑。
如何生成代理类呢?
JDK动态代理
- JDK动态代理要求 被代理类必须有接口抽象。
- 通过实现 InvocationHandler 接口并实现 invoke(Object proxy, Method method, Object[] args) 方法进行自定义逻辑的织入:
- proxy :当前的代理类实例;
- method:被代理的方法;
- args:方法入参;
invoke方法的官方说明如下:即在
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
使用示例:
1、被代理的方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// 方法实现 public class HelloAOPImpl implements HelloAOP { @Override public String sayHello() { String hello = "你好,AOP"; System.out.println(hello); return hello; } }
2、配置自定义调用处理器
public class MyInvocationHandler implements InvocationHandler { 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 res = method.invoke(target, args); /**调用后,自定义业务*/ return res; } //获取代理类实例 public <T> T getProxyInstance(){ return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } }
2:调用与输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public static void main(String[] args) { HelloAOPImpl helloAOP = new HelloAOPImpl(); MyInvocationHandler myInvocationHandler = new MyInvocationHandler(helloAOP); HelloAOP proxy = myInvocationHandler.getProxyInstance(); proxy.sayHello(); } // 输出 我是代理,有人让我对你说: 你好,AOP
一个疑问:代理类如何取代被代理类的呢?
CGLIB动态代理
CGLIB动态代理不需要代理对象实现某个接口:
1、被代理类(没有接口实现)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class HelloAOPImpl2 { public void sayHello() { String s = "你好,AOP"; System.out.println(s); } }
2、CGLIB代理
public class CgibAOP2 implements MethodInterceptor { private Object target; /** * 通过构造函数设置被代理对象 * @param target */ public CgibAOP2(Object target) { this.target = target; } /** * 回调该方法。 * @param o * @param method * @param objects * @param methodProxy * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("say之前:"+ method+"1"); Object res = method.invoke(target, objects); System.out.println("say之后:"+ method+"1"); return res; } /** * 生成代理实例 * @return */ public Object getProxy(){ // 通过增强实现 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); //设置回调 Object res = enhancer.create(); return res; } }
3、测试:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Test { public static void main(String[] args) { HelloAOPImpl2 helloAOP = new HelloAOPImpl2(); HelloAOPImpl2 proxy = (HelloAOPImpl2)new CgibAOP2(helloAOP).getProxy(); proxy.sayHello(); } }
输出:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
say之前:public void com.wht.springaop.DynamicProxy.Cglib.HelloAOPImpl2.sayHello()1 你好,AOP say之后:public void com.wht.springaop.DynamicProxy.Cglib.HelloAOPImpl2.sayHello()1