Spring原理分析-Scope

2022-04-14  本文已影响0人  石头耳东

零、本文纲要

一、Scope
1、Scope类型
2、基础准备与演示
二、Scope失效
1、基础准备与演示
2、失效原因及处理
3、总结

一、Scope

1、Scope类型

singleton, prototype, request, session, application

2、基础准备与演示

request类型,如下:

@Scope("request")
@Component
public class BeanForRequest {
    private static final Logger log = LoggerFactory.getLogger(BeanForRequest.class);
    @PreDestroy
    public void destroy(){
        log.debug("BeanForRequest DESTROY");
    }
}

session类型,如下:

@Scope("session")
@Component
public class BeanForSession {
    private static final Logger log = LoggerFactory.getLogger(BeanForSession.class);
    @PreDestroy
    public void destroy(){
        log.debug("BeanForSession DESTROY");
    }
}

application类型,如下:

@Scope("application")
@Component
public class BeanForApplication {
    private static final Logger log = LoggerFactory.getLogger(BeanForApplication.class);
    @PreDestroy
    public void destroy(){
        log.debug("BeanForApplication DESTROY");
    }
}
@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 context = request.getServletContext();
        String resp = "<ul>" +
                "<li>" + "REQUEST SCOPE:" + beanForRequest + "</li>" +
                "<li>" + "SESSION SCOPE:" + beanForSession + "</li>" +
                "<li>" + "APPLICATION SCOPE:" + beanForApplication + "</li>" +
                "</ul>";
        return resp;
    }
}
@SpringBootApplication
public class Demo08 {
    public static void main(String[] args) {
        SpringApplication.run(Demo08.class, args);
    }
}
Scope.png

二、Scope失效

1、基础准备与演示

编写F1,其Scope为prototype多例,如下:

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

编写E,其内部注入F1,如下:

@Component
public class E {

//    @Lazy
    @Autowired
    private F1 f1;

    public F1 getF1(){return f1;}
}
@ComponentScan("com.stone.demo08.entity")
public class ApplicationDemo {
    private static final Logger log = LoggerFactory.getLogger(ApplicationDemo.class);

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext(ApplicationDemo.class);
        E e = context.getBean(E.class);
        log.debug("{}", e.getF1());
        log.debug("{}", e.getF1());
        log.debug("{}", e.getF1());
        context.close();
    }
}
多例失效情形.png

2、失效原因及处理

单例E被创建时,完成了F属性的注入。此后调用get方法,得到的始终是只创建一次时注入的F对象。

Ⅰ 添加@Lazy注解

添加@Lazy注解.png

@Lazy注解会生成目标对象的代理对象,代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象。

使用代理对象.png

Ⅱ 添加proxyMode = ScopedProxyMode.TARGET_CLASS属性

@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}
TARGET_CLASS属性.png

Ⅲ 使用ObjectFactory工厂

@Autowired
private ObjectFactory<F3> f3;

public F3 getF3() {
    return f3.getObject();
}
使用ObjectFactory工厂.png

Ⅳ 使用ApplicationContext

@Autowired
private ApplicationContext context;

public F4 getF4(){return context.getBean(F4.class);}
使用ApplicationContext.png

3、总结

Ⅰ @Lazy注解;
Ⅱ @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS);
Ⅲ ObjectFactory工厂;
Ⅳ ApplicationContext。

四种方法的共同特点都是在运行时再去获取多例对象,推迟了其他Scope Bean的获取。

推荐使用ObjectFactory工厂、ApplicationContext这两种方法,性能更优。

三、结尾

以上即为Spring原理分析-Scope的全部内容,感谢阅读。

上一篇 下一篇

猜你喜欢

热点阅读