关于java:Configuration-注解的-Full-模式和-Lite-模式

38次阅读

共计 3596 个字符,预计需要花费 9 分钟才能阅读完成。

@Configuration 注解置信各位小伙伴常常会用到,然而大家晓得吗,这个注解有两种不同的模式,一种叫做 Full 模式,另外一种则叫做 Lite 模式。

精确来说,Full 模式和 Lite 模式其实 Spring 容器在解决 Bean 时的两种不同行为。

这两种不同的模式在应用时候的体现齐全不同,明天松哥就来和各位小伙伴捋一捋这两种模式。

1. 概念梳理

首先咱们先来看一下 Spring 官网文档中对 Full 模式和 Lite 模式的一个介绍:

截图来自:https://docs.spring.io/spring-framework/reference/core/beans/…

这个文档次要讲了这样几件事件:

  1. 咱们能够通过在一个办法上增加 @Bean 注解,进而将该办法的返回值裸露给 Spring 容器,在这种场景下,@Bean 注解实际上就是一种通用的工厂办法机制。
  2. 当一个增加了 @Bean 注解的办法位于一个没有增加 @Configuration 注解的类里边时,那么这个增加了 @Bean 注解的办法在解决时就会依照 Lite 模式来解决。
  3. 当一个 Bean 被申明在增加了 @Component 注解的类中,那么会依照 Lite 模式来解决。
  4. 当一个 Bean 被申明在一个一般的类中时(plain old class),依照 Lite 模式来解决(这一点感觉和第二点差不多)。
  5. 在 Lite 模式下,@Bean 注解标记的办法最终不会被 CGLIB 进行代理,就是一个一般的工厂办法,因而,在 @Bean 标记的办法中,不能调用其余 @Bean 注解标记的办法,如果有须要,能够通过办法参数注入本人所须要的 Bean。
  6. 因为 Lite 模式下并不会应用 CGLIB,因而 @Bean 标记的办法能够是 final 类型的。
  7. 在大多数场景下,咱们在一个 @Configuration 注解标记的类中,应用 @Bean 注解向 Spring 容器注册一个 Bean,都是 Full 模式。

官网文档的介绍还是有些形象,接下来松哥通过具体的案例来和大家演示 Full 模式和 Lite 模式的差异。

2. Full 模式

先看 Full 模式,中文也能够称之为 残缺 模式,咱们平时应用时,在一个配置类上增加 @Configuration 注解,且不增加任何额定属性,这就是 Full 模式了。

Full 模式最大的特点是会给配置类通过 CGLIB 生成一个代理,所有被 @Bean 注解标记的办法未来都是通过代理办法进行调用。

假如我有如下配置类:

@Configuration
public class JavaConfig {

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

当初,咱们去 Spring 容器获取这个配置类:

public class JavaDemo {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
        JavaConfig config = ctx.getBean(JavaConfig.class);
        System.out.println("config.getClass() =" + config.getClass());
    }
}

打印后果如下:

大家看到,最终从 Spring 容器中拿到的 JavaConfig 实例并不是原始的 JavaConfig 对象,而是一个被代理的 JavaConfig 对象。

为什么要代理呢?必定是为了实现某些性能。

大家看上面这个案例:

@Configuration
public class JavaConfig {

    @Bean
    User user() {User user = new User();
        user.setDog(dog());
        return user;
    }
    
    @Bean
    Dog dog() {return new Dog();
    }
}

在 Full 模式下,在 user() 办法中调用 dog() 办法的时候,调用的是一个代理对象的 dog 办法,在这个代理对象的 dog 办法中,会首先去查看 Spring 容器中是否存在 Dog 对象,如果存在,则间接应用 Spring 容器中的 dog 对象,就不会真正去执行 dog 办法而获取到一个新的 dog 对象了,如果 Spring 容器中不存在 dog 对象,才会创立新的 dog 对象进去。

一言以蔽之,在 Full 模式下,user 中的 dog 对象和 dog 办法注册到 Spring 容器的 dog 对象是同一个。

在 Full 模式下,因为要给以后类生成代理,而后去代理 @Bean 注解标记的办法,因而,这些 @Bean 注解标记的办法不能是 final 或者 private 类型的,因为 final 或者 private 类型的办法无奈被重写,也就没法生成代理对象,如果增加了 final 或者 private 修饰符,那么会抛出如下异样:

3. Lite 模式

再来看 Lite 模式,这种模式能够认为是一种精简模式。

怎么开启呢?咱们能够去除配置类上的 @Configuration 注解,或者去除之后增加 @Component 注解,又或者应用 @ComponentScan、@ImportResource、@Import 等注解标记类,那么最终都是 Lite 模式:

@Component
public class JavaConfig {

    @Bean
    final User user() {User user = new User();
        user.setDog(dog());
        return user;
    }

    @Bean
    Dog dog() {return new Dog();
    }
}

此时就是 Lite 模式,当初咱们去 Spring 容器中获取这个配置类:

public class JavaDemo {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
        JavaConfig config = ctx.getBean(JavaConfig.class);
        System.out.println("config.getClass() =" + config.getClass());
    }
}

最终打印后果如下:

大家看到,咱们从 Spring 容器中拿到的就是原始的对象,而不是一个被代理过的对象。因而:

  1. 因为 @Bean 注解标记的办法没有被代理,因而,该办法能够是 final 也能够是 private,运行时都不会报错。
  2. 因为 @Bean 办法没有被代理,因而在 user 办法中调用 dog 办法的时候,就间接调用了,这就导致 user 中的 dog 和最终 dog 办法注册到 Spring 容器中的 dog 不是同一个。

针对第二点,如果想要确保 user 中的 dog 和 Spring 容器中的 dog 是同一个,那么能够通过参数将所须要的对象注入进来,相似上面这样:

@Component
public class JavaConfig {

    @Bean
    final User user(Dog dog) {User user = new User();
        user.setDog(dog);
        return user;
    }

    @Bean
    Dog dog() {return new Dog();
    }
}

当 Spring 容器调用 user 办法初始化 User 对象时,发现该办法还有参数,因而会去容器中查找这个参数,找到了间接应用。

另外,咱们也能够在类上增加 @Configuration 注解,然而通过批改属性值来启用 Lite 模式:

@Configuration(proxyBeanMethods = false)
public class JavaConfig {

    @Bean
    final User user(Dog dog) {User user = new User();
        user.setDog(dog);
        return user;
    }

    @Bean
    Dog dog() {return new Dog();
    }
}

如果设置了 proxyBeanMethods 属性为 false,那么也就是 Lite 模式了,其实咱们从属性名称上也能看进去端倪:是否代理 @Bean 注解标记的办法。

4. 小结

总结一下:

  1. Lite 模式下,配置类中的办法就是一般办法,能够是 final 类型,也能够是 private。
  2. Lite 模式下,不须要通过 CGLIB 生成动静代理类,所以启动速度会快一些。
  3. Lite 模式下,一个 @Bean 办法调用另外一个 @Bean 办法,会导致同一个 Bean 被初始化两次。
  4. Full 模式下,会给配置类生成一个动静代理类,配置类中的所有办法都将被动静代理,因而配置类中的办法不能是 final 或者 private 的。
  5. Full 模式下,一个 @Bean 办法调用另外一个 @Bean 办法,动静代理办法会先去容器中查看是否存在该 Bean,如果存在,则间接应用容器中的 Bean,否则才会去创立新的对象。

日常开发中,咱们应用较多的是 Full 模式。

正文完
 0