Spring 高级 Scope失效解决

一、面试问题

1、如果一个单例Bean里面 注入多例 通过单例Bean对象获取到的多例Bean是单例还是多例

二、 失效演示

1、代码

package com.mangoubiubiu.show.a09;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class E {


    @Autowired
    private F1 f1;


    public F1 getF1(){
        return f1;
    }




}
package com.mangoubiubiu.show.a09;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Scope("prototype")
@Component
public class F1 {


}
package com.mangoubiubiu.show.a09;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com.mangoubiubiu.show.a09")
@Slf4j
public class A09Application {

    public static void main(String [] aras){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class);

        E e = context.getBean(E.class);
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());

        context.close();
    }



}

发现它们是同一个对象,而不是期望的多例对象

对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的 F,因此 E 用的始终是第一次依赖注入的 F

二、 失效解决方案

1、使用 @Lazy 生成代理

  • 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象

package com.mangoubiubiu.show.a09;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class E {


    @Autowired
    @Lazy
    private F1 f1;


    public F1 getF1(){
        return f1;
    }




}

发现获取到的是不同的实例Bean

2、@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) 生成代理

在目标类上加

package com.mangoubiubiu.show.a09;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F1 {


}
package com.mangoubiubiu.show.a09;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class E {


    @Autowired
//    @Lazy
    private F1 f1;

    public F1 getF1(){
        return f1;
    }
}

发现获取到的是不同的实例Bean

3、使用对象工厂ObjectFactory获取多实例Bean

package com.mangoubiubiu.show.a09;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class E {


//    @Autowired
////    @Lazy
//    private F1 f1;


//    public F1 getF1(){
//        return f1;
//    }

    @Autowired
    private ObjectFactory<F1> f1;

    public F1 getF1(){
        return f1.getObject();
    }

}

发现获取到的是不同的实例Bean

4、通过容器拿多例Bean

package com.mangoubiubiu.show.a09;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class E {


//    @Autowired
////    @Lazy
//    private F1 f1;


//    public F1 getF1(){
//        return f1;
//    }


//    @Autowired
//    private ObjectFactory<F1> f1;
//
//    public F1 getF1(){
//        return f1.getObject();
//    }
    @Autowired
    private ApplicationContext context;

    public F1 getF1(){
        return  context.getBean(F1.class);
    }
}

收获💡

  1. 单例注入其它 scope 的四种解决方法
    • @Lazy
    • @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
    • ObjectFactory
    • ApplicationContext
  1. 解决方法虽然不同,但理念上殊途同归: 都是推迟其它 scope bean 的获取
posted @ 2022-09-20 22:43  KwFruit  阅读(109)  评论(0编辑  收藏  举报