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 {
}
相关推荐
Hical_W10 小时前
深入学习CPP17_PMR
c++·学习
xuanwenchao10 小时前
ROS2学习笔记 - 1、编写运行第一个程序
笔记·学习
独小乐10 小时前
018.使用I2C总线EEPROM|千篇笔记实现嵌入式全栈/裸机篇
linux·笔记·单片机·嵌入式硬件·arm·信息与通信
惠惠软件10 小时前
豆包 AI 学习投喂与排名优化指南
人工智能·学习·语音识别
V搜xhliang024610 小时前
OpenClaw、AI大模型赋能数据分析与学术科研 学习
人工智能·深度学习·学习·机器学习·数据挖掘·数据分析
云烟成雨TD11 小时前
Spring AI Alibaba 1.x 系列【18】Hook 接口和四大抽象类
java·人工智能·spring
YuanDaima204811 小时前
二分查找基础原理与题目说明
开发语言·数据结构·人工智能·笔记·python·算法
里昆11 小时前
【电力电子】某模拟量采集器的上位机设置和遇到的问题解决
学习
卖报的大地主11 小时前
TPAMI 2026 | 判别和扩散生成学习融合的礼物:边界细化遥感语义分割
人工智能·笔记·学习
Yeh20205811 小时前
Http笔记
笔记