• Bean作用域和生命周期-------JavaEE(Spring)


    1.之前学过的变量的作用域:是指变量在方法中或者作用域中的某种行为,现在我们来进行了解一下Bean的作用域

    1)@Autowired实现根据name再根据类型,@Resource则相反,先根据类型,再根据name

    2)Bean的作用域在Spring容器里面默认是单例模式

    1)我们先写一段代码:

    package APP.Service;
    
    import APP.BeanMethod.User;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService {
        public void start(String name) {
            System.out.println("我是Service" + name);
        }
      @Bean(name="u1")
        public User run(Integer id) {//前端传过来的参数可能是空,根据用户ID查询数据库;
            if (id == 1) {
                User user = new User();
                user.setId(id);
                user.setName("周韵杠");
                return user;
            }else{
                User user=new User();
                user.setName("胡子");
                user.setId(id);
                return user;
            }
        }
    }
    

    2)我们再写一个类用于获取id为1的user对象

    @Controller
    public class UserController {
        @Resource(name="u1")
        private User user;
        public User GetUser()
        {   User user1=user;//创建一个新的引用
            user.setName("曹操");
            return user;
        }
    }
    

    3)我们再写一个类在用来获取id为1的user对象

    @Controller
    public class JavaController {
        @Autowired
        private User u1;
        public  User GetUser()
        {
            User user=u1;
            return user;
        }
    }
    

    4)main方法的函数

    ApplicationContext context=new ClassPathXmlApplicationContext("web.xml");
    UserController userController=context.getBean("userController",UserController.class);
    JavaController javaController=context.getBean("javaController",JavaController.class);
    User user1=userController.GetUser();
    User user2=javaController.GetUser();
    System.out.println(user1);
    System.out.println(user2);
    此时打印出的结果是:

    User{id=1, name='曹操'}
    User{id=1, name='曹操'}

    但是我们发现,user2不是应该打印周韵杠吗? 

    什么是作用域:限定程序中变量的可用范围就叫做作用域,或者在源代码中定义变量的某个区域就叫做作用域,有几种类型;

    但是Bean的作用域是指Bean在整个Spring框架容器里面的某种行为模式,是Bean的类型有哪些 ,比如说singLeton单例作用域,就表示Bean在整个Spring框架里面只有一份,他是全局共享的,那么当其他人修改了这个值之后,那么另一个人读到的就是被修改的值

    Spring容器在进行初始化一个Bean的实例的时候,同时会指定该实例的作用域,Spring有六种作用域,最后四种是针对SpringMVC生效的

    因为单例模式只被初始化一次,初始化一次之后我们可以反复的进行使用,所以使用的性能比较高,所有人都是用的一个对象;

    1.Bean的6种作用域:注意后四种是SpringMVC里面的值,是基于SpringMvc来进行生效的,但是普通的Spring项目(非web项目)只有前两种;也就说明Bean在Spring里面一共有六种类型;

    web项目:通过浏览器或者postman的方式来进行访问一个地址的方式来进行发送Http请求,与咱们的在idea中的Spring代码进行交互,是具有上面的5种值;

    1.singleton:单例模式

    描述:该作用域下的Bean在IOC容器中只存在一个实例:

    当我们进行获取Bean(即通过applicationContext.getBean等方法获取以及装配Bean(即通过Autowired注入)这都是一个对象;

    场景:通常无状态的Bean的使用该作用域,无状态表示Bean对象的属性状态不需要进行更新,不会修改Bean,通常我们的Spring默认选择该作用域;

    缺点:一个改变了,其他的就都改变了;

    2.prototype:原型模式

    描述:每次对于该作用域下面的Bean的请求都会创建新的实例:当我们进行获取Bean的时候(即通过applicationContext.getBean()方法来进行获取)或者装配Bean(即通过Autowired来进行注入),这几种方法获取的都是新的对象实例,每一个类中引入的对象都是自己的;

    场景:通常有状态的Bean使用该作用域

    3.Request

    描述:每一次HTTP请求都会创建新的Bean实例,就类似于prototype

    场景:一次http请求和响应的共享Bean

    备注:只限于SpringMVC中使用,在咱们的普通项目是不能进行使用的

    4.session

    描述:在一个HttpSession中,定义一个Bean实例

    场景:用户会话的共享Bean,比如说记录一个用户的登录信息,是针对一个人来进行操作的,只要是这个人操作的,就会对应到这个实例;

    备注:只是限于SpringMVC中进行使用

    5.application

    描述:在一个http servlet context中对应一个Bean实例

    场景:Web应用的上下文信息,比如说记录一个应用的共享信息

    备注:只限于SpringMVC进行使用

    singletion是作用于整个Spring(IOC容器)容器当中,application是在一个Servlet容器当中(处理WEB请求)

    6.WebSocket

    描述:在一个Http WebSocket的生命周期中,定义一个Bean实例

    场景:WebSocket的每一次对话当中,保存了一个Map结构的头信息,将来用于包裹客户端消息头,第一次初始化之后,直到WebSocket结束都是同一个Bean

    备注:限定在Spring WebSocket中使用

    单例作用域和全局作用域

    singletion是Spring Core的作用域,application是Spring Web的作用域(只有在Servlet里面,在SpringMVC里面才有效果的)

    singletion是作用域IOC的容器,而application是作用于Servlet的容器

    我们如何进行设置Bean的作用域呢?保证多例的作用域

    1)直接使用@Scope他是可以即应用于类注解上面,又能应用于方法注解上面

    @Scope("prototype")直接去设置相应的值

    2)直接使用枚举进行设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

    3)Scope翻译成中文是作用域的意思,虽然说@Scope是可以进行应用到类注解和方法注解,但是如果应用到类注解,就说明进行设置当前这个类所生效;

    4)我们一定要注意,我们如果想要方法的返回值是单例的或者是多例的,我们就可以经这个注解修饰方法,如果我们要使用的是@Bean注解·+@Scope,@Scope一定要放在方法上进行注解,不能放在类上;

    1. @Component
    2. public class GetBean {
    3. @Bean(name ="u1")//将当前User对象存储到Spring里面
    4. @Scope("prototype")
    5. public User GetUser1(){
    6. User user=new User();
    7. user.setId(1);
    8. user.setName("李佳伟");
    9. return user;
    10. }

    2.Bean的大的执行流程-----重要

    1)启动Spring容器-----执行main方法(执行带有ApplicationContext的main方法)

    2)加载Spring配置文件(配置一个组件的扫描路径,通常在resource里面或者是使用标签)

    3)加载配置文件中的bean或者根据配置文件中的bean组件的根扫描路径,进行对Bean对象的扫描(会进行扫描五大类注解,如果有,直接进行加载)(如果说我们在A类里面注入了B类,那么先会把B类给注入到Spring容器里面,在进行注入A类)

    4)将加载的对象存入到Spring容器里面,进行加载

    5)其他需要使用Bean对象的地方就可以直接进行获取并使用了

    6)执行完之后,执行销毁操作

    Bean的执行流程(Spring的执行流程)-----启动Spring容器-----实例化Bean(分配内存空间,从无到有)-----将Bean进行注册到Spring里面(存储操作)-----我们最后再将Bean装配到需要的类中,取操作;

    Bean的生命周期-----重要

    所谓的生命周期就是指一个对象从创建到销毁的整个过程

    1)实例化Bean,为Bean对象分配内存空间

    2)进行设置它的属性(Bean的注入和装配)

    我们一定是要先进行加载属性的,如果先进行初始化方法,很有可能就会在方法里面用到这个类属性(如果这个属性被@Resource或者Autowired所修饰,那么我们就需要对使用的Bean进行初始化注入)

    一个类是有属性和方法的

    3)(Bean初始化---一系列准备工作的统称),执行各种通知方法,比如说在飞机上进行检查工作,检查按钮;

    3.1实现了各种Aware通知的方法,比如说BeanNameAware,BeanFactory,ApplicationContextAware的接口方法

    3.2执行BeanPostProcessor初始化前置方法,如果有的话,就执行,前两种是系统级别的

    3.3执行带注解的@PostConstruct初始化方法,依赖注入操作之后进行执行

    是否为InitializingBean调用afterPropertiesSet方法

    3.4执行自己所指定的init-method方法,如果有指定的话(最早使用XML的方式,在没有注解之前)

    3.5执行BeanPostProcess初始化后置方法

    4)使用Bean

    5)进行销毁Bean

    5.1首先会执行@PreDestory这是销毁前方法,比如说像记录一下时间,日志

    5.2如果说实现了DisposableBean接口方法

    5.3destory-method:销毁前的执行方法,在XML里面进行设置

    下面我们写了一些代码来进行演示:

    @Controller
    public class UserController implements BeanNameAware {
        @Resource
        private UserService userService;
    
        public UserController(UserService userService) {
            this.userService = userService;
        }
    
        @Override
        public void setBeanName(String s) {
            System.out.println("执行通知方法"+s);
        }
        @PostConstruct//出生于注解时代
        public void start()
        {
            System.out.println("执行被注解@PostConstruct修饰的方法");
        }
        public void init()//直接这么写,是无法进行执行的,我们必须要在XML里面进行相应的配置,这里面的方法名字是可以随便取的,只要和XML里面的名字相匹配就可以了
        {
            System.out.println("执行init方法");
        }
        public void destory()
        {
            System.out.println("执行destory方法");
        }
        @PreDestroy
        public void predestory()
        {
            System.out.println("执行被注解修饰的");
        }
    }
    class HelloServlet{
        public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("web.xml");
        UserController userController=context.getBean("userController",UserController.class);
        userController.destory();
        }
    }

    web.xml配置文件:

    
        
    

    打印结果:执行通知方法userController
    执行被注解@PostConstruct修饰的方法
    执行通知方法userinit
    执行被注解@PostConstruct修饰的方法
    执行init方法
    执行destory方法

  • 相关阅读:
    Spring Cloud Alibaba【转账功能实现上、转账功能实现下、没有引入分布式事物问题演示、项目引入Seata 】(十一)
    do while循环、嵌套循环、数组简介
    企业微信hook接口协议,ipad协议http,设置消息回调地址
    ISP住宅网络的特点是什么
    SAP-MM-委外订单合并有什么不同?
    【服务器数据恢复】RAID5多块硬盘先后离线的数据恢复案例
    2024 年排名前 5 名的 Mac 数据恢复软件分享
    【回归预测-lssvm】基于粒子群算法优化最小二乘支持向量机lssvm实现数据回归预测附matlab代码
    成为一个优秀的测试工程师需要具备哪些知识和经验?
    Qt编写4K/8K大分辨率播放器(8K占用1%CPU)
  • 原文地址:https://blog.csdn.net/weixin_61518137/article/details/125755759