静态代理和动态代理有什么区别?--乐字节java

代理模式

​ 代理模式在 Java 开发中是一种比较常见的设计模式。设计目的旨在为服务类与客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。如租房的例子:房客、中介、房东。对应于代理模式中即:客户类、代理类 、委托类(被代理类)。

​ 为某一个对象(委托类)提供一个代理(代理类),用来控制对这个对象的访问。委托类和代理类有一个共同的父类或父接口。代理类会对请求做预处理、过滤,将请求分配给指定对象。

​ 生活中常见的代理情况:

​ 租房中介、婚庆公司等

​ 代理模式的两个设计原则:

1. 代理类 与 委托类 具有相似的行为(共同)

2. 代理类增强委托类的行为

SpringAOP-01.png

​ 常用的代理模式:

​ 1. 静态代理

​ 2. 动态代理

静态代理

​ 某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。

代理的三要素

​ a、有共同的行为(结婚) - 接口

​ b、目标角色(新人) - 实现行为

​ c、代理角色(婚庆公司) - 实现行为 增强目标对象行为

静态代理的特点

​ 1、目标角色固定

​ 2、在应用程序执行前就得到目标角色

​ 3、代理对象会增强目标对象的行为

​ 4、有可能存在多个代理 引起"类爆炸"(缺点)

静态代理的实现

定义行为(共同) 定义接口
/**
 * 定义行为
 */
public interface Marry {
    public void toMarry();
}
目标对象(实现行为)
/**
 * 静态代理 ——> 目标对象
 */
public class You implements  Marry {
    // 实现行为
    @Override
    public void toMarry() {
        System.out.println("我要结婚了...");
    }
}
代理对象(实现行为、增强目标对象的行为)
/**
 * 静态代理 ——> 代理对象
 */
public class MarryCompanyProxy implements Marry {

    // 目标对象
    private Marry marry;
    // 通过构造器将目标对象传入
    public MarryCompanyProxy(Marry marry) {
        this.marry = marry;
    }

    // 实现行为
    @Override
    public void toMarry() {
        // 增强行为
        before();
                
        // 执行目标对象中的方法
        marry.toMarry();
        
        // 增强行为
        after();
    }

    /**
     * 增强行为
     */
    private void after() {
        System.out.println("新婚快乐,早生贵子!");
    }

    /**
     * 增强行为
     */
    private void before() {
        System.out.println("场地正在布置中...");
    }
}
通过代理对象实现目标对象的功能
// 目标对象
You you = new You();
// 构造代理角色同时传入真实角色
MarryCompanyProxy marryCompanyProxy = new MarryCompanyProxy(you);
// 通过代理对象调用目标对象中的方法
marryCompanyProxy.toMarry();

​ 静态代理对于代理的角色是固定的,如dao层有20个dao类,如果要对方法的访问权限进行代理,此时需要创建20个静态代理角色,引起类爆炸,无法满足生产上的需要,于是就催生了动态代理的思想。

如有疑问,可加入群:10803-55292,输入暗号13,即可有大佬帮助

动态代理

​ 相比于静态代理,动态代理在创建代理对象上更加的灵活,动态代理类的字节码在程序运行时,由Java反射机制动态产生。它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为反射机制可以生成任意类型的动态代理类。代理的行为可以代理多个方法即满足生产需要的同时又达到代码通用的目的

​ 动态代理的两种实现方式:

​ 1. JDK 动态代理

​ 2. CGLIB动态代理

动态代理的特点

  1. 目标对象不固定
  2. 在应用程序执行时动态创建目标对象
  3. 代理对象会增强目标对象的行为

JDK动态代理

注:JDK动态代理的目标对象必须有接口实现

newProxyInstance

Proxy类:

​ Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下操作方法:

/*
	返回一个指定接口的代理类的实例方法调用分派到指定的调用处理程序。 (返回代理对象)
		loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
		interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果					   我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这					组接口中的方法了
		h:一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口。每个代理实例都具有一个			 关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序            的 invoke 方法(传入InvocationHandler接口的子类)
*/
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
获取代理对象
public class JdkHandler implements InvocationHandler {

    // 目标对象
    private Object target; // 目标对象的类型不固定,创建时动态生成
    // 通过构造器将目标对象赋值
    public JdkHandler(Object target) {
        this.target = target;
    }

    /**
     *  1、调用目标对象的方法(返回Object)
     *  2、增强目标对象的行为
     * @param proxy 调用该方法的代理实例
     * @param method  目标对象的方法
     * @param args  目标对象的方法形参
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 增强行为
        System.out.println("==============方法前执行");

        // 调用目标对象的方法(返回Object)
        Object result = method.invoke(target,args);

        // 增强行为
        System.out.println("方法后执行==============");

        return result;
    }


    /**
     * 得到代理对象
     * public static Object newProxyInstance(ClassLoader loader,
     *                                       Class<?>[] interfaces,
     *                                       InvocationHandler h)
     *      loader:类加载器
     * 	    interfaces:接口数组
     * 	    h:InvocationHandler接口 (传入InvocationHandler接口的实现类)
     *
     *
     * @return
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
}
通过代理对象实现目标对象的功能
// 目标对象
You you = new You();
// 获取代理对象
JdkHandler jdkHandler = new JdkHandler(you);
Marry marry = (Marry) jdkHandler.getProxy();
// 通过代理对象调用目标对象中的方法
marry.toMarry();	
问:Java动态代理类中的invoke是怎么调用的?

答:在生成的动态代理类$Proxy0.class中,构造方法调用了父类Proxy.class的构造方法,给成员变量invocationHandler赋值,$Proxy0.class的static模块中创建了被代理类的方法,调用相应方法时方法体中调用了父类中的成员变量InvocationHandler的invoke()方法。

注:JDK的动态代理依靠接口实现,如果有些类并没有接口实现,则不能使用JDK代理。

CGLIB 动态代理

​ JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能使用JDK的动态代理,cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

添加依赖

在pom.xml文件中引入cglib的相关依赖

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
定义类

实现MethodInterceptor接口

public class CglibInterceptor implements MethodInterceptor {

    // 目标对象
    private Object target;
    // 通过构造器传入目标对象
    public CglibInterceptor(Object target) {
        this.target = target;
    }

    /**
     * 获取代理对象
     * @return
     */
    public Object getProxy() {
        // 通过Enhancer对象的create()方法可以生成一个类,用于生成代理对象
        Enhancer enhancer = new Enhancer();
        // 设置父类 (将目标类作为其父类)
        enhancer.setSuperclass(target.getClass());
        // 设置拦截器 回调对象为本身对象
        enhancer.setCallback(this);
        // 生成一个代理类对象,并返回
        return enhancer.create();
    }

    /**
     * 拦截器
     * 	1、目标对象的方法调用
     * 	2、增强行为
     * @param object  由CGLib动态生成的代理类实例
     * @param method  实体类所调用的被代理的方法引用
     * @param objects 参数值列表
     * @param methodProxy  生成的代理类对方法的代理引用
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object object, Method method, Object[] objects, 
                            MethodProxy methodProxy) throws Throwable {

        // 增强行为
        System.out.println("==============方法前执行");

        // 调用目标对象的方法(返回Object)
        Object result = methodProxy.invoke(target,objects);

        // 增强行为
        System.out.println("方法后执行==============");

        return result;
    }

}
调用方法
// 目标对象
You you = new You();
CglibInterceptor cglibInterceptor = new CglibInterceptor(you);
Marry marry = (Marry) cglibInterceptor.getProxy();
marry.toMarry();

User user = new User();
CglibInterceptor cglibInterceptor = new CglibInterceptor(user);
User u = (User) cglibInterceptor.getProxy();
u.test();

JDK代理与CGLIB代理的区别

  • JDK动态代理实现接口,Cglib动态代理继承思想
  • JDK动态代理(目标对象存在接口时)执行效率高于Ciglib
  • 如果目标对象有接口实现,选择JDK代理,如果没有接口实现选择Cglib代理

image

<think>好的,我现在需要回答用户关于Java静态代理动态代理区别的问题。首先,我得回忆一下这两种代理的基本概念,然后比较它们的区别静态代理是手创建的代理类,每个代理类对应一个目标类。用户可能想知道为什么需要手创建,以及有什么优缺点。比如,如果目标类有多个方法,代理类需要实现相同接口并重写所有方法,这样会增加代码量,尤其是当接口方法很多时。但静态代理的好处是直观,容易理解控制。 动态代理则是运行时生成的,不需要手编写代理类。Java提供了Proxy类InvocationHandler接口来实现。动态代理的核心在于反射机制,通过InvocationHandler的invoke方法来统一处理所有方法调用。这样无论目标接口有多少方法,代理类都不需要显式实现,减少了重复代码。用户可能想知道动态代理是如何工作的,比如Proxy.newProxyInstance方法如何生成代理对象,以及InvocationHandler的作用。 接下来要比较两者的区别。首先从实现方式来说,静态代理需要手编写代理类,动态代理是自生成的。然后是灵活性,动态代理更灵活,可以代理多个不同的接口,而静态代理每个代理类只能代理一个接口。维护性方面,动态代理在接口变化时不需要修改代理类,而静态代理需要同步修改。性能方面,静态代理可能更快,因为直接调用方法,而动态代理涉及反射调用,可能有性能损耗。依赖关系方面,静态代理需要实现目标接口,而动态代理通过反射获取接口信息。 用户可能还关心应用场景。静态代理适合接口方法少或需要细粒度控制的场景,动态代理适合AOP、日志、事务等需要统一处理的场景。另外,动态代理只能代理接口,不能代理类,这也是一个需要注意的点。而静态代理可以代理具体类,如果不需要接口的话。 需要举例说明吗?比如静态代理需要编写一个实现相同接口的类,并在每个方法中调用目标对象的方法,同时添加额外逻辑。动态代理则通过InvocationHandler在invoke方法中添加逻辑,然后由Proxy创建代理对象。 有没有可能混淆的地方?比如动态代理的局限性,比如只能代理接口,不能代理类。这时候可能需要提到CGLIB这样的库,它通过继承来实现代理类,但这是第三方库,不是Java标准库的内容。不过用户的问题可能仅限于Java自带的动态代理,所以暂时不需要展开。 需要检查是否有遗漏的区别点,比如生成的代理类数量、代码冗余度、设计模式的不同(静态代理属于代理模式,动态代理属于动态代理模式,或者反射机制的应用)。 最后,总结两者的区别,确保涵盖实现方式、灵活性、维护成本、性能、依赖关系适用场景等方面。确保语言简洁明了,结构清晰,便于用户理解。</think>### Java 静态代理动态代理的核心区别 #### 1. **实现方式** - **静态代理** 手编写代理类,需**显式实现目标接口**,并在代理类中**硬编码增强逻辑**。 ```java // 目标接口 public interface Calculator { int add(int a, int b); } // 静态代理类(手实现接口) public class CalculatorProxy implements Calculator { private Calculator target; public CalculatorProxy(Calculator target) { this.target = target; } @Override public int add(int a, int b) { System.out.println("Before add"); int result = target.add(a, b); // 委托给目标对象 System.out.println("After add"); return result; } } ``` - **动态代理** 通过 `Proxy` 类 `InvocationHandler` 接口**态生成代理对象**,增强逻辑**集中写在 `invoke` 方法**中。 ```java // 动态代理处理器 public class LogHandler implements InvocationHandler { private Object target; public LogHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before " + method.getName()); Object result = method.invoke(target, args); // 反射调用目标方法 System.out.println("After " + method.getName()); return result; } } // 态生成代理对象 Calculator proxy = (Calculator) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new LogHandler(target) ); ``` --- #### 2. **灵活性对比** | 特性 | 静态代理 | 动态代理 | |--------------------|-----------------------------------|-----------------------------------| | **代理范围** | 每个代理类只能代理一个接口 | 可代理任意接口(通过反射) | | **代码冗余** | 需为每个接口编写代理类 | 一个处理器类处理所有接口方法 | | **接口变化影响** | 接口修改时,需同步修改代理类 | 接口修改时,代理逻辑无需调整 | --- #### 3. **性能差异** - **静态代理**:直接调用目标方法,无反射开销,**执行效率更高**。 - **动态代理**:依赖反射调用方法,**性能略低**(但现代JVM优化后差距较小)。 --- #### 4. **适用场景** - **静态代理适用** ✅ 接口方法少 ✅ 需精确控制某个方法的增强逻辑 ✅ 目标类无接口(可通过继承实现代理,但需非final类) - **动态代理适用** ✅ 接口方法多或频繁变 ✅ 需要统一处理多个方法的增强逻辑(如日志、事务) ✅ 框架级AOP实现(如Spring默认使用动态代理--- #### 5. **本质区别总结** | 维度 | 静态代理 | 动态代理 | |------------|-----------------------------------|-----------------------------------| | **实现** | 手编码代理类 | 运行时态生成代理类 | | **核心** | 代理模式 | 反射机制 + 字节码生成 | | **局限性** | 代理类与目标类强耦合 | 只能代理接口(JDK动态代理的限制) | --- ### 扩展说明 - **动态代理的底层实现**:JDK动态代理通过生成 `$Proxy0` 类文件实现,可通过 `-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true` 导出生成的代理类。 - **突破接口限制**:若需代理类而非接口,可使用 **CGLIB** 库(基于继承实现动态代理)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值