Spring Bean作用域

@Single 单例的

在Spring容器创建一个组件的时候,默认情况下只会创建一次,不同的组件公用一个对象,即单例的模式。

代码一

public interface Dao {
    void query();
}

代码二

@Component
public class daoImpl implements Dao {
    public void query() {
        System.out.println("Impl");
    }
}

代码三


@Service
public class ServiceImpl {
    @Autowired
    private Dao dao;
    public void prient(){
        System.out.println(dao.hashCode());
    }
}



@Service
public class ServiceTwo {

    @Autowired
    private Dao dao;
    public void prient(){
        System.out.println(dao.hashCode());
    }
}


代码四

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext acc=
                new AnnotationConfigApplicationContext(Spring.class);
        ServiceImpl service= (ServiceImpl) acc.getBean("serviceImpl");
        service.prient();
        ServiceTwo service2= (ServiceTwo) acc.getBean("serviceTwo");
        service2.prient();
    }
}

输出的内容是一样的
输出相同的hasCode .
将实现类daoImpl 重新修改一下做成作用域是原型的方式(prototype)
代码五



@Component
@Scope("prototype")
public class daoImpl implements Dao {
    public void query() {
        System.out.println("Impl");
    }
}

将会输出不同的HasCode
在这里插入图片描述
通过官方的两个图片来详细描述一下Single和Prototype,首先看一下Single的。
single
解释一下图片,容器在初始化的时候只给第一个初始化的Bean开辟一个内存区域来存放这个实例,其它的Bean要想再创建一个Bean时不会开辟新的内存区域,会使用原来的。
Prototype 原型的方式:
在这里插入图片描述
容器在每一次创建一个Bean的时候都会去开辟一个新的内存区域,来存放对象,也就是同一个类的不同bean在Spring容器中也是不同的。

依赖和被依赖不同的作用域会造成问题

官网描述:
In most application scenarios, most beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with another non-singleton bean, you typically handle the dependency by defining one bean as a property of the other. A problem arises when the bean lifecycles are different. Suppose singleton bean A needs to use non-singleton (prototype) bean B, perhaps on each method invocation on A. The container creates the singleton bean A only once, and thus only gets one opportunity to set the properties. The container cannot provide bean A with a new instance of bean B every time one is needed.
大概解释一下,大多数情况下单例的Bean依赖单例的,原型的依赖原型的。如果一个单例的依赖了一个非单例的,由于Spring在初始化的过程中只给单例的类一次创建机会,那么依赖的非单例也就失效了。
看一下相关代码:
代码一

@Component
@Scope("prototype")
public class daoImpl implements Dao {
    public void query() {
        System.out.println("Impl");
    }
}

非单例的。
代码二

@Service
public class ServiceImpl {
    @Autowired
    private Dao dao;
    public void prient(){
        System.out.println(dao.hashCode());
    }
}

需要依赖的类时单例的。
测试代码

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext acc=
                new AnnotationConfigApplicationContext(Spring.class);
        ServiceImpl service= (ServiceImpl) acc.getBean("serviceImpl");
        service.prient();
        ServiceImpl service2= (ServiceImpl) acc.getBean("serviceImpl");
        service2.prient();
    }
}

运行结果

726408598
726408598

Process finished with exit code 0

若何解决呢?
官网给出的解决方案是重写ApplicationContextAware的setApplicationContext方法


@Service
public class ServiceImpl implements ApplicationContextAware {

    private ApplicationContext applicationContext;
    public void prient(){
         Dao dao=createCommand();
        System.out.println(dao.hashCode());
    }
    protected Dao createCommand() {

        return this.applicationContext.getBean("dao", Dao.class);
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

运行结果

1594791957
1988644427

Process finished with exit code 0

由于上面的侵入性太高了,可以使用 @Lookup注解。

@Service
public abstract class ServiceImpl  {
    public void prient(){
         Dao dao=createDao();
        System.out.println(dao.hashCode());
    }
    @Lookup
    protected abstract   Dao createDao();
}

如果不想使用抽象方法可以返回一个null。

@Service
public  class ServiceImpl  {
    public void prient(){
         Dao dao=createDao();
        System.out.println(dao.hashCode());
    }
    @Lookup
    protected  Dao createDao(){
        return null;
    }
}

这样也可以解决这种问题。

1677207406
1979274004

Process finished with exit code 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值