java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring @Configuration proxyBeanMethods=false

Spring @Configuration proxyBeanMethods=false问题

作者:catoop

这篇文章主要介绍了Spring @Configuration proxyBeanMethods=false问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

Spring @Configuration proxyBeanMethods=false

开门见山,本文没有原理只有结论,要点如下:

1、proxyBeanMethods=true,Full 全模式,如不指定则默认为 true,@Bean 修饰的方法会被代理。

2、proxyBeanMethods=false,Lite 轻量级模式,@Bean 修饰的方法不会被代理。

3、仔细观察 proxyBeanMethods 这个词语,顾名思义,是代理方法的(仅指代被 @Bean 注解的方法哦),所以它的作用肯定是跟当前这个 @Configuration 中的 Bean方法有关的。

4、在同一个 @Configuration 配置类中,值为 true 时,某方法直接调用其他的 Bean方法获取 Bean(方法返回值是Bean对象)时,不会创建新的 Bean,而是会从 Spring 容器中直接提取(如果容器中没有则会同放入容器中)。

5、当值为 false 时,与第4点区别的是 “像调用普通的Java方法一样,每次都会完整的执行方法,然后返回一个全新的对象”,因为 false 的意思就是不要代理我的方法(不代理就没有前置逻辑就原汁原味方法调用呗)。

6、如果你的同一个 Configuration 配置类中的多个Bean方法之间没有这样互相调用的需求,那么建议使用 Lite轻量级模式(设置 proxyBeanMethods=false),以提高 SpringBoot 的启动速度和性能。

如下代码示例中

是否设置 proxyBeanMethods = false 决定了 同学你好... 被输出一次还是两次。

@Configuration(proxyBeanMethods = false)
public class TestConfig {

    @Bean
    public Student getStudent() {
        System.out.println("同学你好...");
        return new Student();
    }
    
    @Bean
    public Teacher getTeacher() {
        System.out.println("getTeacher() 方法被执行...");
        return new Teacher(getStudent());
    }
    
}

实验验证@Configuration中proxyBeanMethods = true和proxyBeanMethods = false的区别

proxyBeanMethods 注释说明

如果看完英文注释完全明白什么意思,OK可以直接关闭该页面了。

因为我看完了一头雾水,所以才有下面的实验。

其实注释文档写得很明白,看完本文再看注释就豁然开朗了。

测试完整代码

package com.testProxyBeanMethods;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@SpringBootApplication
public class TestApplication {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext ctx = SpringApplication.run(TestApplication.class, args);
        while (true) {
            ctx.getBean(HelloConfiguration.class).test();
            Thread.sleep(1000L);
        }
    }
}


@Configuration(proxyBeanMethods = false)
class HelloConfiguration {

    //spring 容器托管的bean
    @Bean("person")
    //Scope可以不用加,默认就是单例
    public Person person() {
        System.out.println("===:make person " + System.currentTimeMillis());
        return new Person();
    }

    /**
     * 测试直接调用person()方法
     */
    public void test() {
        Person p = person();
        System.out.println("+++person hash code:" + System.identityHashCode(p));
        System.out.println("+++person name:" + p.getName());
    }

}


/**
 * 定义一个class
 */
class Person {
    private String name;

    private static int i = 0;

    public Person() {
        name = String.valueOf(++i);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

当 proxyBeanMethods = true , person() 调用后返回的是同一个对象

当 proxyBeanMethods = fase , person() 调用一次生成一个新对象

结果说明

1.proxyBeanMethods=true 时, Spring用cglib 对HelloConfiguration 所有有@Bean的方法进行了增强,就算你直接调用person()方法,因为cglib生成的代理类不会直接执行person()里面的new Person() ,他会检查是否有单例,有直接返回。

2. proxyBeanMethods=false 时,没有对person()方法增强,那么调用person()方法,就相当于调用了一个普通方法,每次调用都是直接执行了new Person() , 获取的person对象都是new出来的,这个对象与spring容器无关(没有被spring容器托管), 因为@Bean,所以spring容器里面还有一个托管的person

3. 当我们自己写框架或者工具的时候,如果某个对象在框架内部可以不是单例的,那么可以proxyBeanMethods=false ,用于优化性能和减少不必要的代理开销

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文