Scope

笔记参考B站黑马程序员视频:spring原理

1.Scope类型

Singleton Scope

定义:在整个应用程序中,只有一个实例存在。
Spring Framework 中的使用:默认的 bean Scope,Spring 容器中只会创建一个实例,并在需要时共享给所有请求。

 

Prototype Scope

定义:每次请求时都会创建一个新的实例。
Spring Framework 中的使用:每次通过 Spring 容器获取 bean 时,都会返回一个新的实例。

 

Request Scope

定义:在每个 HTTP 请求中创建一个新的实例,适用于 web 应用。
Spring Framework 中的使用:仅在 web 应用中有意义,确保每个 HTTP 请求处理过程中,使用的 bean 都是独立的。
优点:避免多个请求之间状态混乱,保证请求级别的数据安全性。

 

Session Scope

定义:在每个用户会话(session)中创建一个实例,适用于需要跟踪用户状态的 web 应用。
Spring Framework 中的使用:确保每个用户在其会话期间使用的 bean 是唯一的。
优点:适合需要持久性用户数据的情况,如用户登录信息、购物车等。

 

application Scope

应用程序作用域(application scope)用于在整个应用程序生命周期内共享数据。具体来说,application Scope 是指将数据存储在 ServletContext 中,在应用程序启动时加载,并在整个应用程序运行期间可供所有用户和所有会话访问的作用域。

 

演示:

application Scope

package com.dreams.demo08;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Scope("application")
@Component
public class BeanForApplication {
    private static final Logger log = LoggerFactory.getLogger(BeanForApplication.class);

    @PreDestroy
    public void destroy() {
        log.debug("destroy");
    }
}

 

Session Scope

package com.dreams.demo08;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Scope("session")
@Component
public class BeanForSession {
    private static final Logger log = LoggerFactory.getLogger(BeanForSession.class);

    @PreDestroy
    public void destroy() {
        log.debug("destroy");
    }
}

 

request scope

package com.dreams.demo08;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Scope("request")
@Component
public class BeanForRequest {
    private static final Logger log = LoggerFactory.getLogger(BeanForRequest.class);

    @PreDestroy
    public void destroy() {
        log.debug("destroy");
    }

}

 

再来个启动类

package com.dreams.demo08;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

控制层方法

package com.dreams.demo08;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@RestController
public class MyController {

    @Lazy
    @Autowired
    private BeanForRequest beanForRequest;

    @Lazy
    @Autowired
    private BeanForSession beanForSession;

    @Lazy
    @Autowired
    private BeanForApplication beanForApplication;

    @GetMapping(value = "/test", produces = "text/html")
    public String test(HttpServletRequest request, HttpSession session) {
        ServletContext sc = request.getServletContext();
        String sb = "<ul>" +
                    "<li>" + "request scope:" + beanForRequest + "</li>" +
                    "<li>" + "session scope:" + beanForSession + "</li>" +
                    "<li>" + "application scope:" + beanForApplication + "</li>" +
                    "</ul>";
        return sb;
    }

}

 

jdk >= 9 如果反射调用 jdk 中方法,jdk <= 8 不会有问题,如果 jdk > 8, 运行时需要添加VM参数

--add-opens java.base/java.lang=ALL-UNNAMED

否则会出现以下报错 

运行效果如下:

清下缓存

 

 

2.scope失效

演示

如果上面的控制层在不加 @Lazy注入时,scope是失效的

package com.dreams.demo08.demo;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Scope("prototype")
@Component
public class F1 {
}

 

然后在单例(默认)中注入上面的多例

package com.dreams.demo08.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class One {

    @Autowired
    private F1 f1;

    public F1 getF1() {
        return f1;
    }

}

 

启动类调用

package com.dreams.demo08;

import com.dreams.demo08.demo.One;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;


@ComponentScan("com.dreams.demo08.demo")
public class ScopeApplication {

    private static final Logger log = LoggerFactory.getLogger(ScopeApplication.class);

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ScopeApplication.class);

        One bean = context.getBean(One.class);
        log.debug("{}",bean.getF1());
        log.debug("{}",bean.getF1());
        log.debug("{}",bean.getF1());
        context.close();
    }
}

可以看到scope没有生效,还是单例

 

原理就是:

对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的 One,因此 One 用的始终是第一次依赖注入的 F1

 

方法1-@Lazy解决

解决方法就是:

  • 使用 @Lazy 生成代理

  • 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象

  • 每次调用bean.getF1()时,这个代理对象都会创建新的 f 对象
package com.dreams.demo08.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class One {

    @Lazy
    @Autowired
    private F1 f1;

    public F1 getF1() {
        return f1;
    }

}

启动类

log.debug("{}",bean.getF1().getClass());

可以看到是代理对象

 

 

方法2-proxyMode配置解决

将@Lazy注释掉,在要注入的多例类加上proxyMode配置

package com.dreams.demo08.demo;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F1 {
}

可以看到成功了,当然底层也是代理对象

 

方法3-对象工厂解决

package com.dreams.demo08.demo;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class One {
    @Autowired
    private ObjectFactory<F1> f1;

    public F1 getF1() {
        return f1.getObject();
    }

}

可以看到这里就不是使用代理了

 

 

方法4-注入容器

package com.dreams.demo08.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class One {
    @Autowired
    private ApplicationContext context;

    public F1 getF1() {
        return context.getBean(F1.class);
    }

}

同样没有用代理

 

 

3.参考

黑马程序员:spring

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇