Spring-Bean 作用域

作用域

在这里插入图片描述

作用域案例

public class BeanScopeDemo {
    @Autowired
    @Qualifier("singletonPerson")
    Person person;

    @Autowired
    @Qualifier("prototypePerson")
    Person person1;

    @Autowired
    @Qualifier("prototypePerson")
    Person person2;

    @Autowired
    Set<Person> personSet;
    /**
     * 创建bean
     * @return
     */
    public static Person createPerson(){
        Person person = new Person();
        person.setId(System.currentTimeMillis());
        person.setName(System.currentTimeMillis()+"");
        return person;
    }

    /**
     * 查找
     * @param context
     */
    public static void scopeBeanLookUp(AnnotationConfigApplicationContext context){
        for (int i = 0; i < 3; i++) {
            Person prototypePerson = context.getBean("prototypePerson", Person.class);
            System.out.println("prototypePerson" + prototypePerson);
            Person singletonPerson = context.getBean("singletonPerson", Person.class);
            System.out.println("singletonPerson" + singletonPerson);
        }
    }
    private static void scopedBeansByInjection(AnnotationConfigApplicationContext context) {
        BeanScopeDemo bean = context.getBean(BeanScopeDemo.class);
        System.out.println(bean.person);
        System.out.println(bean.person1);
        System.out.println(bean.person2);
        System.out.println(bean.personSet);
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(BeanScopeDemo.class);
        context.refresh();
        scopeBeanLookUp(context);
        scopedBeansByInjection(context);
        context.close();
    }

    /**
     * 默认scope 就是singleton
     * @return
     */
    @Bean
    public static Person singletonPerson(){
        return createPerson();
    }
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public static Person prototypePerson(){
        return createPerson();
    }
}

运行结果:
在这里插入图片描述
结论:
1 singleton Bean 无论依赖查找还是依赖注入,均为同一个对象
2 prototype Bean 无论依赖查找还是依赖注入,均为新生成的对象
3 如果为集合类型,则单例和原型对象各一个

单例模式和原型模式生命周期的不同

public class Person implements BeanNameAware {
    private Long id;
    private String name;
    /**
     * 不需要序列化
     */
    private transient String beanName;
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @PostConstruct
    public void init() {
        System.out.println(this.beanName + " : init execute");
    }
    @PreDestroy
    public void destroy() {
        System.out.println(this.beanName + " : destroy execute");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

改造Person以后我们继续调用上面的方法:
在这里插入图片描述
我们可以得到下面的结论:
1 原型和单例模式都是会执行postconstruct
2 原型模式的生命周期不能被spring完全管理,不会执行销毁方法

如果我们需要销毁,采用下面这种方式来操作

public class BeanScopeDemo implements DisposableBean {
    @Autowired
    @Qualifier("singletonPerson")
    Person person;

    @Autowired
    @Qualifier("prototypePerson")
    Person person1;

    @Autowired
    @Qualifier("prototypePerson")
    Person person2;

    @Autowired
    Map<String, Person> personMap;
    @Autowired
    ConfigurableListableBeanFactory beanFactory;

    /**
     * 创建bean
     *
     * @return
     */
    public static Person createPerson() {
        Person person = new Person();
        person.setId(System.currentTimeMillis());
        person.setName(System.currentTimeMillis() + "");
        return person;
    }

    /**
     * 查找
     *
     * @param context
     */
    public static void scopeBeanLookUp(AnnotationConfigApplicationContext context) {
        for (int i = 0; i < 3; i++) {
            Person prototypePerson = context.getBean("prototypePerson", Person.class);
            System.out.println("prototypePerson" + prototypePerson);
            Person singletonPerson = context.getBean("singletonPerson", Person.class);
            System.out.println("singletonPerson" + singletonPerson);
        }
    }

    private static void scopedBeansByInjection(AnnotationConfigApplicationContext context) {
        BeanScopeDemo bean = context.getBean(BeanScopeDemo.class);
        System.out.println(bean.person);
        System.out.println(bean.person1);
        System.out.println(bean.person2);
        System.out.println(bean.personMap);
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(BeanScopeDemo.class);
        context.refresh();
        scopeBeanLookUp(context);
        scopedBeansByInjection(context);
        context.close();
    }

    /**
     * 默认scope 就是singleton
     *
     * @return
     */
    @Bean
    public static Person singletonPerson() {
        return createPerson();
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public static Person prototypePerson() {
        return createPerson();
    }

    @Autowired
    ConfigurableListableBeanFactory beanFactory;
    @Override
    public void destroy() throws Exception {
        this.person1.destroy();
        this.person2.destroy();
        for (Map.Entry<String, Person> entry : this.personMap.entrySet()) {
            String key = entry.getKey();
            BeanDefinition bd = beanFactory.getBeanDefinition(key);
            if (bd.isPrototype()) {
                entry.getValue().destroy();
            }

        }
    }
}

运行结果:
在这里插入图片描述
可以看到原型模式的对象也被销毁了。

自定义Scope

1 首先自定义Scope

public class ThreadLocalScope implements Scope {
    public static final String SCOPE_NAME = "thread_local";
    private NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal<Map<String, Object>>("thread-local-scope") {
       public Map<String, Object> initialValue() {
           return new HashMap<>();
       }
    };
    private Map<String, Object> getContext() {
        return threadLocal.get();
    }
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> context = getContext();
        Object object = context.get(name);
        if (object == null) {
            object = objectFactory.getObject();
            context.put(name, object);
        }
        return object;
    }
    @Override
    public Object remove(String name) {
        return getContext().remove(name);
    }
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        remove(name);
    }
    @Override
    public Object resolveContextualObject(String key) {
        return getContext().get(key);
    }
    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }
}

2 查找方式

public class ThreadLocalScopeDemo {
    /**
     * 默认scope 就是singleton
     *
     * @return
     */
    @Bean
    @Scope(ThreadLocalScope.SCOPE_NAME)
    public static Person singletonPerson() {
        return createPerson();
    }
    /**
     * 创建bean
     *
     * @return
     */
    public static Person createPerson() {
        Person person = new Person();
        person.setId(System.currentTimeMillis());
        person.setName(System.currentTimeMillis() + "");
        return person;
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(ThreadLocalScopeDemo.class);
        // 注册工厂 也就是 ThreadLocalScope.SCOPE_NAME 这个注入会走这里
        context.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
        });
        context.refresh();
        scopeBeansLookUp(context);
        context.close();
    }
    private static void scopeBeansLookUp(ApplicationContext context) {
    	// 这里开启三个现场去查找
        for (int i = 0; i < 3; i ++) {
            Thread thread = new Thread(() -> {
                Person person = context.getBean( Person.class);
                System.out.println(Thread.currentThread().getId()+ " : " + person);
            });
            thread.start();
            try {
                thread.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

结果:
在这里插入图片描述
也就几说我们可以减少对象的创建因为我们在Threadlocal里面存储了,所以线程内部是可以复用的,不存在线程安全问题。
比如SimpleDateFormat是非线程安全的,所以可以采用这种方式来实现。

拓展提示:SpingCloud中的@RefreshScope
参考资料:小马哥核心编程思想

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值