Spring原理

这次我们来研究Bean的相关知识和spring boot自动配置的相关流程

        1.Bean的作用域

              1概念

                在SpringIoC&DI阶段,我们学习了Spring是如何帮助我们管理对象的.

                1. 通过 @Controller ,@Service , @Repository , @Component , @Configuration                              , @Bean 来声明Bean对象.

                2. 通过ApplicationContext 或者BeanFactory 来获取对象

                3. 通过 @Autowired , Setter ⽅法或者构造⽅法等来为应⽤程序注⼊所依赖的Bean对象

                我们编写代码,从spring容器中获取bean

                        

package com.example.springconfig;

import com.example.springconfig.demos.model.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringConfigApplication {

    public static void main(String[] args) {

         ApplicationContext context=SpringApplication.run(SpringConfigApplication.class, args);
        User user1 = context.getBean(User.class);
        user1.setName("lisi");
        System.out.println( "当前对象地址:"+System.identityHashCode(user1));


        User user2 = context.getBean(User.class);
        System.out.println( "当前对象地址:"+System.identityHashCode(user2));
    }

}







package com.example.springconfig.demos.config;

import com.example.springconfig.demos.model.User;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
    @Bean
    public User user1(){
        return  new User(1,"zhangsan");
    }
}




package com.example.springconfig.demos.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    private Integer id;
    private  String name;

}

   

运行出结果 

发现输出对象地址的值是一样的,说明从spring容器中取出的对象都是同一个

这也是"单例模式"    单例模式:确保⼀个类只有⼀个实例,多次创建也不会创建出多个实例

默认情况下,Spring容器中的bean都是单例的,这种⾏为模式,我们就称之为Bean的作⽤域.

      Bean的作⽤域是指Bean在Spring框架中的某种⾏为模式.

⽐如单例作⽤域:表⽰Bean在整个Spring中只有⼀份,它是全局共享的.那么当其他⼈修改了这个值之后,那么另⼀个⼈读取到的就是被修改的值、

   2.Bean的作用域

在Spring中⽀持6种作⽤域,后4种在SpringMVC环境才⽣效

1. singleton:单例作⽤域

2. prototype:原型作⽤域(多例作⽤域)

3. request:请求作⽤域

4. session:会话作⽤域

5. Application:全局作⽤域

6. websocket:HTTPWebSocket作⽤域

接下来 我们来看看这几个bean的作用域

在这之前我们先来看一下一些注解的详细

堆和栈之间的关系

各个bean作用域中的代码

package com.example.springconfig.demos.controller;

import com.example.springconfig.demos.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.jws.soap.SOAPBinding;

@RequestMapping("/scope")
@RestController
public class BeanScopeController {

    @Autowired
      private ApplicationContext context;
    @Resource(name = "singletonUser")
    private  User singletonUser;

    @Resource(name = "prototypeUser")
    private  User prototypeUser;
    @Resource(name = "requestUser")
    private  User requestUser;
    @Resource(name = "sessionUser")
    private  User sessionUser;
    @Resource(name = "applicationUser")
    private  User applicationUser;
    @RequestMapping("/single")
    public  String  single() {
        /**
         *1.从context中获取对象
         * 2.属性注入获取对象
         */
        User user = (User) context.getBean("singletonUser");
        return "context中获取的对象是:" + user + ",属性注入获取的对象:" + System.identityHashCode(singletonUser);
    }
    @RequestMapping("/prototype")
    public  String  prototype(){
        /**
         *1.从context中获取对象
         * 2.属性注入获取对象
         */
        User user= (User) context.getBean("prototypeUser");
        return "context中获取的对象是:"+user+",属性注入获取的对象:"+System.identityHashCode(prototypeUser);
    }
    @RequestMapping("/request")
    public  String  request(){
        /**
         *1.从context中获取对象
         * 2.属性注入获取对象
         */
        User user= (User) context.getBean("requestUser");
        return "context中获取的对象是:"+user+",属性注入获取的对象:"+System.identityHashCode(requestUser);
    }

    @RequestMapping("/session")
    public  String  session(){
        /**
         *1.从context中获取对象
         * 2.属性注入获取对象
         */
        User user= (User) context.getBean("sessionUser");
        return "context中获取的对象是:"+user+",属性注入获取的对象:"+System.identityHashCode(sessionUser);
    }
    @RequestMapping("/application")
    public  String  application(){
        /**
         *1.从context中获取对象
         * 2.属性注入获取对象
         */
        User user= (User) context.getBean("applicationUser");
        return "context中获取的对象是:"+user+",属性注入获取的对象:"+System.identityHashCode(applicationUser);
    }





}




package com.example.springconfig.demos.config;

import com.example.springconfig.demos.model.User;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.annotation.ApplicationScope;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.annotation.SessionScope;
import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor;

@Configuration
public class BeanConfig {
    @Bean
    public User user1(){
        return  new User(1,"zhangsan");
    }
    @Bean
  @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
//    @Scope("singleton")
    public  User singletonUser(){
        return  new User();
    }
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public  User prototypeUser(){
        return new User();
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_REQUEST,proxyMode = ScopedProxyMode.TARGET_CLASS)
    public  User requestUser(){
        return  new User();
    }
    @Bean
    @SessionScope
    public User sessionUser(){
    return  new User();
    }

    @Bean
    @ApplicationScope
    public  User applicationUser(){
        return  new User();
    }

}

  1.singleton

 每次获取的都是同一个对象

   2.prototype

     每次获取的对象是不同的

3.request

请求每次获取的对象都不一样

4.session

在⼀个session中,多次请求,获取到的对象都是同⼀个.

 5.application

在⼀个应⽤中,多次访问都是同⼀个对象
Applicationscope就是对于整个web容器来说,bean的作⽤域是ServletContext级别的.这个和singleton有点类似区别在于:Applicationscope是ServletContext的单例,singleton是⼀个ApplicationContext的单例.在⼀个web容器中ApplicationContext可以有多个.(了解即可)

3.Bean的生命周期        

             ⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程,我们把这个过程就叫做⼀个对象的⽣命周期.Bean的⽣命周期分为以下5个部分:

 1. 实例化(为Bean分配内存空间)

2. 属性赋值(Bean注⼊和装配,⽐如 @AutoWired )

3. 初始化

                a. 执⾏各种通知,如 BeanNameAware ,BeanFactoryAware ,ApplicationContextAware                      的接⼝⽅法.

                b. 执⾏初始化⽅法

                  ▪ xml定义 init-method

                  ▪ 使⽤注解的⽅式 @PostConstruct

                ▪ 执⾏初始化后置⽅法( BeanPostProcessor )

   4. 使⽤Bean

  5. 销毁Bean

a. 销毁容器的各种⽅法,如 @PreDestroy ,DisposableBean 接⼝⽅法, destroymethod.

演示代码代码如下

package com.example.springconfig.demos.component;

import com.example.springconfig.demos.model.User;
import org.apache.ibatis.annotations.Update;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class BeanLifeComponent {
    private User user;

    public BeanLifeComponent() {
        System.out.println("执行构造方法");
    }


    @Autowired
    @Qualifier("user1")
    public void setUser1(User user1) {
        this.user = user;
        System.out.println("属性注入");
    }
    @PostConstruct
    public  void  init(){
        System.out.println("执行初始化");
    }
    public  void use(){
        System.out.println("执行use");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行destroy方法");
    }
}

4.关于Bean相关的源码

        我们举个例子来说一下,我们获取bean对象,并通过不同的方式拿取相关的值,

我们通过结果看到,源码里有类似代理类和目标类的东西,我们通过toString方法拿到的其实是spring代理的时候进行了重写,重写的逻辑是执行目标toString

代理类包含目标类 

返回的user其实就是代理类 我们在执行程序的时候,代理类没有发生变化,目标类在发生变化

        

                1.AbstractAutowireCapableBeanFactory

        我们翻看AbstractAutowireCapableBeanFactory这个源码,在里面看到了

里面有实例化bean的源码

我们根据bean的周期来看

接下来就看属性注入

在属性注入里面有bean的初始化initializeBean 里面有bean初识化的各种代码

我们可以看到spring的源码是非常复杂的,我们现在也只是浅浅读了一下

5.spring自动配置

                SpringBoot的⾃动配置就是当Spring容器启动后,⼀些配置类,bean对象等就⾃动存                    ⼊到了IoC容器中,不需要我们⼿动去声明,从⽽简化了开发,省去了繁琐的配置操                     作.

             SpringBoot⾃动配置,就是指SpringBoot是如何将依赖jar包中的配置类以及Bean加载到SpringIoC容器中的

            我们学习主要分以下两个⽅⾯:

           1. Spring是如何把对象加载到SpringIoC容器中的

           2. SpringBoot是如何实现的

  我们先看看@SpringBootApplication这个注解 点进去

2.@SpringBootConfiguration

                

 

3.@EnableAutoConfiguration

这里面的注解是实现自动配置的核心 

我们再点击进入import中的AutoConfigurationImportSelector.class

这里面的这个方法是主要的方法,我们在点进getAutoConfigurationEntry 

标注的这一行是拿到配置信息,我们继续点击查看怎样拿到配置信息

         

我们搜索这个路径

文件里面就是配置的文件

4.@AutoConfigurationPackage

我们接下来看这个注解

点进进入

我们点进Registrar

里面就是获取包的名字之类的

总结

 

 
 
 

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值