JDK动态代理和Cglib动态代理

1. JDK动态代理

原理:利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

实现:JDK动态代理的条件是被代理对象必须实现接口。需要创建代理类需要实现InvocationHandler接口。

public interface IProducer {
    void saleProduct(float money);

    void afterService(float money);
}
public class Producer  implements IProducer{
    public void saleProduct(float money) {
        System.out.println("销售产品,销售了"+money);
    }

    public void afterService(float money) {
        System.out.println("售后服务,花了"+money);
    }
}
public class Client {
    public static void main(String[] args) {
        final Producer producer = new Producer();
        final IProducer proxyProducer  = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 作用:执行被代理对象的任何接口方法都会经过此方法
                     * 方法参数的含义:
                     * @param proxy  :代理对象的引用
                     * @param method :当前执行的方法
                     * @param args:当前执行方法所需的参数
                     * @return    :和被代理对象有相同的返回值
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object value =null;
                        //提供增强的代码
                        Float money = (Float) args[0];
                        //判断当前方法是不是销售
                        if("saleProduct".equals(method.getName())){
                            value = method.invoke(producer,1000*0.8f);
                        }
                        return value;
                    }
                });
        proxyProducer.saleProduct(1000f);
    }
}

运行结果:

销售产品,销售了800.0

2. CGLIB动态代理

原理:利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

实现:CGLIB动态代理可以不实现接口,直接对Java类进行代理。CGLIB动态代理需要实现MethodInterceptor接口,重写intercept()方法。

public class Producer2 {//cglib代理不用实现接口
    public void saleProduct(float money) {
        System.out.println("销售产品,销售了"+money);
    }

    public void afterService(float money) {
        System.out.println("售后服务,花了"+money);
    }
}
public class Client2 {
    public static void main(String[] args) {
        final Producer2 producer2 = new Producer2();
        Producer2 cglibProducer2 = (Producer2) Enhancer.create(producer2.getClass(), new MethodInterceptor() {
            /**
             * 执行被代理对象的任何方法都会经过该方法
             * @param o  和基于接口代理中的proxy一样
             * @param method
             * @param objects  和基于接口代理中的args一样
             *  以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
             * @param methodProxy:当前执行方法的代理对象
             * @return
             * @throws Throwable
             */
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object value =null;

                //提供增强的代码
                Float money = (Float) objects[0];
                //判断当前方法是不是销售
                if("saleProduct".equals(method.getName())){
                    value = method.invoke(producer2,money*0.8f);
                }
                return value;
            }
        });
        cglibProducer2.saleProduct(10000f);
    }
}

运行结果:

销售产品,销售了8000.0

如果将代理的方法改为final修饰,final public void saleProduct(float money),输出就会变为:

销售产品,销售了10000.0

原因:CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,对于final类或方法,是无法继承的。

3. JDK动态代理和CGLIB动态代理的区别

JDK动态代理只能对实现了接口的类生成代理,而不能针对类。

CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final,对于final类或方法,是无法继承的。

4. Spring AOP何时使用JDK或CGLIB?

1)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
2)如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
3)如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。

5. Spring 如何强制使用CGLIB实现AOP

1)添加CGLIB库(aspectjrt-xxx.jar、aspectjweaver-xxx.jar、cglib-nodep-xxx.jar)

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>

2)在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值