zoukankan      html  css  js  c++  java
  • Spring入门之三-------SpringIoC之Scopes

    一、singleton和prototype

    public class Bean1 {
    
        public Bean1() {
            System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
        }
    }
    Bean1

    1. singleton:

    每个IoC容器只创建一个该类的Bean。

    <bean id="bean1Singleton" class="com.imooc.springClass3.iocOthers.Bean1" scope="singleton"/>

    public class BeanTest {
        @Test
        public void testBean() throws Exception {
            for (int i = 0; i < 10; i++) {
                Bean1 bean1Singleton = context.getBean("bean1Singleton", Bean1.class);
                System.out.println("bean1Singleton = " + bean1Singleton);
            }
        }
    }

    输出

    bean1Singleton = com.imooc.springClass3.iocOthers.Bean1@696da30b
    bean1Singleton = com.imooc.springClass3.iocOthers.Bean1@696da30b
    bean1Singleton = com.imooc.springClass3.iocOthers.Bean1@696da30b
    ......

    可以看到,每个Bean对象的地址都是一样的。

    2. prototype

    每次从IoC容器中请求Bean都会创建一个新的实例,包括将Bean注入到另一个Bean中或通过Spring上下文执行getBean方法

    <bean id="bean1Prototype" class="com.imooc.springClass3.iocOthers.Bean1" scope="prototype"/>
    public class BeanTest {
        @Test
        public void testBean() throws Exception {
            for (int i = 0; i < 10; i++) {
                Bean1 bean1Prototype = context.getBean("bean1Prototype", Bean1.class);
                System.out.println("bean1Prototype = " + bean1Prototype);
            }
        }
    }

    输出

    Bean1:com.imooc.springClass3.iocOthers.Bean1@5f9b2141 has been created
    bean1Prototype = com.imooc.springClass3.iocOthers.Bean1@5f9b2141
    Bean1:com.imooc.springClass3.iocOthers.Bean1@247d8ae has been created
    bean1Prototype = com.imooc.springClass3.iocOthers.Bean1@247d8ae
    Bean1:com.imooc.springClass3.iocOthers.Bean1@48974e45 has been created
    bean1Prototype = com.imooc.springClass3.iocOthers.Bean1@48974e45
    ......

    可以看到,每个Bean对象的地址都是不同的。

    二、request、session、application、websocket

    只有在web环境下才可以使用这四个作用域,要引入web环境要求做如下配置(web.xml):

    如果使用DispatcherServlet,则不需要增加其他任何配置,例如:

    <servlet>
        <servlet-name>SpringServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    如果不使用DispatcherServlet,那么需要增加listener或filter:

    (1)如果是Servlet 2.4以上

    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>

    (2)如果是Servlet 2.4及以下

    <filter>
        <filter-name>requestContextFilter</filter-name>
        <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>requestContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    配置好了我们开始测试:

    1. request

    每个Bean的作用域为一个request请求,即每个request请求都会创建一个单独的实例。

    @Controller
    public class RequestScopeController {
    
        @GetMapping("testRequestScope")
        @ResponseBody
        public String test() {
            return this.toString();
        }
    }
    <bean id="testController" class="com.imooc.springClass3.iocOthers.RequestScopeController" scope="request"/>

    运行tomcat,访问:http://127.0.0.1:8080/testRequestScope,刷新几次,可以看到每次刷新后创建的RequestScopeController实例都是不同的地址。

    2. session

    每个Bean的作用域为一个session会话,即每个session都会创建一个单独的实例

    @Controller
    public class SessionScopeController {
    
        @GetMapping("testSessionScope")
        @ResponseBody
        public String test() {
            return this.toString();
        }
    }
    <bean id="sessionScopeController" class="com.imooc.springClass3.iocOthers.SessionScopeController" scope="session"/>

    运行tomcat,访问:http://127.0.0.1:8080/testRequestScope,刷新几次,可以看到每次刷新后创建的SessionScopeController实例都是一样的地址。但是当我们打开另外一个浏览器或重新打开当前浏览器再次访问该地址,可以看到SessionScopeController的实例的地址发生了变化

    3. application

    每个Bean的作用域为一个servletContext上下文,即每个servletContext都会创建一个单独的实例

    @Controller
    public class ApplicationScopeController {
    
        @GetMapping("testAppScope")
        @ResponseBody
        public String test() {
            return this.toString();
        }
    }
    <bean id="applicationScopeController" class="com.imooc.springClass3.iocOthers.ApplicationScopeController" scope="application"/>

    运行tomcat,访问:http://127.0.0.1:8080/testRequestScope,刷新几次,可以看到每次刷新后创建的ApplicationScopeController实例都是一样的地址。即使我们打开另外一个浏览器或重新打开当前浏览器再次访问该地址,ApplicationScopeController的实例的地址也不会发生变化。

    4. websocket

    每个Bean的作用域为一个webSocket连接,即每个webSocket连接都会创建一个新的实例。

    三、自定义scope以及SimpleThreadScope

    1. 自定义scope

    (1)定义一个Class实现org.springframework.beans.factory.config.Scope,本例中定义了一个MyScope,实现:每个Class最多可以生成两个实例。代码如下:

    public class MyScope implements org.springframework.beans.factory.config.Scope {
    
        private Map<String, Object> map = new ConcurrentHashMap<String, Object>();
    
        public Object get(String s, ObjectFactory<?> objectFactory) {
            if (map.containsKey(s + "0") && map.containsKey(s + "1")) {
                return map.get(s + new Random().nextInt(2));
            } else {
                Object object = objectFactory.getObject();
                if (!map.containsKey(s + "0")){
                    map.put(s + "0", object);
                } else if (!map.containsKey(s + "1")) {
                    map.put(s + "1", object);
                }
                return object;
            }
        }
    
        @Nullable
        public Object remove(String s) {
            Object object = null;
            if (map.containsKey(s + "0") && map.containsKey(s + "1")) {
                object =  map.get(s + new Random().nextInt(2));
            } else if (map.containsKey(s + "0")){
                object =  map.get(s + "0");
            } else if (map.containsKey(s + "1")) {
                object =  map.get(s + "1");
            }
            map.remove(s + "0");
            map.remove(s + "1");
            return object;
        }
    
        public void registerDestructionCallback(String s, Runnable runnable) {
    
        }
    
        @Nullable
        public Object resolveContextualObject(String s) {
            return null;
        }
    
        @Nullable
        public String getConversationId() {
            return null;
        }
    }

    (2)向Spring注册MyScope

    <bean id="myScope" class="com.imooc.springClass3.iocOthers.MyScope"/>
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="myScope" value-ref="myScope"/>
            </map>
        </property>
    </bean>

    (3)注册一个Bean使用MyScope作用域

    <bean id="bean1MyScope" class="com.imooc.springClass3.iocOthers.Bean1" scope="myScope"/>

    (4)测试

    public class BeanTest {
        @Test
        public void testBean() throws Exception {
            for (int i = 0; i < 10; i++) {
                Bean1 bean1MyScope = context.getBean("bean1MyScope", Bean1.class);
                System.out.println("bean1MyScope = " + bean1MyScope);
            }
    }

    (5)输出

    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@932bc4a
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@932bc4a
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@6bedbc4d
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@932bc4a
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@932bc4a
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@6bedbc4d
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@6bedbc4d
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@932bc4a
    bean1MyScope = com.imooc.springClass3.iocOthers.Bean1@6bedbc4d

    从输出结果可以看到只出现了两个不同的Bean地址,说明我们只创建了两个Bean实例。

    2. SimpleThreadScope

    每个Bean的作用域为一个线程,即每个线程都会创建一个Bean实例。

    (1)注册SimpleThreadScope

    <bean id="simpleThreadScope" class="org.springframework.context.support.SimpleThreadScope"/>
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="simpleThreadScope" value-ref="simpleThreadScope"/>
            </map>
        </property>
    </bean>

    (2)注册一个Bean使用SimpleThreadScope作用域

    <bean id="bean1SimpleThreadScope" class="com.imooc.springClass3.iocOthers.Bean1" scope="simpleThreadScope"/>

    (3)测试

    public class BeanTest {
        @Test
        public void testBean() throws Exception {
            for (int i = 0; i < 10; i++) {
                new Thread(new Runnable() {
                    public void run() {
                        for (int i1 = 0; i1 < 10; i1++) {
                            Bean1 bean1SimpleThreadScope = context.getBean("bean1SimpleThreadScope", Bean1.class);
                            System.out.println("bean1SimpleThreadScope = " + bean1SimpleThreadScope);
                        }
                    }
                }).start();
            }
            Thread.sleep(2000);
        }
    }

    (4)输出:由于多线程并发,我们没有控制线程同步,所以输出结果可能出现混乱,所以我们就不贴输出结果了。

  • 相关阅读:
    mongodb协议透传
    [转]PyInstaller2的信息文件Version的生成
    [转]使用PyInstaller2将Python脚本转化为可执行文件(中使用部分)
    Cache应用(sql依赖缓存)
    关于Cookie与Session的疑问解答
    ADO.NET Entity Framework
    WPF中的画笔功能,实现直实线、弯实线、直虚线、弯虚线
    Singleton模式之多线程
    控件回发系列一(IPostBackEventHandler)
    使用VS2010创建EntityDataModel出错
  • 原文地址:https://www.cnblogs.com/LOVE0612/p/10049563.html
Copyright © 2011-2022 走看看