在Spring中是通过代理模式来实现AOP
代理模式:给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
主要是由 接口+真实实现类+代理类 这三部分组成
而代理模式又分为静态代理 动态代理 Cglib代理
下面通过一个例子以及其代码实现来更好的理解静态代理 动态代理 Cglib代理
以支付宝支付为例,我们用支付宝购买东西从来只需要关系我们支付了没有,而至于钱是如何从银行转到商家这个过程我们是不关心的,这个过程就是代理类(也就是支付宝)帮我们处理的的。下面我们来看看这个过程的具体代码实现
静态代理的代码实现:
首先先创建一个接口
public interface Payment {
void pay();
}
再创建一个真实实现类(也就是用户)来实现这个接口
public class RealPayment implements Payment{
@Override
public void pay() {
System.out.println("作为用户,我只关心支付");
}
}
再创建一个代理类(也就是支付宝)也来实现这个接口,同时代理真实实现类
public class AliPay implements Payment {
private Payment payment;
public AliPay(Payment payment){
this.payment = payment;
}
@Override
public void pay() {
beforePay();
payment.pay();
afterPay();
}
public void beforePay(){
System.out.println("从招行取款");
}
public void afterPay(){
System.out.println("支付给慕课");
}
}
最后在main函数里面,创建一个代理对象,传入真实实现类,便能实现代理过程
public class ProxyDemo {
public static void main(String[] args) {
Payment proxy = new AliPay(new RealPayment());
proxy.pay();
}
}
使用静态代理,其一,如果接口增加方法,那么实现类必须重写方法,代理类也要重写代理的方法;其二,如果增加新的接口,也势必要增加新的代理类,这势必会造大量的代码冗余。把这些相同的代理过程抽取出来,便能大幅度减少代码冗余,这就是AOP的思想。而Spring就是通过动态代理和Cglib来实现AOP思想
动态代理的代码实现:
动态代理的实现前两步跟静态代理一样(此处省略)
创建代理类,实现InvocationHandler接口,重写invoke方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class jdkProxy implements InvocationHandler {
private Object targetObject;
public jdkProxy(Object object) {
this.targetObject = object;
}
/**
*
* @param proxy 被代理对象类
* @param method 被代理对象要实现的方法
* @param args 实现该方法所需要的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("从银行卡里取钱");
Object invoke = method.invoke(targetObject, args);
System.out.println("把钱打给商家");
return invoke;
}
}
在main函数里,创建动态代理对象
public class ProxyDemo {
public static void main(String[] args) {
Payment payment = new RealPayment(); //被代理对象
jdkProxy jdkProxy = new jdkProxy(payment);
//创建动态代理对象
Payment proxy = (Payment) Proxy.newProxyInstance(payment.getClass().getClassLoader(),payment.getClass().getInterfaces(),jdkProxy);
proxy.pay();
}
}
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样做的好处就是,如果接口增加新的方法,实现类重写,但是代理类不用重写,便能直接调用,如果增加新的接口,则在代理类里面传入新的接口对象即可,无需创建新的代理类。
Cglib代理的代码实现:
首先创建一个真实实现类,这个类无序实现任何接口
public class RealPayment{
public void pay() {
System.out.println("作为用户,我只关心支付");
}
}
创建Cglib类,实现MethodInterceptor接口,重新intercept方法
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class Cglib implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("从银行取钱");
//调用原有方法
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("打钱给商家");
return o1;
}
}
在main方法中,创建Cglib代理对象
public class ProxyDemo {
public static void main(String[] args) {
Cglib cglib = new Cglib();
Enhancer en = new Enhancer(); //帮我们生成代理对象
en.setSuperclass(RealPayment.class); //设置对谁进行代理
en.setCallback(cglib); //代理要做什么
RealPayment payment = (RealPayment) en.create();//创建代理对象
payment.pay();
}
}
Spring AOP的实现:jdkProxy(动态代理)和Cglib代理
至于使用哪种由AopProxyFactory根据AdvisedSupport对象的配置来决定
默认的策略是目标类是接口,则用jdkProxy来实现,否则用后者
jdkProxy(动态代理):
- 被代理对象必须实现接口,才能产生代理对象,如果没有接口将不能使用动态代理。
- 核心是InvocationHandler接口和Proxy类
- 通过java的内部反射机制实现
- 反射机制在生成类的过程中比较高效
Cglib代理:第三方代理技术:
- 可以对任何类生成代理,代理的原理是对目标对象进行继承代理。
- 如果目标对象被final修饰,那么该类无法被cglib代理
- 借助ASM实现
- ASM在生成类之后的执行过程比较高效