Spring学习记录--------AOP面向切面编程的思想(动态代理)

动态代理的原理

代理设计模式的原理:使用一个代理将原本对象包装起来,然后用该代理对象”取代”原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

实现原理
    jdk动态代理
        主要通过Proxy.newProxyInstance()和InvocationHandler这两个类和方法实现
        实现过程
            创建代理类proxy实现Invocation接口,重写invoke()方法
                调用被代理类方法时默认调用此方法
            将被代理类作为构造函数的参数传入代理类proxy
            调用Proxy.newProxyInsatnce(classloader,interfaces,handler)方法生成代理类
                生成的代理类
                    $Proxy0 extends Proxy implements Person
                    类型为$Proxy0
                    因为已经继承了Proxy,所以java动态代理只能对接口进行代理
                代理对象会实现用户提供的这组接口,因此可以将这个代理对象强制类型转化为这组接口中的任意一个
                通过反射生成对象
            总结: 代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。
    cglib
        生成对象类型为Enhancer
        实现原理类似于 jdk 动态代理,只是他在运行期间生成的代理对象是针
对目标类扩展的子类
    静态代理
        缺点
            如果要代理一个接口的多个实现的话需要定义不同的代理类
            代理类 和 被代理类 必须实现同样的接口,万一接口有变动,代理、被代理类都得修改
        在编译的时候就直接生成代理类
    JDK动态代理和cglib的对比
        CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高
            1.6和1.7的时候,CGLib更快
            1.8的时候,jdk更快
        CGLib在创建对象的时候所花费的时间却比JDK动态代理多
        singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反之,则适合用JDK动态代理
        JDK动态代理是面向接口的,CGLib动态代理是通过字节码底层继承代理类来实现(如果被代理类被final关键字所修饰,那么会失败)
        JDK生成的代理类类型是Proxy(因为继承的是Proxy),CGLIB生成的代理类类型是Enhancer类型
        如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制);
如果要被代理的对象不是实现类,那么Spring会强制使用CGLib来实现动态代理。 

public class LoggingProxy {
    //被代理的对象
    private Object target;
    public LoggingProxy(Object target){
        this.target=target;
    }
    public Object getProxy(){
        //获取被代理对象的类加载器
        ClassLoader classLoader=target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        Object proxy= Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            /**
             * 参数的说明
             * invoke方法说明就是要执行的扩展的攻难
             * proxy:传入的被代理的对象
             * method:调用的方法
             * args:调用方法时候传入的参数
             * @param proxy
             * @param method
             * @param args
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String name = method.getName();
                System.out.println("====Logging: the method" +name+"begin with " + Arrays.toString(args));
                //执行目标的方法即将方法的调用转到被代理的对象上
                Object result = method.invoke(target, args);
                System.out.println("====Logging: the method"+name+"returns"+result);
                return result;
            }
        });
        return proxy;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值