Spring框架中的@Configuration参数proxyBeanMethods

在这里插入图片描述

一.概念分析

在Spring框架中,@Configuration注解用于声明一个Java类作为配置类,它替代了传统的XML配置方式。通过@Configuration注解标记的类可以包含@Bean注解,用于定义Spring容器中的Bean对象。而在@Configuration注解中,有一个非常重要的属性proxyBeanMethods,它控制着@Configuration类中@Bean方法的代理行为。让我们对这个属性进行非常详细的介绍:

  1. @Configuration注解:

    • @Configuration是Spring框架提供的一个元注解,用于表示一个类是一个配置类。
    • 配置类通常包含@Bean注解,定义了创建和配置Bean的方法。
    • Spring会扫描@Configuration类,并将其中的@Bean方法注册为Spring容器中的Bean。
  2. @Bean注解:

    • @Bean是用于定义Spring Bean的注解。
    • 在@Configuration类中,通过@Bean注解标记的方法会返回一个对象,该对象将被注册到Spring容器中作为Bean。
    • 默认情况下,Spring容器会使用方法名作为Bean的名称,也可以通过@Bean的name属性指定Bean的名称。
  3. proxyBeanMethods属性:

    • proxyBeanMethods是@Configuration注解的一个属性,它用于控制@Bean方法的代理行为。
    • 在Spring 5及之前的版本,默认值为true,从Spring 5开始,默认值为true。
    • 该属性接受一个布尔值,设置为true表示启用代理模式,设置为false表示禁用代理模式。
  4. 代理模式(Proxy Mode):

    • 在@Configuration类中,当proxyBeanMethods属性设置为true时,Spring会对@Configuration类进行CGLIB代理。
    • CGLIB是一个强大的第三方库,用于在运行时生成Java类的子类。
    • 对@Configuration类进行代理后,调用@Bean方法时,Spring会检查是否已经存在该Bean,如果存在,则直接返回已存在的Bean,否则调用方法创建新的Bean并缓存起来。
    • 这样做的好处是,当多个@Bean方法之间存在相互调用时,可以保证对相同Bean的调用不会重复执行,提高了应用程序的性能。
  5. 禁用代理模式:

    • 当proxyBeanMethods属性设置为false时,禁用了CGLIB代理。
    • 在禁用代理模式下,Spring容器每次调用@Bean方法时都会执行一次方法体,不会缓存Bean对象。
    • 这样做的好处是,每次调用@Bean方法都会重新创建一个新的Bean对象,适用于那些需要每次返回新实例的场景。
  6. 如何选择代理模式:

    • 选择是否启用代理模式取决于应用程序的需求。
    • 如果@Configuration类中的@Bean方法之间没有相互调用,并且Bean的创建不涉及复杂的逻辑,可以考虑启用代理模式,以提高性能。
    • 如果@Bean方法之间有相互调用,或者Bean的创建逻辑比较复杂,为了保证每次调用都返回新的实例,可以禁用代理模式。

示例代码:

@Configuration
public class MyConfiguration {
    
    

    @Bean
    public MyBean myBean() {
    
    
        return new MyBean();
    }

    @Bean
    public AnotherBean anotherBean() {
    
    
        return new AnotherBean(myBean()); 
    }
}

总结:
@Configuration注解用于声明配置类,其中的@Bean注解用于定义Spring容器中的Bean对象。proxyBeanMethods属性控制@Bean方法的代理行为。启用代理模式可以提高性能,禁用代理模式可以保证每次调用@Bean方法都返回新的实例。选择是否启用代理模式取决于应用程序的需求。
##二. 场景再现
为了更好地理解proxyBeanMethods的不同使用场景,我们创建一个简单的示例来演示它们的效果。我们将创建一个Spring应用程序,其中包含一个@Configuration类,其中定义了两个@Bean方法,并在不同场景下测试proxyBeanMethods的行为。

场景一:启用代理模式

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = true)
public class ProxyEnabledConfiguration {
    
    

    @Bean
    public MyBean myBean() {
    
    
        return new MyBean();
    }

    @Bean
    public AnotherBean anotherBean() {
    
    
     //开启代理,实例Bean会被缓存,直接返回已存在的Bean
        return new AnotherBean(myBean()); 
    }
}

场景二:禁用代理模式

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class ProxyDisabledConfiguration {
    
    

    @Bean
    public MyBean myBean() {
    
    
        return new MyBean();
    }

    @Bean
    public AnotherBean anotherBean() {
    
    
    //禁用代理,每次都会生成新的实例Bean
        return new AnotherBean(myBean()); 
    }
}

MyBean.java:

public class MyBean {
    
    
    private static int instanceCounter = 0;
    private int instanceNumber;

    public MyBean() {
    
    
        instanceNumber = ++instanceCounter;
        System.out.println("Creating MyBean instance: " + instanceNumber);
    }

    public int getInstanceNumber() {
    
    
        return instanceNumber;
    }
}

AnotherBean.java:

public class AnotherBean {
    
    
    private MyBean myBean;

    public AnotherBean(MyBean myBean) {
    
    
        this.myBean = myBean;
        System.out.println("Creating AnotherBean instance using MyBean with instance number: " + myBean.getInstanceNumber());
    }
}

测试类:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    
    

    public static void main(String[] args) {
    
    
        // proxyBeanMethods enabled
        AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(ProxyEnabledConfiguration.class);
        AnotherBean anotherBean1 = context1.getBean(AnotherBean.class);

        // proxyBeanMethods disabled
        AnnotationConfigApplicationContext context2 = new AnnotationConfigApplicationContext(ProxyDisabledConfiguration.class);
        AnotherBean anotherBean2 = context2.getBean(AnotherBean.class);
    }
}

在启用代理模式的场景中(ProxyEnabledConfiguration),MyBean只会被实例化一次,因为AnotherBean会复用已经创建的MyBean实例,从控制台输出可以看到:

Creating MyBean instance: 1
Creating AnotherBean instance using MyBean with instance number: 1

而在禁用代理模式的场景中(ProxyDisabledConfiguration),MyBean会被每次调用都实例化一次,因为没有缓存,从控制台输出可以看到:

Creating MyBean instance: 1
Creating MyBean instance: 2
Creating AnotherBean instance using MyBean with instance number: 1
Creating MyBean instance: 3
Creating AnotherBean instance using MyBean with instance number: 2

通过这两个场景的对比,我们可以清楚地看到proxyBeanMethods属性的影响。

概念性东西确实很绕,有时候我们想要探寻底层原理,往往会碰壁,但是,不能放弃,多读几遍,多查查资料,兼容众家之长,把它拿下,吸收,彻底理解,慢慢的,一步一步来,不要着急!!!

猜你喜欢

转载自blog.csdn.net/weixin_53742691/article/details/132051388