 个人主页:Dikz12个人专栏:Spring学习之路格言:吾愚多不敏,而愿加学欢迎大家点赞✍评论⭐收藏

目录

Bean的作用域

代码实现

观察Bean的作用域

Bean的生命周期

Spring Boot自动配置

原理分析 

1. 元注解.

2.  @SpringBootConfiguration.

3. @EnableAutoConfiguration (开启⾃动配置).

4.@ComponentScan (包扫描)

总结 

Bean的作用域

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

singleton:单例作⽤域 prototype:原型作⽤域(多例作⽤域) request:请求作⽤域 session:会话作⽤域  Application: 全局作⽤域  websocket:HTTP WebSocket 作⽤域

     作⽤域

 说明

singleton

每个Spring IoC容器内同名称的bean只有⼀个实例(单例)(默认)

prototype

每次使⽤该bean时会创建新的实例(⾮单例)

request

每个HTTP 请求⽣命周期内, 创建新的实例(web环境中, 了解)

session

每个HTTP Session⽣命周期内, 创建新的实例(web环境中, 了解)

 Application

每个ServletContext⽣命周期内, 创建新的实例(web环境中, 了解)

websocket

每个WebSocket⽣命周期内, 创建新的实例(web环境中, 了解)

官方参考文档:https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html

代码实现

定义几个不同作用域Bean.

@Configuration

public class BeanConfig {

@Scope("singleton")

@Bean

public User singleUser() {

return new User();

}

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

@Bean

public User prototypeUser() {

return new User();

}

//请求作用域

@RequestScope

@Bean

public User requestUser() {

return new User();

}

//会话作用域

@SessionScope

@Bean

public User sessionUser() {

return new User();

}

//全局作用域

@ApplicationScope

@Bean

public User applicationUser() {

return new User();

}

}

@RequestScope

等同于

@Scope(value = WebApplicationContext.SCOPE_REQUEST

, proxyMode = ScopedProxyMode.TARGET_CLASS

)

proxyMode⽤来为spring bean设置代理.

proxyMode = ScopedProxyMode.

TARGET_CLASS

表⽰这个Bean基于CGLIB实现动态代理. Request, session和application作⽤域的Bean 需要设置

proxyMode

@RestController

@RequestMapping("/scope")

public class BeanScopeController {

@Autowired

private ApplicationContext context;

@Resource(name = "singleUser")

private User singleUser;

@Resource(name = "prototypeUser")

private User prototypeUser;

@Resource(name = "requestUser")

private User requestUser;

//单例作用域

@RequestMapping("/single")

public String single(){

/**

* 1. 从context获取对象

* 2. 属性注入获取对象

*/

User user = (User) context.getBean("singleUser");

return "context获取的对象:"+user+",属性注入获取的对象:"+singleUser;

}

//原型作用域(多例)

@RequestMapping("/prototype")

public String prototypeUser(){

/**

* 1. 从context获取对象

* 2. 属性注入获取对象

*/

User user = (User) context.getBean("prototypeUser");

// 栈上的引用地址

// return "context获取的对象:"+user+",属性注入获取的对象:"+prototypeUser;

//打印内存地址

return "context获取的对象:"+System.identityHashCode(user)+",属性注入获取的对象:"+System.identityHashCode(prototypeUser);

}

//请求作用域

@RequestMapping("/request")

public String requestUser() {

User user = (User) context.getBean("requestUser");

// return "context获取的对象:"+System.identityHashCode(user)+",属性注入获取的对象:"+System.identityHashCode(requestUser);

System.out.println(user.toString());

System.out.println(user.getClass().getName() + "@" + Integer.toHexString(user.hashCode()));

return "context获取的对象:"+user+",属性注入获取的对象:"+requestUser;

}

}

观察Bean的作用域

单例作用域 :

多次访问, 得到的都是同⼀个对象, 并且 @Autowired 和 applicationContext.getBean() 也是同⼀个对象.

多例作用域 :

观察ContextDog, 每次获取的对象都不⼀样(注⼊的对象在Spring容器启动时, 就已经注⼊了, 所以多次 请求也不会发⽣变化).

请求作用域:

在⼀次请求中,

@Autowired

applicationContext.getBean()

也是同⼀个对象.

但是每次请求, 都会重新创建对象.

Bean的生命周期

⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程,我们把这个过程就叫做⼀个对象的⽣命周期.

1. 实例化(为Bean分配内存空间) 2. 属性赋值(Bean注⼊和装配,⽐如 @AutoWired ) 3. 初始化        a. 执⾏各种通知,如BeanNameAware ,BeanFactoryAware ,ApplicationContextAware 的接⼝⽅法.       b. 执⾏初始化⽅法            ▪ xml定义 init-method            ▪ 使⽤注解的⽅式 @PostConstruct            ▪ 执⾏初始化后置⽅法( BeanPostProcessor ) 4. 使⽤Bean.

5.销毁Bean.

实例化和属性赋值对应构造⽅法和setter⽅法的注⼊.  初始化和销毁是⽤⼾能⾃定义扩展的两个阶段,可以在实例化之后,类加载完成之前进⾏⾃定义"事件"处理.

⽐如我们现在需要买⼀栋房⼦,那么我们的流程是这样的:

先买房(实例化,从⽆到有)装修(设置属性)买家电,如洗⾐机,冰箱,电视,空调等([各种]初始化,可以⼊住);⼊住(使⽤ Bean)卖房(Bean 销毁)

 执行流程如下:

Spring Boot自动配置

SpringBoot的⾃动配置就是当Spring容器启动后,⼀些配置类,bean对象等就⾃动存⼊到了IoC容器中,不需要我们⼿动去声明,从⽽简化了开发,省去了繁琐的配置操作. SpringBoot⾃动配置,就是指SpringBoot是如何将依赖jar包中的配置类以及Bean加载到Spring IoC容器中的.

原理分析 

SpringBoot是如何帮助我们做的呢?⼀切的来⾃起源SpringBoot的启动类开始.

@SpringBootApplication 标注的类就是SpringBoot项⽬的启动类.

@SpringBootApplication

public class SpringIocApplication {

public static void main(String[] args) {

//获取Spring上下⽂对象

ApplicationContext context = SpringApplication.run(SpringIocApplication.class, args);

//从Spring上下⽂中获取对象

BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);

beanLifeComponent.use();

}

}

这个类和普通类唯⼀的区别就是 @SpringBootApplication 注解,这个注解也是SpringBoot实现 ⾃动配置的核⼼.

@SpringBootApplication 是⼀个组合注解,注解中包含了:

1. 元注解.

JDK中提供了4个标准的⽤来对注解类型进⾏注解的注解类,我们称之为meta-annotation(元注 解),他们分别是: • @Target描述注解的使⽤范围(即被修饰的注解可以⽤在什么地⽅) • @Retention描述注解保留的时间范围 • @Documented描述在使⽤javadoc⼯具为类⽣成帮助⽂档时是否要保留其注解信息 • @Inherited使被它修饰的注解具有继承性(如果某个类使⽤了被@Inherited修饰的注解,则 其⼦类将⾃动具有该注解)

2.  @SpringBootConfiguration.

⾥⾯就是@Configuration,标注当前类为配置类,其实只是做了⼀层封装改了个名字⽽已. (@Indexed注解,是⽤来加速应⽤启动的,不⽤关⼼)

3. @EnableAutoConfiguration (开启⾃动配置).

  看下@EnableAutoConfiguration 注解的实现:

这个注解包含两部分: 1. @Import({AutoConfigurationImportSelector.class}) 。

    使⽤@Import注解,导⼊了实现ImportSelector接⼝的实现类 .

    selectImports() ⽅法底层调⽤ getAutoConfigurationEntry() ⽅法,获取可⾃动配置的    配置类信息集合.   getAutoConfigurationEntry() ⽅法通过调⽤  getCandidateConfigurations(annotationMetadata, attributes) ⽅法获取在配置⽂件中配置的所有⾃动配置类的集合.

2. @AutoConfigurationPackage.

这个注解主要是导⼊⼀个配置⽂件 AutoConfigurationPackages.Registrar.class.

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

Registrar() {

}

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));

}

public Set determineImports(AnnotationMetadata metadata) {

return Collections.singleton(new PackageImports(metadata));

}

}

 (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0])) : 当前启动类的包名.

所以,Registrar实现了 ImportBeanDefinitionRegistrar 类,就可以被注解@Import导⼊到spring容器⾥.

4.@ComponentScan (包扫描)

可以通过 basePackageClasses  或 basePackages 来定义要扫描的特定包,如果没有定义 特定的包,将从声明该注解的类的包开始扫描,这也是为什么SpringBoot项⽬声明的注解类必须要在启动类的⽬录下. excludeFilters⾃定义过滤器,通常⽤于排除⼀些类,注解等.

总结 

SpringBoot⾃动配置原理的⼤概流程如下:

 

文章链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。

发表评论

返回顶部暗黑模式