bean的作用域_Spring注解驱动开发之三——@Scope指定作用域、@Lazy懒加载、@Conditional根据条件创建实例…

  • Post author:
  • Post category:其他


eedf82280e43235cc7e3b4a9355756cf.png

本文包含以下内容:

  1. 使用@Scope指定作用域测试

  2. 使用@Lazy 配置懒加载测试

  3. 使用@Conditional根据条件创建实例测试

  4. 拓展@Scope、@Lazy、@Conditional

1.使用@Scope指定作用域测试

1)默认情况下,Spring 创建实例的作用域是

单例的

,通过一下测试得到结论:

@Test  public void test02(){    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);//    String[] definitionNames = applicationContext.getBeanDefinitionNames();//    for (String name : definitionNames) {//      System.out.println(name);//    }//        System.out.println("ioc容器创建完成....");    Object bean = applicationContext.getBean("person");    Object bean2 = applicationContext.getBean("person");    System.out.println(bean == bean2);  }

运行结果,如下图所示:

aff2fec34e59ea10f90c4648099a8b90.png

2)使用
@Scope
()修改

作用域

,作用域可用参数

prototype:

多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;

singleton:

单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从

容器

(map.get())中拿,

request:

同一次请求创建一个实例

session:

同一个session创建一个实例

将创建实例的方法上添加上@Scope(“prototype”) 表示多实例的

@Scope("prototype")  @Bean("person")  public Person person01(){    return new Person("张三", 25);  }

再次运行得到结果如下

d2df794cf047c5377400932beee2029c.png

2.使用@Lazy 配置懒加载测试

在默认的作用域为单例的模式下,可以使用
@Lazy 进行懒加载,即调用的时候,再创建实例对象

  @Lazy  @Bean("person")  public Person person01(){    System.out.println("给容器中添加Person....");    return new Person("张三", 25);  }

配置懒加载前:

403e16b6377462eed304ace0a6256d9a.png

配置懒加载后:

14b1933d3bf2e35ebc74f88b813cf443.png

3.使用@Conditional根据条件创建实例测试

可以通过@Conditional 判断时候满足对应条件再进行创建,即如果要判断当前运行系统来创建指定的Bean 。1)创建
Condition 接口的实现类,作为判断条件的类:

//判断是否windows系统public class WindowsCondition implements Condition {  @Override  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {    Environment environment = context.getEnvironment();    String property = environment.getProperty("os.name");    if(property.contains("Windows")){      return true;    }    return false;  }}

创建判断Linux 系统的实现类,其中两个参数:

ConditionContext

:判断条件能使用的上下文(环境)如获得获得类加载器、当前环境信息、Bean注册类等信息

AnnotatedTypeMetadata

:注释信息

//判断是否linux系统public class LinuxCondition implements Condition {  /**   * ConditionContext:判断条件能使用的上下文(环境)   * AnnotatedTypeMetadata:注释信息   */  @Override  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {    // TODO是否linux系统    //1、能获取到ioc使用的beanfactory    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();    //2、获取类加载器    ClassLoader classLoader = context.getClassLoader();    //3、获取当前环境信息    Environment environment = context.getEnvironment();    //4、获取到bean定义的注册类    BeanDefinitionRegistry registry = context.getRegistry();        String property = environment.getProperty("os.name");        //可以判断容器中的bean注册情况,也可以给容器中注册bean    boolean definition = registry.containsBeanDefinition("person");    if(property.contains("linux")){      return true;    }        return false;  }}

2)建立不同条件对应的Bean

  @Conditional(WindowsCondition.class)  @Bean("bill")  public Person person01(){    return new Person("Bill Gates",62);  }  @Conditional(LinuxCondition.class)  @Bean("linus")  public Person person02(){    return new Person("linus", 48);  }

3)建立测试方法

@Test  public void test03(){    String[] namesForType = applicationContext.getBeanNamesForType(Person.class);    ConfigurableEnvironment environment = applicationContext.getEnvironment();    //动态获取环境变量的值;Windows 10    String property = environment.getProperty("os.name");    System.out.println(property);    for (String name : namesForType) {      System.out.println(name);    }        Map<String, Person> persons = applicationContext.getBeansOfType(Person.class);    System.out.println(persons);      }

获得结果:

ab53c050eb35c6b7180f04f6daf8120f.png

4)修改启动参数,模拟linux 系统启动

a7d80784455a48c491bedf6dff13e409.png

添加配置 -Dos.name=linux

fc83e782b46cb8c079b3dfbc7e418719.png

运行结果:

0c53ce25ff255886a789316a4e8ab3f1.png

5)也可以将注解放在类上,对于所有当前类下所有的@Bean 注解,满足条件才进行创建

//类中组件统一设置。满足当前条件,这个类中配置的所有bean注册才能生效;@Conditional({WindowsCondition.class})public class MainConfig2 {}

4.拓展@Scope、@Lazy、@Conditional

1)@Scope使用场景:几乎
90%以上的业务使用singleton单实例就可以,所以spring默认的类型也是singleton,singleton虽然保证了全局是一个实例,对性能有所提高,但是如果实例中有非静态变量时,会导致线程安全问题,共享资源的竞争当设置为prototype时:每次连接请求,都会生成一个bean实例,也会导致一个问题,当请求数越多,

性能会降低

,因为创建的实例,导致GC频繁,gc时长增加2)@Lazy主要作用:@Lazy注解注解的作用主要是减少springIOC容器启动的加载时间当出现循环依赖时,也可以添加@Lazy3)@Conditional
应用场景:在一些需要条件满足才是实例化的类中,使用此注解,我曾经在项目中需要根据不同的场景使用不同的mq中间件的时候使用过,在mq的实例化bean上,加上此注解,根据配置文件的不同,来决定这个bean是否加载至ioc容器中。


-END-

42cd61a1dea98d2726bcb64484987b64.png


可以关注我的公众号,免费获取价值1980元


学习资料


点击“在看”,学多少都不会忘~

a382dc9ca9d5ea648c6008648d463ddc.png