真懂Spring的@Configuration配置类?你可能自我感觉太良好(中)

简介: 真懂Spring的@Configuration配置类?你可能自我感觉太良好(中)

使用举例


@Configuration
public class AppConfig {
    @Bean
    public User user(){
        User user = new User();
        user.setName("A哥");
        user.setAge(18);
        return user;
    }
}
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = context.getBean(User.class);
        System.out.println(user.getClass());
        System.out.println(user);
    }
}



输出:

class com.yourbatman.fullliteconfig.User
User{name='A哥', age=18}



Full模式和Lite模式

Full模式和Lite模式均是针对于Spring配置类而言的,和xml配置文件无关。值得注意的是:判断是Full模式 or Lite模式的前提是,首先你得是个容器组件。至于一个实例是如何“晋升”成为容器组件的,可以用注解也可以没有注解,本文就不展开讨论了,这属于Spring的基础知识。


Lite模式

当@Bean方法在没有使用@Configuration注释的类中声明时,它们被称为在Lite模式下处理。它包括:在@Component中声明的@Bean方法,甚至只是在一个非常普通的类中声明的Bean方法,都被认为是Lite版的配置类。@Bean方法是一种通用的工厂方法(factory-method)机制。


和Full模式的@Configuration不同,Lite模式的@Bean方法不能声明Bean之间的依赖关系。因此,这样的@Bean方法不应该调用其他@Bean方法。每个这样的方法实际上只是一个特定Bean引用的工厂方法(factory-method),没有任何特殊的运行时语义。


何时为Lite模式


官方定义为:在没有标注@Configuration的类里面有@Bean方法就称为Lite模式的配置。透过源码再看这个定义是不完全正确的,而应该是有如下case均认为是Lite模式的配置类:


  1. 类上标注有@Component注解
  2. 类上标注有@ComponentScan注解
  3. 类上标注有@Import注解
  4. 类上标注有@ImportResource注解
  5. 若类上没有任何注解,但类内存在@Bean方法


以上case的前提均是类上没有被标注@Configuration,在Spring 5.2之后新增了一种case也算作Lite模式:


6.标注有@Configuration(proxyBeanMethods = false),注意:此值默认是true哦,需要显示改为false才算是Lite模式


细心的你会发现,自Spring5.2(对应Spring Boot 2.2.0)开始,内置的几乎所有的@Configuration配置类都被修改为了@Configuration(proxyBeanMethods = false),目的何为?答:以此来降低启动时间,为Cloud Native继续做准备。

优缺点


优点:


  • 运行时不再需要给对应类生成CGLIB子类,提高了运行性能,降低了启动时间
  • 可以该配置类当作一个普通类使用喽:也就是说@Bean方法 可以是private、可以是final


缺点:


  • 不能声明@Bean之间的依赖,也就是说不能通过方法调用来依赖其它Bean
  • (其实这个缺点还好,很容易用其它方式“弥补”,比如:把依赖Bean放进方法入参里即可)

代码示例


主配置类:


@ComponentScan("com.yourbatman.fullliteconfig.liteconfig")
@Configuration
public class AppConfig {
}


准备一个Lite模式的配置:

@Component
// @Configuration(proxyBeanMethods = false) // 这样也是Lite模式
public class LiteConfig {
    @Bean
    public User user() {
        User user = new User();
        user.setName("A哥-lite");
        user.setAge(18);
        return user;
    }
    @Bean
    private final User user2() {
        User user = new User();
        user.setName("A哥-lite2");
        user.setAge(18);
        // 模拟依赖于user实例  看看是否是同一实例
        System.out.println(System.identityHashCode(user()));
        System.out.println(System.identityHashCode(user()));
        return user;
    }
    public static class InnerConfig {
        @Bean
        // private final User userInner() { // 只在lite模式下才好使
        public User userInner() {
            User user = new User();
            user.setName("A哥-lite-inner");
            user.setAge(18);
            return user;
        }
    }
}


测试用例:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        // 配置类情况
        System.out.println(context.getBean(LiteConfig.class).getClass());
        System.out.println(context.getBean(LiteConfig.InnerConfig.class).getClass());
        String[] beanNames = context.getBeanNamesForType(User.class);
        for (String beanName : beanNames) {
            User user = context.getBean(beanName, User.class);
            System.out.println("beanName:" + beanName);
            System.out.println(user.getClass());
            System.out.println(user);
            System.out.println("------------------------");
        }
    }
}


结果输出:


1100767002
313540687
class com.yourbatman.fullliteconfig.liteconfig.LiteConfig
class com.yourbatman.fullliteconfig.liteconfig.LiteConfig$InnerConfig
beanName:userInner
class com.yourbatman.fullliteconfig.User
User{name='A哥-lite-inner', age=18}
------------------------
beanName:user
class com.yourbatman.fullliteconfig.User
User{name='A哥-lite', age=18}
------------------------
beanName:user2
class com.yourbatman.fullliteconfig.User
User{name='A哥-lite2', age=18}
------------------------


小总结


  • 该模式下,配置类本身不会被CGLIB增强,放进IoC容器内的就是本尊
  • 该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式
  • 该模式下,配置类内部不能通过方法调用来处理依赖,否则每次生成的都是一个新实例而并非IoC容器内的单例
  • 该模式下,配置类就是一普通类嘛,所以@Bean方法可以使用private/final等进行修饰(static自然也是阔仪的)


Full模式


在常见的场景中,@Bean方法都会在标注有@Configuration的类中声明,以确保总是使用“Full模式”,这么一来,交叉方法引用会被重定向到容器的生命周期管理,所以就可以更方便的管理Bean依赖。

相关文章
|
16天前
|
Java 开发者 微服务
手写模拟Spring Boot自动配置功能
【11月更文挑战第19天】随着微服务架构的兴起,Spring Boot作为一种快速开发框架,因其简化了Spring应用的初始搭建和开发过程,受到了广大开发者的青睐。自动配置作为Spring Boot的核心特性之一,大大减少了手动配置的工作量,提高了开发效率。
37 0
|
2月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
48 4
|
2月前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
38 0
|
2月前
|
Java API Spring
在 Spring 配置文件中配置 Filter 的步骤
【10月更文挑战第21天】在 Spring 配置文件中配置 Filter 是实现请求过滤的重要手段。通过合理的配置,可以灵活地对请求进行处理,满足各种应用需求。还可以根据具体的项目要求和实际情况,进一步深入研究和优化 Filter 的配置,以提高应用的性能和安全性。
|
26天前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
30 1
|
2月前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
147 1
|
2月前
|
存储 Java 程序员
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
本文详细讲解了Spring框架中IOC容器如何存储和取出Bean对象,包括五大类注解(@Controller、@Service、@Repository、@Component、@Configuration)和方法注解@Bean的用法,以及DI(依赖注入)的三种注入方式:属性注入、构造方法注入和Setter注入,并分析了它们的优缺点。
33 0
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
|
2月前
|
XML Java 数据格式
手动开发-简单的Spring基于注解配置的程序--源码解析
手动开发-简单的Spring基于注解配置的程序--源码解析
47 0
|
2月前
|
XML Java 数据格式
手动开发-简单的Spring基于XML配置的程序--源码解析
手动开发-简单的Spring基于XML配置的程序--源码解析
82 0
|
2月前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
42 0