08.Scope

08.Scope

  1. 五种作用域:singleton、prototype、request、session、application
  2. 五种作用域对应的销毁时机
  3. 单例Bean中注入其他作用域Bean失效的情况及解决办法

一 五种作用域及其对应的销毁时机

  1. singleton:单例,spring容器启动时创建(未设置延迟),容器关闭时销毁
  2. prototype:多例,每次使用时创建,不会自动销毁,需要手动调用 DefaultListableBeanFactory.destroyBean(bean) 销毁
  3. request:每次请求用到此 bean 时创建,请求结束时销毁
  4. session:每个会话用到此 bean 时创建,会话结束时销毁
  5. application:web 容器用到此 bean 时创建,容器停止时销毁;注意,销毁机制疑似实现有误,有可能在WebServletContext容器关闭时不生效

二 单例Bean中注入其他作用域Bean失效的情况及解决方法

当我们在一个单例的Bean中直接注入其他作用域的Bean时,会发现获取时每次都是同一个Bean;

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

如何解决?以@Lazy举例,使用 @Lazy 生成代理,代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象

一共有以下四种方式:

  1. 注入时声明为@Lazy,用到时再创建;标记为@Lazy后,实际上注入的并不是该bean,而是该bean的一个代理类,每次使用的时候创建一个全新

    @Lazy
    @Autowired
    private F1 f1;
    
  2. 使用注解创建bean时通过@Scope注解指定作用域和代理方式为ScopedProxyMode.TARGET_CLASS;与@Lazy类似,都是通过注入代理来解决

    @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
    
  3. 使用ObjectFactory<T>进行包装:

    @Autowired
    private ObjectFactory<F3> f3; // org.springframework.beans.factory
    
  4. 注入applicationContext,通过context.getBean来获取和使用

解决方法虽然不同,但理念上殊途同归: 都是推迟其它作用域的bean 的获取

演示代码文章来源地址https://uudwc.com/A/rV62

@SpringBootApplication
public class A08 {
    public static void main(String[] args) {
        SpringApplication.run(A08.class, args);
    }
}
@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;
    }
}
@Scope("application")
@Component
public class BeanForApplication {
    private static final Logger log = LoggerFactory.getLogger(BeanForApplication.class);

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

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

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

}

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

    @PreDestroy
    public void destroy() {
        log.debug("destroy");
    }
}
@ComponentScan("com.itheima.a08.sub")
public class A08_1 {

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

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

        E e = context.getBean(E.class);
        log.debug("{}", e.getF1().getClass());
        log.debug("{}", e.getF1());
        log.debug("{}", e.getF1());
        log.debug("{}", e.getF1());

        log.debug("{}", e.getF2().getClass());
        log.debug("{}", e.getF2());
        log.debug("{}", e.getF2());
        log.debug("{}", e.getF2());

        log.debug("{}", e.getF3());
        log.debug("{}", e.getF3());

        log.debug("{}", e.getF4());
        log.debug("{}", e.getF4());

        context.close();
    }
}
@Component
public class E {

    @Lazy
    @Autowired
    private F1 f1;
    @Autowired
    private F2 f2;
    @Autowired
    private ObjectFactory<F3> f3;
    @Autowired
    private ApplicationContext context;

    public F1 getF1() {
        return f1;
    }

    public F2 getF2() {
        return f2;
    }

    public F3 getF3() {
        return f3.getObject();
    }

    public F4 getF4() {
        return context.getBean(F4.class);
    }
}
@Scope("prototype")
@Component
public class F1 {
}

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

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

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

原文地址:https://blog.csdn.net/m0_46836425/article/details/131197844

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年06月17日 14:07
港科夜闻|香港科大工学院陈浩教授获选2023年亚洲青年科学家
下一篇 2023年06月17日 14:07