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/>

     

     

  • 相关阅读:
    CREATE AGGREGATE
    技术文档列表
    jQuery 判断表单中多个 input text 中至少有一个不为空
    Java实现 蓝桥杯 算法提高 奥运会开幕式
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
  • 原文地址:https://www.cnblogs.com/Mrfanl/p/9768122.html
Copyright © 2011-2022 走看看