jdk动态代理和cglib动态代理实现及区别

代理模式是一种提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

代理模式又分为:静态代理、jdk动态代理、cglib动态代理。静态代理不讲,因为会产生过多的代理对象,不易维护。而动态代理是动态地在内存中构建代理对象,从字节码上进行处理,从而实现对目标对象的代理功能,接口增加方法时代理对象不受影响 。

代码实现

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.example</groupId>
    <artifactId>test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

JDK动态代理的实现

package test.test;

import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

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

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class TestJDK {
    @org.junit.Test
    public void main() {
        IPerson target=new Person();
        IPerson person=(IPerson) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new PersonInvocationHandler(target));
        person.sing();
    }

    class PersonInvocationHandler implements InvocationHandler{
        private Object target;

        public PersonInvocationHandler(Object target){
            this.target=target;
        }


        @Override
        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
            //方法增强
            System.out.println("鸡你太美真的是泰裤辣!!!!");
            Object invoke = method.invoke(target, objects);
            return invoke;
        }
    }

    interface  IPerson{
        void sing();
    }

    static class  Person implements IPerson{

        @Override
        public void sing() {
            System.out.println("鸡你太美");
        }
    }
}

在这里插入图片描述

结论

1.jdk动态代理需要提供目标类要实现的接口,代理的代理类实现了目标类实现的接口,并且会实现接口所有方法来代码增强,如果目标类未实现接口则无法代理。
2.由运行图结果可以看出,在调用时会先去调用处理类进行增强,再通过反射的方式调用目标类的方法。
3…jdk动态代理会在运行时为目标类生成一个动态代理类$proxy*.class

Cglib代码实现

package test.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.test.context.junit4.SpringRunner;

import java.lang.reflect.Method;

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestCglib {
    @Test
    public void test(){
        Person proxy=(Person) Enhancer.create(Person.class, new PersonMethodInterceptor());
        proxy.sing();
    }

    class PersonMethodInterceptor implements MethodInterceptor{

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("你家鲲鲲泰裤辣");
            Object result = methodProxy.invokeSuper(o, objects);
            return result;
        }
    }

    public static class Person{
        public void sing(){
            System.out.println("鸡你太美");
        }
    }
}

在这里插入图片描述
结论
1.cglib的底层是通过ASM在运行时动态生成目标类的子类,采用继承的方式,所以目标类不能被final关键字修饰,否则无法使用cglib做动态代理
2.cglib动态代理会重写父类所有的方法来代码增强,调用时先通过代理类进行增强,再直接调用父类对应的方法进行调用目标方法

总结

  1. 实现机制:jdk动态代理必须要有目标类要实现的接口,且只提供这一种方式,如果目标类没有实现接口,只能用cglib代理,而无法用jdk动态代理
  2. 底层运行:jdk动态代理利用拦截器(必须实现InvocationHandler)加上反射机制,生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,而cglib的底层是通过ASM框架,在运行时把代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理
  3. 增强机制: jdk动态代理的代理类实现了目标类实现的接口,会通过实现接口所有方法来代码增强。cglib动态代理通过继承机制,重写父类所有的方法来代码增强
  4. 调用机制:jdk动态代理调用时先去调用处理类进行增强,再通过反射的方式调用目标类的方法。cglib动态代理调用时先通过代理类(子类)进行增强,再直接调用父类对应的方法进行调用目标方法。 jdk调用代理方法,是通过反射机制调用,cglib是通过FastClass机制直接调用方法
  5. 性能上:在jdk1.6之前,由于反射调用慢,所以jdk动态代理效率不高,cglib是jdk代理速度的10倍左右。后续jdk版本对jdk动态代理进行了优化,在jdk1.8之前,在调用次数较少时效率高于cglib代理,在大量调用的时候cglib效率会高于jdk动态代理。但是在jdk1.8的时候,jdk动态代理效率已经高于cglib
  6. Spring中档bean实现接口时,会采用jdk动态代理模式;当bean没有实现接口时会采用cglib实现,但是可以通过配置项强制使用cglib
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值