JDK代理和cglib代理

Java中代理模式有两种:动态代理和静态代理。静态代理有JDK静态代理,而动态代理分为JDK动态代理和cglib动态代理。在Spring的AOP实现中,主要应用了JDK动态代理以及CGLIB动态代理。记录一下今天学习的收获。
代理一般就是给目标类的方法在执行之前处理消息,过滤消息,也就是通常说的增强目标类的方法。之后还能进行消息的后置处理。代理类类本身不实现服务,而是通过调用真实目标类中的方法来提供服务。

JDK静态代理源码的实现:

1、业务接口:

package com.static_agent;
public interface TargetInterface {
    public void addBook();
}

2、业务实现:

package com.static_agent;

public class Target implements TargetInterface {
    @Override
    public void addBook() {
        System.out.println("增加一本图书成功------");
    }
}

3、代理类:

package com.static_agent;

public class Proxy implements TargetInterface{
    //真实目标对象
    private Target target;
    public Proxy(Target target) {
        this.target = target;
    }

    @Override
    public void addBook() {
        System.out.println("代理类方法,进行了增强。。。");
        System.out.println("事务开始。。。");
        // 调用目标类的方法;
        target.addBook();
        System.out.println("处理结束。。。");
    }
}

4、测试代码:

package com.static_agent;

public class StaticProxyTest {
    public static void main(String[] args) {
        //创建真实对象
        Target target = new Target();
        //创建代理对象
        Proxy proxy = new Proxy(target);
        //使用代理对象进行方法的执行
        proxy.addBook();

    }
}

5、执行结果
在这里插入图片描述

JDK动态代理源码的实现

1、业务接口:

package com.dynamic_agent;
public interface TargetInterface {
    public void save();
}

2、业务实现:

package com.dynamic_agent;
public class Target implements TargetInterface {
    @Override
    public void save() {
        System.out.println("save Running-----");
    }
}

3、增强实现类:

package com.dynamic_agent;
public class Advice {
    public void before(){
        System.out.println("前置增强--------");
    }

    public void afterReturning(){
        System.out.println("后置增强--------");
    }
}


4、测试代码:

package com.dynamic_agent;

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

public class DynamicProxyTest {
    public static void main(String[] args) {
        //创建目标对象
        Target target = new Target();
        //增强对象
        Advice advice = new Advice();

        //返回值就是动态代理生成的对象
        /*        目标对象和代理对象是兄弟关系,俩都是接口的子类*/

        TargetInterface proxy= (TargetInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //目标对象类加载器
                target.getClass().getInterfaces(),//目标对象相同的接口字节码对象数组
                new InvocationHandler() {
                    //调用代理对象的任何方法,实质执行的都是  invoke()  方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //前置增强
                        advice.before();
                        //执行目标方法
                        Object invoke = method.invoke(target, args);
                        //后置增强
                        advice.afterReturning();
                        return invoke;
                    }
                }
        );

        //调用代理对象的方法
        proxy.save();
        //以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
        System.out.println(proxy.getClass().getName());
    }
}


5、执行结果
在这里插入图片描述

cglib动态代理源码的实现

1、导入依赖:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.3.6</version>
</dependency>

2、目标类:

package com.dynamic_cglib;
public class Target{

    public void save() {
        System.out.println("cglib save Running-----");
    }
}


3、增强实现类:

package com.dynamic_cglib;
public class Advice {
    public void before(){
        System.out.println("cglib 前置增强--------");
    }

    public void afterReturning(){
        System.out.println("cglib 后置增强--------");
    }
}


4、测试代码:

package com.dynamic_cglib;


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 DynamicCglibProxy {
    public static void main(String[] args) {
        //创建目标对象
        Target target = new Target();
        //增强对象
        Advice advice = new Advice();

        //返回值就是动态代理生成的对象  基于cglib
        //1、创建一个增强器
        Enhancer enhancer = new Enhancer();
        //2、设置父类(目标类)
        enhancer.setSuperclass(target.getClass());
        //3、设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                advice.before();//前置
                Object invoke = method.invoke(target, args);//执行目标
                advice.afterReturning();//后置
                return invoke;
            }
        });
        //4、创建代理对象
        Target proxy = (Target) enhancer.create();
        proxy.save();
        System.out.println(proxy.getClass().getName());
    }

}


5、执行结果
在这里插入图片描述

关于动态代理总结:1、原理

jdk静态代理直接是代理类实现目标对象的接口,完成代理,耦合度较高。

jdk动态代理是接口代理,目标接口需要有一个类来实现自己的抽象方法,代理类和目标类是兄弟关系。

jdk动态代理会根据目标对象生成一个代理类,并实现了该业务接口的jdk代理类,该类的字节码会被传进去的ClassLoader加载,创建了jdk代理对象实例,

jdk代理对象实例在创建时,业务代理对象实例会被赋值给Proxy类,jdk代理对象实例也就有了业务代理对象实例,同时jdk代理对象实例通过反射根据被代理类的业务方法创建了相应的Method对象m(可能有多个)。当jdk代理对象实例调用业务方法,如proxy.saver();这个会先把对应的m对象作为参数传给invoke()方法(就是invoke方法的第二个参数),调用了jdk代理对象实例的invoke()回调方法,在invoke方法里面再通过反射来调用被代理对象的因为方法,也就是Object invoke = method.invoke(target, args);。

cglib动态代理是继承代理,通过ASM字节码框架修改字节码生成新的子类,重写并增强方法的功能。

2、优缺点

 jdk静态代理类只能为一个被代理类服务,如果需要代理的类比较多,就会出现代码冗余的问题。jdk静态代理在编译时产生class文件,运行时无需产生,可直接使用,效率好。

 jdk动态代理必须实现接口,通过反射来动态代理方法,消耗系统性能。但是无需产生过多的代理类,避免了重复代码的产生,系统更加灵活。

 cglib动态代理无需实现接口,通过生成子类字节码来实现,比反射快一点,没有性能问题。但是由于cglib会继承被代理类,所以被代理类不能是final类,被代理方法不能是final,并且会带着一点侵入性。

因此,cglib的应用更加广泛一点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值