Spring AOP里的静态代理和动态代理,你真的了解嘛?

什么是代理?

为某一个对象创建一个代理对象,程序不直接用原本的对象,而是由创建的代理对象来控制原对象,通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间

什么是静态代理?

由程序创建或特定工具自动生成代码,在程序运行前,代理类的.class文件就已经存在

通过将目标类与代理类实现同一个接口,让代理类持有真实类对象,然后在代理类方法中调用真实类方法,在调用真实类方法的前后添加我们所需要的功能扩展代码来达到增强的目的。

优点

代理使客户端不需要知道实现类是什么,怎么做,而客户端只需知道代理即可

方便增加功能,扩展业务逻辑

缺点

代理类中常出现大量冗余的代码,非常不利于扩展和维护

如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度

案例演示

PayService.java接口

package net.cybclass.sp.proxy;

public interface PayService {
    /**
     * 支付回调
     * @param outTradeNo 订单号
     * @return
     */
    String callback(String outTradeNo);

    /**
     * 下单
     * @param userId 用户id
     * @param productId 产品id
     * @return
     */
    int save(int userId,int productId);
}

PayServiceImpl.java( 接口实现类
)

package net.cybclass.sp.proxy;

public class PayServiceImpl implements PayService{
    public String callback(String outTradeNo) {
        System.out.println("目标类 PayServiceImpl 回调 方法 callback");
        return outTradeNo;
    }

    public int save(int userId, int productId) {
        System.out.println("目标类 PayServiceImpl 回调 方法 save");
        return productId;
    }
}

StaticProxyPayServiceImpl.java( 接口实现类,静态代理
)

package net.cybclass.sp.proxy;

public class StaticProxyPayServiceImpl implements PayService{
    private PayService payService;
    public StaticProxyPayServiceImpl(PayService payService)
    {
        this.payService=payService;
    }
    public String callback(String outTradeNo) {
        System.out.println("StaticProxyPayServiceImpl callback begin");
        String result=payService.callback(outTradeNo);
        System.out.println("StaticProxyPayServiceImpl callback end");
        return result;
    }

    public int save(int userId, int productId) {
        System.out.println("StaticProxyPayServiceImpl save begin");
        int id = payService.save(userId, productId);
        System.out.println("StaticProxyPayServiceImpl save end");
        return id;
    }
}

演示

Spring AOP里的静态代理和动态代理,你真的了解嘛?

什么是动态代理?

在程序运行时,运用反射机制动态创建而成,无需手动编写代码

    • JDK动态代理
    • CGLIB动态代理(
      原理

      :是对指定的业务类生成一个子类,并覆盖其中的业务方法来实现代理)

jdk动态代理演示

定义一个类,去实现InvocationHandler这个接口,并车从写invoke方法

//Object proxy:被代理的对象
//Method method:要调用的方法
//Object[] args:方法调用时所需要参数
public Object invoke(Object proxy, Method method, Object[] args){}

PayService.java( 接口
)

package net.cybclass.sp.proxy;

public interface PayService {
    /**
     * 支付回调
     * @param outTradeNo 订单号
     * @return
     */
    String callback(String outTradeNo);

    /**
     * 下单
     * @param userId 用户id
     * @param productId 产品id
     * @return
     */
    int save(int userId,int productId);
}

PayServiceImpl.java( 接口实现类
)

package net.cybclass.sp.proxy;

public class PayServiceImpl implements PayService{
    public String callback(String outTradeNo) {
        System.out.println("目标类 PayServiceImpl 回调 方法 callback");
        return outTradeNo;
    }

    public int save(int userId, int productId) {
        System.out.println("目标类 PayServiceImpl 回调 方法 save");
        return productId;
    }
}

JDKProxy.java( jdk动态代理类
)

package net.cybclass.sp.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKProxy implements InvocationHandler {
    //目标类
    private Object targetObject;

    /**
     * 获取代理对象
     * @param targetObject 目标类
     * @return
     */
    public Object newProxyInstance(Object targetObject) {
        this.targetObject = targetObject;
        //绑定关系,也就是和具体的那个实现类关联
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(), this);
    }

    /**
     * JDK动态代理
     *
     * @param proxy  静态代理对象
     * @param method 要调用的方法
     * @param args   方法调用时所需要参数
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
            System.out.println("通过JDK动态代理调用"+method.getName()+",打印日志 begin");
            result = method.invoke(targetObject, args);
            System.out.println("通过JDK动态代理调用"+method.getName()+",打印日志 end");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }
}

演示

Spring AOP里的静态代理和动态代理,你真的了解嘛?

CGLIB动态代理演示

PayService.java( 接口
)

package net.cybclass.sp.proxy;

public interface PayService {
    /**
     * 支付回调
     * @param outTradeNo 订单号
     * @return
     */
    String callback(String outTradeNo);

    /**
     * 下单
     * @param userId 用户id
     * @param productId 产品id
     * @return
     */
    int save(int userId,int productId);
}

PayServiceImpl.java( 接口实现类
)

package net.cybclass.sp.proxy;

public class PayServiceImpl implements PayService{
    public String callback(String outTradeNo) {
        System.out.println("目标类 PayServiceImpl 回调 方法 callback");
        return outTradeNo;
    }

    public int save(int userId, int productId) {
        System.out.println("目标类 PayServiceImpl 回调 方法 save");
        return productId;
    }
}

CGLIBProxy.java( CGLIB动态代理类
)

package net.cybclass.sp.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLIBProxy implements MethodInterceptor {
    //目标类
    private Object targetObject;
    //绑定关系
    public Object newProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        Enhancer enhancer=new Enhancer();
        //设置代理类的父类(目标类)
        enhancer.setSuperclass(this.targetObject.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建子类(代理对象)
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result=null;
        try
        {
            System.out.println("通过CGLIB动态代理调用"+method.getName()+",打印日志 begin");
            result=methodProxy.invokeSuper(o,args);
            System.out.println("通过CGLIB动态代理调用"+method.getName()+",打印日志 end");
        }
        catch (Exception ex){
            ex.printStackTrace();
        }
        return result;
    }
}

演示

Spring AOP里的静态代理和动态代理,你真的了解嘛?

总结

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理,解耦和易维护。

两种动态代理的区别

  • JDK动态代理:要求目标对象实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以用CGLIB动态代理
  • JDK动态代理是自带的,CGLIB需要引入第三方包
  • CGLIB动态代理,它是内存中构建一个子类对象从而实现对目标对象功能的扩展
  • CGLIB动态代理基于继承来实现代理,所以无法对final类,private方法和static方法实现代理

Spring AOP中的代理使用的默认策略

  • 如果目标对象实现类接口,则默认采用JDK动态代理
  • 如果目标对象没有实现接口,则采用CGLIB进行动态代理

原文 

http://www.cnblogs.com/chenyanbin/p/13306055.html

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Spring AOP里的静态代理和动态代理,你真的了解嘛?

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址