【Spring】IOC/DI中常用的注解@Lazy、@Scope与@Conditional

发布于:2024-04-28 ⋅ 阅读:(21) ⋅ 点赞:(0)

目录

1、@Lazy 懒加载bean

1.1、与@component配合使用

1.2、与@Bean注解配合使用

2、@Scope bean的作用域

2.1、不指定@Scope

2.2、指定@Scope为 prototype

3、@Conditional 条件注解

1、@Lazy 懒加载bean

        @Lazy用于指定单例bean实例化的时机,在没有指定此注解时,单例bean会在容器初始化时就被创建。而当使用此注解后,单例对象的创建时机会在该bean在被第一次使用时创建,并且只创建一次。第二次及以后获取使用就不再创建。

        在实际开发场景中,并不是所有bean都要一开始就被创建的,有些可以等到使用时才创建。此时就可以使用该注解实现。此注解只对单例bean有用,原型bean时此注解不起作用。

        原型bean是在每次请求时都会创建一个新的实例,而不像单例bean那样只有一个实例。因此,使用@Lazy注解对原型bean没有实际意义,因为即使不使用该注解,每次请求都会创建一个新的实例。所以,@Lazy注解只对那些在容器初始化时就被创建的单例bean有用。

@Lazy注解可以作用在类上、方法上、构造器上、方法参数上、成员变量中。

@Lazy注解作用于类上时,通常与@Component及其衍生注解配合使用。
@Lazy注解作用于方法上时,通常与@Bean注解配合使用。
 

示例:

没有使用@Lazy注解时

@Component  //把E配置成bean
public class E {
    public E(){
        //当调用这个无参构造函数创造bean时,就会执行这条打印语句
        System.out.println("E");
    }
}


//测试类
@SpringBootTest(classes = TestLazy.class)
@ComponentScan("com.lt.lazyDemo")//我的E类是在"com.lt.lazyDemo"这个包下,所以我这里填这个路径,你们改成自己的E类的路径
public class TestLazy {

    @Test
    public void test(){

    }
}

1.1、与@component配合使用

@Component
@Lazy
public class E {
    public E(){
        //当调用这个无参构造函数创造bean时,就会执行这条打印语句
        System.out.println("E");
    }
}


//测试类的代码不变

1.2、与@Bean注解配合使用

//把E类上面的注解都注释掉


//测试类
@SpringBootTest(classes = TestLazy.class)
//使用@Bean的方式配置bean时,@ComponentScan注解就可用可不用了
//@ComponentScan("com.lt.lazyDemo")
public class TestLazy {

    @Bean
    @Lazy
    public E e1(){
        return new E();
    }

    @Test
    public void test(){

    }

}

使用@Lazy注解的好处:在spring中,默认的bean会在启动的时候就会创建,如果说某些Bean非常大,如果在启动的时候就创建就会影响启动速度,就可以把那些大的Bean设置成懒加载,这样可以优化启动速度

2、@Scope bean的作用域

        @Scope注解是 Spring IOC 容器中的一个作用域,在 Spring IOC 容器中,他用来配置Bean实例的作用域对象。@Scope 具有以下几种作用域:

singleton 单实例的(单例)(默认)

----全局有且仅有一个实例

prototype 多实例的(多例)

---- 每次获取Bean的时候会有一个新的实例

reqeust   同一次请求

----request:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效

session   同一个会话级别

---- session:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效

这里只需要掌握singleton和prototype这两种就行了,其他两种感兴趣的可以自己去了解了解

@Scope注解作用于类上时,通常与@Component及其衍生注解配合使用。

@Component
@Scope(value = "prototype")
public class F {
    public F(){
        System.out.println("F");
    }
}

@Scope注解作用于方法上时,通常与@Bean注解配合使用。

@Bean
@Scope(value = "prototype")
public F f(){
    return new F();
}

@Scope注解使用示例:

2.1、不指定@Scope

        在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉模式加载(容器启动实例就创建好了)

public class F {
    public F(){
        System.out.println("F");
    }
}


//测试类TestScope
@SpringBootTest(classes = TestScope.class)
public class TestScope {

    @Bean
    public F f(){
        return new F();
    }

    @Test
    public void test(@Autowired F f, @Autowired F ff, @Autowired F fff){
        System.out.println(f);
        System.out.println(ff);
        System.out.println(fff);
    }
}

2.2、指定@Scope为 prototype

        指定@Scope为 prototype 表示为多实例的,是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是 在第一次使用的时候才会创建)

//F类的代码没有变


//测试类TestScope
@SpringBootTest(classes = TestScope.class)
public class TestScope {

    @Bean
    // 默认单例@Scope("singleton")
    // @Scope("prototype")多例
    @Scope(value = "prototype")
    public F f(){
        return new F();
    }

    @Test
    public void test(@Autowired F f, @Autowired F ff, @Autowired F fff){
        System.out.println(f);
        System.out.println(ff);
        System.out.println(fff);
    }
}

        多例模式会比单例模式对内存造成更大的一个使用,内存开销会比较大。但是有时候不得不使用多例模式,因为单例模式在有些情况下可能会造成线程不安全

3、@Conditional 条件注解

        @Conditional注解:可以用在任何类型或者方法上面,通过@Conditional注解可以配置一些条件判断,当所有条件都满足的时候,被@Conditional标注的目标才会被spring容器处理。

        比如可以通过@Conditional来控制bean是否需要注册,控制被@Configuration标注的配置类是需要需要被解析等

        @Conditional 注解上有一个 value 属性,其值只能为 Condition 类型的数组,使用 @Conditional 时必须进行指定。Condition 是指具体的条件,条件是否匹配由 Condition 进行控制,其是一个接口,需要我们自己实现。

@Conditional使用的3步骤

(1)自定义一个类,实现Condition或ConfigurationCondition接口,实现matches方法

(2)在目标对象上使用@Conditional注解,并指定value的值为自定义的Condition类型

(3)启动spring容器加载资源,此时@Conditional就会起作用了

示例:

//自定义类ConditionalService
public class ConditionalService {
    public ConditionalService(){
        System.out.println("ConditionalService");
    }
}



//Condition接口的实现类MyCondition
public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true;  //返回true为bean生效,false为bean不生效
    }
}


@SpringBootTest(classes = TestConditional.class)
public class TestConditional {

    @Bean
    //必须指定一个实现了Condition接口的类,由matches方法的返回值决定当前Bean是否生效
    @Conditional(MyCondition.class)
    public ConditionalService conditionalService(){
        return new ConditionalService();
    }

    @Test
    public void test(@Autowired(required = false) ConditionalService conditionalService){
        System.out.println(conditionalService);
    }
}

推荐:

【Spring】IOC/DI中常用的注解@Order与@DependsOn-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/138167160?spm=1001.2014.3001.5501【Spring】依赖注入(DI)时常用的注解@Autowired和@Value_配置类 使用@autowired 类型注入-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/137784706?spm=1001.2014.3001.5501【Java网络编程】TCP通信(Socket 与 ServerSocket)和UDP通信的三种数据传输方式_socket tcpserver-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/137926277?spm=1001.2014.3001.5501


网站公告

今日签到

点亮在社区的每一天
去签到