Full @Configurationlite @Bean mode 是 Spring Java Config 中两个非常有意思的概念。

先来看一下官方文档关于这两者的相关内容:


相关定义

  • lite @Bean mode :当@Bean方法在没有使用@Configuration注解的类中声明时称之为lite @Bean mode
  • Full @Configuration:如果@Bean方法在使用@Configuration注解的类中声明时称之为Full @Configuration

有何区别

总结一句话,Full @Configuration中的@Bean方法会被CGLIB所代理,而 lite @Bean mode中的@Bean方法不会被CGLIB代理。

举个例子

有一普通Java类,现在分别使用Full @Configurationlite @Bean mode这两种模式注册到Spring容器中。

public class User {
    public User() {
        System.out.println("user create... hashCode :" + this.hashCode());
    }
}

Full @Configuration

配置类:

@Configuration
public class AppConfig {

    @Bean
    public User user() {
        return new User();
    }

    @Bean
    public String name(User user) {
        System.out.println(user.hashCode());
        System.out.println(user().hashCode());
        return "123";
    }
}

主程序:

public class FullMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = context.getBean(User.class);
        System.out.println(user.hashCode());
        context.close();
    }
}

运行结果:

user create... hashCode :1709537756
1709537756
1709537756
1709537756

分析:@Bean是在使用了@Configuration注解的类上被声明的,属于Full @Configuration@Configuration类中的@Bean地方会被CGLIB进行代理。Spring会拦截该方法的执行,在默认单例情况下,容器中只有一个Bean,所以我们多次调用user()方法,获取的都是同一个对象。

注意:被CGLIB的方法是不能被声明为privatefinal,因为CGLIB是通过生成子类来实现代理的,privatefinal方法是不能被子类Override的,也就是说,Full @Configuration模式下,@Bean的方法是不能不能被声明为privatefinal,不然在启动时Spring会直接报错。

lite @Bean mode

配置类:

@Component
public class LiteAppConfig {

    @Bean
    public User user() {
        System.out.println("user() 方法执行");
        return new User();
    }

    @Bean
    public String name(User user) {
        System.out.println("name(User user) 方法执行");
        System.out.println(user.hashCode());
        System.out.println("再次调用user()方法: " + user().hashCode());
        return "123";
    }
}

主程序:

public class LiteMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LiteAppConfig.class);
        User user = context.getBean(User.class);
        System.out.println(user.hashCode());
        context.close();
    }
}

运行结果:

user() 方法执行
user create... hashCode :254413710
name(User user) 方法执行
254413710
user() 方法执行
user create... hashCode :1793329556
再次调用user()方法: 1793329556
254413710

分析:在lite @Bean mode模式下, @Bean方法不会被CGLIB代理,所以多次调用user()会生成多个user对象。

使用建议

为了防止出现一些奇怪的问题,建议都使用Full @Configuration


欢迎关注个人公众号:
你真的懂Spring Java Config 吗?Full @Configuration vs lite @Bean mode-LMLPHP

10-13 22:59