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 )

  1. 使⽤Bean

  2. 销毁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

复制代码
里面就是获取包的名字之类的

总结

复制代码
复制代码
复制代码
复制代码
相关推荐
蓝澈112128 分钟前
迪杰斯特拉算法之解决单源最短路径问题
java·数据结构
Kali_0735 分钟前
使用 Mathematical_Expression 从零开始实现数学题目的作答小游戏【可复制代码】
java·人工智能·免费
rzl021 小时前
java web5(黑马)
java·开发语言·前端
时序数据说1 小时前
为什么时序数据库IoTDB选择Java作为开发语言
java·大数据·开发语言·数据库·物联网·时序数据库·iotdb
君爱学习1 小时前
RocketMQ延迟消息是如何实现的?
后端
guojl1 小时前
深度解读jdk8 HashMap设计与源码
java
Falling421 小时前
使用 CNB 构建并部署maven项目
后端
guojl1 小时前
深度解读jdk8 ConcurrentHashMap设计与源码
java
程序员小假1 小时前
我们来讲一讲 ConcurrentHashMap
后端