Spring基础组件的使用——@Scope和@Lazy及其验证

纵然是瞬间 提交于 2019-11-27 15:45:24

@Scope和@Lazy及其验证

@Scope

我们大家都知道Spring容器中注册了一个Bean,在默认情况下都是单实例的,我们可以来验证一下,继续沿用我们之前的例子。下面是我们的配置类

@Configuration
@ComponentScan(value = "com.test")
public class TestConfig {
    @Scope
    @Bean
    public Dog dog(){
        return new Dog("金毛",3);
    }
}

然后我们在测试类中进行测试

public class TestMain {
    @Test
    public void test(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
        Object dog1 = applicationContext.getBean("dog");
        Object dog2 = applicationContext.getBean("dog");
        System.out.println(dog1 == dog2);
    }
}

打印结果为:true

那我们希望我们的Bean设置为多实例怎么办呢?那就需要用到我们的@Scope注解了。
在这里插入图片描述
我们可以看到@Scope共有四个取值,其中prototype就是我们的多实例,让我们来验证一下

@Configuration
@ComponentScan(value = "com.test")
public class TestConfig {
    @Scope("prototype")
    @Bean
    public Dog dog(){
        return new Dog("金毛",3);
    }
}

再次运行我们的测试类,打印结果为: false

另外我们需要注意,我们的多实例Bean其实是懒加载的,就是IOC容器启动时并不会去调用方法创建对象,而是每次获取的时候才回去创建一个对象。我们接下来去验证一下,首先我们将Dog类的构造方法都打印一句话,便于我们查看结果

public class Dog {
    private String name;
    private int age;
    public Dog() {
        System.out.println("调用无参构造方法...");
    }
    public Dog(String name, int age) {
        System.out.println("调用有参构造方法...");
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

接下来配置类中将Bean改为单实例

@Configuration
@ComponentScan(value = "com.test")
public class TestConfig {
    @Scope("singleton")
    @Bean
    public Dog dog(){
        return new Dog("金毛",3);
    }
}

最后我们运行测试类

public class TestMain {
    @Test
    public void test(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames)
            System.out.println(beanName);
    }
}

结果为:

调用有参构造方法...
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
testConfig
userController
userDao
userService
dog

我们看见构造方法的确被调用了,所以单例的Bean在IOC容器启动的时候就会调用方法去创建对象,并放到IOC容器中,以后每次获取直接取获取就可以了,接下来我们去看看多实例,只需将配置类中的Scope的参数改成prototype即可

@Configuration
@ComponentScan(value = "com.test")
public class TestConfig {
    @Scope("prototype")
    @Bean
    public Dog dog(){
        return new Dog("金毛",3);
    }
}

运行上述的测试类,可以发现结果如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
testConfig
userController
userDao
userService
dog

发现Dog的构造方法的确没有被调用。那我们在测试类中调用下多实例试试

public class TestMain {
    @Test
    public void test(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames)
            System.out.println(beanName);
        System.out.println("-------------------------------");
        applicationContext.getBean("dog");
        for (String beanName : beanDefinitionNames)
            System.out.println(beanName);
    }
}

运行结果如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
testConfig
userController
userDao
userService
dog
-------------------------------
调用有参构造方法...
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
testConfig
userController
userDao
userService
dog

我们可以清楚地发现,并验证我们上述有关@Scope的有关的特征。

@Lazy

现在我们万一想要要求单实例Bean懒加载了怎么办呢·,这时候我们就可以使用@Lazy注解了,这个注解肯定是针对单实例的,因为多实例根本就不需要。

@Configuration
@ComponentScan(value = "com.test")
public class TestConfig {
    @Scope("singleton")
    @Lazy
    @Bean
    public Dog dog(){
        return new Dog("金毛",3);
    }
}

我们只需在需要进行懒加载处理的方法上加上@Lazy注解即可,验证方法如上一致,可执行验证。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!