Spring底层原理学习笔记--第八讲--(Scope及Scope失效解决)

Scope

  • 1.Scope类型有哪些
  • 2.在singleton中使用其它几种scope的注意事项
  • 3.scope的销毁
  • 4.实战:scope失效分析

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

Scope

A08Application.java

java 复制代码
package com.lucifer.itheima.a08;

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

/*
    singleton(获取bean的时候,每次从容器返回的都是同一个对象),prototype(每次到容器中获取bean的时候都会产生一个新的对象),request
    (bean存在于request域中,每次请求来了,会把这个bean放在request域中,请求结束bean的生命周期也随之结束),
    session(会话域,同一个会话内,会话开始bean被创建,会话结束bean被销毁),
    application(应用程序域,应用程序启动时,这个域被创建,应用程序销毁时,被销毁,这里的应用程序指的是web中的servletContext)
    演示 request,session,application作用域
    打开不同的浏览器,刷新http://localhost:8080/test即可查看效果
    如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED
 */
@SpringBootApplication
public class A08Application {
    public static void main(String[] args) {
        SpringApplication.run(A08Application.class,args);
    }

    //请求访问http://localhost:4580/lucifer98/test的结果是
//    request scope:com.lucifer.itheima.a08.BeanForRequest@51d9e461
//    session scope:com.lucifer.itheima.a08.BeanForSession@65784f1f
//    application scope:com.lucifer.itheima.a08.BeanForApplication@30d82692
}

MyController.java

java 复制代码
package com.lucifer.itheima.a08;

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;
    }
}

BeanForApplication.java

java 复制代码
package com.lucifer.itheima.a08;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Slf4j
@Scope("application")
@Component
public class BeanForApplication {

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

}

BeanForRequest.java

java 复制代码
package com.lucifer.itheima.a08;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Scope("request")
@Component
@Slf4j
public class BeanForRequest {

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

}

BeanForSession.java

java 复制代码
package com.lucifer.itheima.a08;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Slf4j
@Scope("session")
@Component
public class BeanForSession {

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

Scope失效解决--@Lazy、@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)、ObjectFactory、ApplicationContext

A09Application.java

java 复制代码
package com.lucifer.itheima.a09;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/*
    如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED

 */
@ComponentScan("com.lucifer.itheima.a09")
@Slf4j
public class A09Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class);

        // 输出结果为
//        11:58:35.868 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@1f1c7bf6
//        11:58:35.870 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@1f1c7bf6
//        11:58:35.870 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@1f1c7bf6
       // F1配置的是多例(@Scope("prototype")),没用一次希望是不同对象,但是F1此时打印出来的是同一个。所以多例配置失效了  即发现他们是同一个对象,而不是期望的多例对象
        // 对于单例对象来讲,依赖注入仅发生了一次,后续再没用到多例的F,因此E用的始终是第一次依赖注入的F

        //解决
        //使用@Lazy生成代理
        //代理对象虽然还是同一个,但是每次使用代理对象的任意方法时,由代理创建新的f对象
        E e = context.getBean(E.class);
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());

        context.close();
    }

}

E.java

java 复制代码
package com.lucifer.itheima.a09;

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

@Component
public class E {

    @Autowired
    private F1 f1;

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

F1.java

java 复制代码
package com.lucifer.itheima.a09;

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

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

}

解决1

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

E.java

java 复制代码
package com.lucifer.itheima.a09;

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

@Component
public class E {

    @Lazy
    @Autowired
    private F1 f1;

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

解决2

  • 使用@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)生成代理

A09Application.java

java 复制代码
package com.lucifer.itheima.a09;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/*
    如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED

 */
@ComponentScan("com.lucifer.itheima.a09")
@Slf4j
public class A09Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class);

        // 输出结果为
//        14:29:03.623 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
        //        .F1$$EnhancerBySpringCGLIB$$d0e56e2e         //代理对象
//        14:29:03.624 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@16ec5519
        // 不同的对象
//        14:29:03.631 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@188715b5
//        14:29:03.632 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@6a192cfe
        E e = context.getBean(E.class);
        //这个是个代理对象
        log.info("{}",e.getF1().getClass());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());


        //F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之前
        // 输出结果为
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09.F2
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
        // 相同的对象
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec

        //F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之后
        //输出结果为
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
        //        .F2$$EnhancerBySpringCGLIB$$5eea9055   //代理对象
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@5c33f1a9
        // 不同的对象
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@1623b78d
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@c8c12ac
        log.info("{}",e.getF2().getClass());
        log.info("{}",e.getF2());
        log.info("{}",e.getF2());
        log.info("{}",e.getF2());

        context.close();
    }
}

E.java

java 复制代码
package com.lucifer.itheima.a09;

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

@Component
public class E {

    @Lazy
    @Autowired
    private F1 f1;

    @Autowired
    private F2 f2;

    public F1 getF1(){
        return f1;
    }

    public F2 getF2(){
        return f2;
    }
}

F1.java

java 复制代码
package com.lucifer.itheima.a09;

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

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

}

F2.java

java 复制代码
package com.lucifer.itheima.a09;

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 F2 {
}

解决3,4

  • 使用ObjectFactory、ApplicationContext间接获取多例

A09Application.java

java 复制代码
package com.lucifer.itheima.a09;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/*
    如果jdk>8,运行时请添加 --add-opens java.base/java.long=ALL-UNNAMED

 */
@ComponentScan("com.lucifer.itheima.a09")
@Slf4j
public class A09Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A09Application.class);

        // 输出结果为
//        14:29:03.623 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
        //        .F1$$EnhancerBySpringCGLIB$$d0e56e2e         //代理对象
//        14:29:03.624 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@16ec5519
        // 不同的对象
//        14:29:03.631 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@188715b5
//        14:29:03.632 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F1@6a192cfe
        E e = context.getBean(E.class);
        //这个是个代理对象
        log.info("{}",e.getF1().getClass());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());
        log.info("{}",e.getF1());


        //F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之前
        // 输出结果为
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09.F2
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
        // 相同的对象
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec
//        15:49:35.069 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@20ce78ec

        //F2加上@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)之后
        //输出结果为
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - class com.lucifer.itheima.a09
        //        .F2$$EnhancerBySpringCGLIB$$5eea9055   //代理对象
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@5c33f1a9
        // 不同的对象
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@1623b78d
//        15:51:26.646 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F2@c8c12ac
        log.info("{}",e.getF2().getClass());
        log.info("{}",e.getF2());
        log.info("{}",e.getF2());
        log.info("{}",e.getF2());


        //输出结果为
//        16:42:03.962 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F3@72967906
        // 是不同的f3
//        16:42:03.963 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F3@2f9f7dcf
        log.info("{}",e.getF3());
        log.info("{}",e.getF3());

        // 输出结果为
//        16:50:29.108 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F4@42a48628  //
        //        不同的对象
//        16:50:29.108 [main] INFO com.lucifer.itheima.a09.A09Application - com.lucifer.itheima.a09.F4@293a5bf6
        log.info("{}",e.getF4());
        log.info("{}",e.getF4());
        context.close();
    }

}

E.java

java 复制代码
package com.lucifer.itheima.a09;

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

@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);
    }
}

F1.java

java 复制代码
package com.lucifer.itheima.a09;

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

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

}

F2.java

java 复制代码
package com.lucifer.itheima.a09;

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 F2 {
}

F3.java

java 复制代码
package com.lucifer.itheima.a09;

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

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

F4.java

java 复制代码
package com.lucifer.itheima.a09;

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

@Scope("prototype")
@Component
public class F4 {
}
相关推荐
代码敲不对.2 小时前
江科大笔记—软件安装
笔记·stm32·单片机·嵌入式硬件
尘浮生2 小时前
Java项目实战II基于Java+Spring Boot+MySQL的大型商场应急预案管理系统(源码+数据库+文档)
java·开发语言·数据库·spring boot·spring·maven·intellij-idea
问道飞鱼3 小时前
每日学习一个数据结构-B+树
数据结构·b树·学习
尘浮生3 小时前
Java项目实战II基于Java+Spring Boot+MySQL的校园社团信息管理系统(源码+数据库+文档)
java·开发语言·数据库·spring boot·mysql·spring·maven
不染_是非3 小时前
Django学习实战篇六(适合略有基础的新手小白学习)(从0开发项目)
后端·python·学习·django
z2014z3 小时前
系统架构设计师教程 第5章 5.4 软件测试 笔记
笔记·系统架构
Midsummer啦啦啦3 小时前
NumPy库学习之argmax函数
学习·numpy
Mero技术博客3 小时前
第二十节:学习Redis缓存数据库实现增删改查(自学Spring boot 3.x的第五天)
数据库·学习·缓存
&AtTiTuDe;4 小时前
如何使用IIC外设(硬件IIC)
经验分享·笔记·stm32·单片机·嵌入式硬件·硬件工程
QuantumYou4 小时前
【对比学习串烧】 SWav和 BYOL
学习·机器学习