zoukankan      html  css  js  c++  java
  • spring中bean的作用域

    spring bean的作用域

     

    先上配置文件和bean

    spring_scope.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <bean id="xiaoming"
              class="beans.Singer"
              p:name="xiaoming"
              p:song="shihaofengqiu">
    
        </bean>
    
        <bean id="song"
              class="beans.Song"
              scope="prototype"
              >
            <property name="context" value="shihaofengqiu"/>
        </bean>
    
    
    </beans>

    Singer.java

    package beans;
    
    public class Singer {
        private String name;
        private String song;
    
        public Singer(){
            System.out.println("I'm a singer");
    
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setSong(String song) {
            this.song = song;
        }
    
        public void play(){
            System.out.println("My name is:"+this.name);
            System.out.println("My song is:"+this.song);
        }
    
    }

    Song.java

    package beans;
    
    public class Song {
        private String context;
        public Song(){
            System.out.println("this is a song");
        }
    
        public void setContext(String context) {
            this.context = context;
        }
    }

    1.scope(只介绍singletonprototype)

           当一个bean的作用域时singleton的时候,ApplicationContext作为Spring Bean的工厂类,spring会在创建容器时就提前将bean的对象实例化,不管你是否使用它,它都都存在容器bean缓存中。即:

    无论是在其他bean的创建过程的注入该bean,还是多次使用ApplicationContextgetbean方法返回对象实例,都是同一个对象实例,这与单例模式有些相似但不相同。

    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring_scope.xml");

    创建ApplicationContext后,控制台输出:

    但若在<bean/>中将lazy-init置“true”,则容器不会将bean提前实例化。

        <bean id="xiaoming"
              class="beans.Singer"
              p:name="xiaoming"
              p:song="shihaofengqiu"
              lazy-init="true">
    
        </bean>

      

            当一个bean的作用域是prototype时,表示一个bean对应多个对象实例,每次在注入另外一个bean或者调用ApplicationContextgetbean方法时,都会去创建一个新的对象,所以不同于singleton,在创建容器的时候不会预先对bean进行实例化。

     ApplicationContext ctx = new ClassPathXmlApplicationContext("spring_scope.xml");
            Song song1=ctx.getBean("song",Song.class);
            Song song2=ctx.getBean("song",Song.class);

    结果为,创建了两个Song的实例(执行了两次构造方法)

    2.

    这样如果作用域为singletonbean注入作用域为singletonbean,或者prototypebean注入prototypebeanprototypebean注入singletonbean,都于我们从逻辑上都与我们想要的时一样的,但是当singletonbean注入prototypebean就有了一个问题;

    将singer中的song属性改为Song对象的引用,并相应的修改xml配置文件:

    执行代码:

    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring_scope.xml");
            Singer  xiaoming = ctx.getBean("xiaoming",Singer.class);
    //        xiaoming.play();
            Singer xiaoming2 = ctx.getBean("xiaoming",Singer.class);

    结果为:(song的构造函数执行了一次)

    问题就出来了,我们将Song设置为prototype,但是因为注入Song的Singer的作用域为singleton,使得Song在容器创建时,Singer实例后注入的Song就无法创建多个对象,即我们想要的是我们多次创建Singer时返回的是单例的Singer,Singer中的song属性却可以是不同的Song实例。

    spring官方文档:“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.”

    解决这个问题可以有下面的方法:

    <1>继承ApplicationContextAware,ApplicationContextAware的子类中,可以注入ApplicationContext,这样就可以通过ApplicationContextsingletonbean获得prototype作用域的bean

    CommandManager.java

     

    package aware;
    
    //import beans.Singer;
    import beans.Song;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class CommandManager implements ApplicationContextAware {
        private ApplicationContext applicationContext;
    
        public Song createSong(){
            return this.applicationContext.getBean("song",Song.class);
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }
    }

     

    修改singer类变为singer_2.java

    package beans;
    
    import aware.CommandManager;
    
    public class Singer_2{
        private String name;
        private Song song;
        private CommandManager manager;
    
        public Singer_2(){
            System.out.println("I'm a singer");
    
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setSong() {
            this.song = manager.createSong();
        }
    
        public void setManager(CommandManager manager) {
            this.manager = manager;
        }
    
        public void play(){
            System.out.println("My name is:"+this.name);
            System.out.println("My song is:"+this.song.getContext());
        }
    
    }

    xml配置文件中添加

     
    <bean id="xiaoming_2"
              class="beans.Singer_2"
              p:name="xiaoming"
              p:manager-ref="manager"
              lazy-init="true"
              >
    
        </bean>

      <bean id="manager"
    class="aware.CommandManager"/>
     

    运行:

      ApplicationContext ctx = new ClassPathXmlApplicationContext("spring_scope.xml");
           Singer_2 xiaoming = ctx.getBean("xiaoming_2",Singer_2.class);
    //       Singer xiaoming_2 = ctx.getBean("xiaoming",Singer.class);
            xiaoming.setSong();
            xiaoming.setSong()

    可以通过setSong方法,在容器中放回不同的Song现象实例。

    结果:

    这样就可以实现不同作用域的bean的注入

    <2>通过<look-method/>标签和抽象类与方法在singleton中注入prorotypebean,其中的abstract方法返回指定的bean

    Singer_3.java

     

    package beans;
    
    public abstract class Singer_3 {
        private String name;
        private Song song;
    
        public Singer_3(){
        }
    
        public void setName(String name) {
            this.name = name;
    
        }
    
        public void setSong(){
            this.song=createSong();
        }
    
        public abstract Song createSong();
    
    }

     

    xml配置文件中添加:

      <bean id="xiaoming_3"
              class="beans.Singer_3"
              p:name="xiaoming">
            <lookup-method name="createSong" bean="song"/>
        </bean>

    执行:

     ApplicationContext ctx = new ClassPathXmlApplicationContext("spring_scope.xml");
           Singer_3 xiaoming = ctx.getBean("xiaoming_3",Singer_3.class);
            xiaoming.setSong();
            xiaoming.setSong();

    结果:

    <3>通过注解省略<lookup-method/>的配置

      @Lookup("song")
        public abstract Song createSong();

    xml配置文件中添加

    <context:annotation-config/>

     

     

  • 相关阅读:
    C#在与java对接时候的UrlEncode的坑
    sql server 删除大量数据的一次坑爹之旅
    js实现黑客帝国文字下落效果
    第一个SignalR案例
    简单的放天灯动画
    计量单位符号的书写规范【转】
    阿里云OSS搭建移动应用直传服务的.Net C#示例
    UWP Windows10开发更新磁贴和动态更新磁贴
    UWP Windows10开发获取设备位置(经纬度)
    Asp.Net识别手机访问
  • 原文地址:https://www.cnblogs.com/Mrfanl/p/9768122.html
Copyright © 2011-2022 走看看