创建bean的方式:
声明式
<bean></bean>
-
<bean></bean>
: 通过xml来配置bean1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30"1.0" encoding="UTF-8" xml version=
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="p1" class="top.nymrli.tryboot.po.User">
<property name="name" value="张三"/>
<property name="age" value="18"/>
</bean>
</beans>
@Test
public void testPerson()
{
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = annotationConfigApplicationContext.getBean("p1", User.class);
System.out.println(user);
}
@Bean
-
@Bean
: 通过注解来标注SpringBean对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class Config {
"user") (
public User getUser(){
return new User("name", 20);
}
}
public void testPerson()
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(Config.class);
// 或者 AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
ctx.refresh();
User user = ctx.getBean("user", User.class);
System.out.println(user);
}AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
与ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
一样,都是指定bean的配置路径后解析,获得bean的配置。
@Component
-
@Component
: 通过标注来创建一个组件SpringBean对象,如下的User。 ==> 等价于ctx.registerBean(User.class)
,registerBean方法的实现最终也是调用了registerBeanDefinition而Config不是一个bean,他的作用跟applicationContext.xml一样,他是存放bean定义路径的一个配置文件,在这里是通过ComponentScan让Spring能够找到top.nymrli.tryboot.po下的所有Bean并解析成SpringBean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23"top.nymrli.tryboot.po") (
public class Config {
}
// ==> beanName为user, 类名小写
public class User {
private String name;
private int age;
}
public void testPerson()
{
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
User user = ctx.getBean(User.class);
System.out.println(user);
}会自动调用User的无参构造方式来创建JavaBean, 因此得到的User是
User(name=null, age=0)
▲.上述三种创建方式本质上都是创建了BeanDefinition,只不过Spring进行了封装,因此使用起来比较简单直观
@Import
spring4.2之后
@Import
注解可以实例化普通类的bean实例
1 |
|
Spring在创建MyConfig的时候,会根据@Import将Role也实例化成一个Bean
编程式
BeanDefinition
通过创建并配置 BeanDefinition 来创建一个Bean
Q: 什么是BeanDefinition?
A: BeanDefinition表示Bean的定义信息, Spring会根据BeanDefinition来创建Bean对象。BeanDefinition有很多的属性用来描述Bean, BeanDefinition是Spring中非常核心的概念。
- beanClass: 表示Bean对象的类类型, Spring在创建Bean的过程中根据此属性来判断实例化对象具体的类类型
- scope:作用域,[singleton、prototype],单例或者原型bean
- isLazy:是否需要懒加载,原型Bean的懒加载不奏效。懒加载的单例bean,会在第一次getBean的时候生成该bean,非懒加载的单例bean,则会在Spring.启动过程中直接生成好。
- dependsOn:表示一个bean在创建之前所依颗的其他bean,在一个bean创建之前,它所依赖的这些bean得先全部创建好。
- primary:表示一个bean是主bean,在Spring中一个类型可以有多个bean对象,在进行依赖注入时,如果根据类型找到了多个b©an,此时会判断这些bean中是否存在一个主bean,如果存在,则直接将这个bean注入给属性。
- initMethodName: 表示一个bean的初始化方法,一个bean的生命周期过程中有一个步骤叫初始化,Spring会在这个步骤中去调用bean的初始化方法。初始化逻辑由程序员自己控制,使得程序员可以自定义逻辑对bean进行加工。
通过
<bean></bean>
、@Bean
、@Component
标注的类都会解析为BeanDefinition,供Spring创建(实例化)具体的Bean。
1 |
|
FactoryBean
FactoryBean是Spring.所提供的一种较灵活的创建Bean的方式,可以通过实现FactoryBean:接口中的getObject()方法来返回一个对象,这个对象就是最终的Bean对象。
FactoryBean接口中的方法
- Object getObject():返回的是Bean对象
- boolean isSingleton():返回的是否是单例Bean对象
- Class getObjectType():返回的是Bean对象的类型
1 | "zhouyu") ( |
上述代码,实际上对应了两个Bean对象:
1、beanName为"zhouyu’,bean对象为getObject方法所返回的User对象。=>applicationcontext.getBean(name:"zhouyu",ZhouyuFactory.class);
2、beanName为"&zhouyu’,bean对象为ZhouyuFactoryBean类的实例对象。=>applicationcontext.getBean(name:"&zhouyu",ZhouyuFactoryBean.class);
与BeanFactory的区别:
- FactoryBean对象本身也是一个Bean,同时它相当于一个小型工厂,可以生产出另外的Bean。==》指定类型的Bean对象
- FactoryBean机制被广泛的应用在Spring内部和Spring-与第三方框架或组件的整合过程中。
- BeanFactory是一个Spring容器,是一个大型工厂,它可以生产出各种各样的Beano
Supplier
1 |
|
BeanFactory
BeanFactory是一种“Spring容器”, BeanFactory翻译过来就是Bean工厂,顾名思义,它可以用来创建Bean、获取Bean。
概念区分:
- BeanFactory将利用BeanDefinition:来生成Bean对象
- BeanDefinition相当于BeanFactory的原材料
- Bean对象就相当于BeanFactory)所生产出来的产品
BeanFactory的核心子接口和实现类:
- ListableBeanFactory
- ConfigurableBeanFactory
- AutowireCapableBeanFactory
- AbstractBeanFactory
- DefaultListableBeanFactory
···
Bean生命周期
Bean生命周期描述的是Spring中一个Bean创建过程和销毁过程中所经历的步骤,其中Bean创建过程是重点。程序员可以利用Bean生命周期机制对Bean进行自定义加工。
- Bean定义:通过xml或者编写类的形式来创建BeanDefinition
- 构造方法推断:从bean的多个构造方法中选出一个构造方法
- 实例化:通过构造方法反射获得对象,在Spring中可以通过BeanPostProcessor机制对实例化进行干预
- 属性填充(自动注入、依赖注入):给属性进行自动填充,比如@Value,@AutoWired
- 初始化:在一个对象的属性填充之后,Spring提供了初始化机制,让程序员可以对其他属性进行赋值、校验等自定义加工(利用InitializingBean接口)
- 初始化后:Aop、生成代理对象。常说的Aop机制就是在这个步骤中通过BeanPostProcessor机制实现的,这步之后获得的对象才是真正的Bean对象
创建过程:
生命周期图:
属性填充注解:@Autowired、@Resource、@Value
@Autowired.
表示某个属性是否需要进行依赖注入,可以写在属性和方法上。注解中的required属性默认为ture,表示如果没有对象可以注入给属性则抛异常。
-
@Autowired:加在某个属性上,Spring在进行Bean的生命周期过程中,在属性填充这一步会基于实例化出来的对象,对该对象中加了@Autowired的属性自动给属性赋值。具体实现为: Spring会先根据属性的类型去Spring容器中找出该类型所有的Bean对象,如果找出来多个,则再根据属性的名字从多个中再确定一个。如果required属性为true,并且根据属性信息找不到对象,则直接抛异常。
-
当@Autowired注解写在某个方法上时,Spring在B ean生命周期的属性填充阶段,会根据方法的参数类型、参数名字从Spring容器找到对象当做方法入参,自动反射调用该方法。
-
@Autowired加在构造方法上时,Spring会在推断构造方法阶段,选择该构造方法来进行实例化,在反射调用构造方法之前,会先根据构造方法参数类型、参数名从Spring容器中找到Bean对象,当做构造方法入参。
@Resource
@Resource注解与@Autowired类似,也是用来进行依赖注入的,@Resource是Java层面所提供的注解,@Autowired.是Spring所提供的注解,它们依赖注入的底层实现逻辑也不同。
@Resource:注解中有一个name属性,针对na me属性是否有值,@Resource的依赖注入底层流程是不同的。
- @Reousrce:如果name属性有值,那么Spring会直接根据所指定的name值去Spring容器找Bean对象,如果找到了则成功,如果没有找到,则报错。
- 如果@Resource中的name属性没有值,则:
- 先判断该属性名字在Spring容器中是否存在Bean对象。
- 如果存在,则成功找到Bean对象进行注入。
- 如果不存在,则根据属性类型去Spring容器找Bean对象,找到一个则进行注入。
@Value
@Value注解和@Resource、@Autowired类似,也是用来对属性进行依赖注入的,只不过@Value是用来从Properties.文件中来获取值的,并且@Value可以解析SpEL(Spring表达式)。
-
@Value("yuzhou")
: 直接将字符串“zhouyu”赋值给属性,如果属性类型不是String,或无法进行类型转化,则报错。 -
@Value(${"yuzhou"})
: 将会把${}
中的字符串当做key,从Properties文件中找出对应的value赋值给属性,如果没找到,则会把${zhouyu}
当做普通字符串注入给属性。 -
@Value(#{"yuzhou"})
:会将#{}
中的字符串当做Spring表达式进行解析,Spring会把"zhouyu"当做beanName,并从Spring容器中找对应bean,如果找到则进行属性注入,没找到则报错。
ApplicationContext
ApplicationContext是比BeanFactory更加强大的Spring容器,它既可以创建bean、获取bean,还支持国际化、事件广播、获取资源等BeanFactor y不具备的功能。
Application Context,所继承的接口
- EnvironmentCapable:拥有获取环境变量的能力:操作系统环境变量和Jvm环境变量
- ListableBeanFactory:拥有了获取所有beanNames、判断某个bean Name是否存在peanDefinition对象、统计Be anDefinition个数、获取某个类型对应的所有beanNames等功能。
- HierarchicalBeanFactory:拥有了获取父BeanFactory、。判断某个name是否存在bean对象的功能。
- MessageSource:拥有了国际化功能,比如可以直接利用Messa geSource对象获取某个国际化资源(比如不同国家语言所对应的字符)
- ApplicationEventPublisher: 拥有了事件发布功能,可以发布事件,这是Application Context相对于BeanFactory比较突出、常用的功能。
- ResourcePatternResolver: 拥有了加载并获取资源的功能,这里的资源可以是文件,图片等某个URL资源都可以。
获得bean的方式:
getBean() API
-
按名称获取Bean
1
2
3Object lion = context.getBean("lion");
assertEquals(Lion.class, lion.getClass());根据bean名称获取bean,如果在spring ico容器中存在和bean,则返回Object 类的实例。否则,抛出如下异常NoSuchBeanDefinitionException。
▲: 主要的缺点是,在获取bean之后,我们必须将它指定转换为所需的类型。如果返回的bean的类型与我们期望的不同,则可能会产生异常。
-
通过名称和类型获取Bean
1
2
3
4
5
6
7Lion lion = context.getBean("lion", Lion.class);
// 与按名称获取Bean相比,此方法更安全,因为我们可以编译阶段就发现错误而不是在运行阶段。
assertThrows(BeanNotOfRequiredTypeException.class, () ->
context.getBean("lion", Tiger.class));
} -
按类型获取Bean
1 | // right |
由于Lion和Tiger都实现了Animal接口,因此仅指定类型不足以明确确定结果。因此,我们会得到一个*NoUniqueBeanDefinitionException
*。即在同一个IOC 容器中,如果有相同类型的多个bean,则不能通过类型获取bean。
- 按名称和构造函数参数对Bean进行筛选
1 | Tiger tiger = (Tiger) context.getBean("tiger", "Siberian"); |
-
按类型和构造函数参数对Bean进行筛选
▲: 这个方法有点不同,因为它只适用于具有原型作用域的bean。
1
2Tiger tiger = context.getBean(Tiger.class, "Shere Khan");
assertEquals("Shere Khan", tiger.getName());
BeanPostProcessor机制
BeanPostProcessor是Spring所提供的一种扩展机制,可以利用该机制对Bean进行定制化加工,在Spring底层源码实现中,也广泛的用到了该机制,BeanPostProcessor通常也叫做Bean后置处理器。
BeanPostProcessor在Spring中是一个接口,我们定义一个后置处理器,就是提供一个类实现该接口,在Spring中还存在一些接口继承了BeanPostProcessor,这些子接口是在BeanPostProcessor的基础上增加了一些其他的功能。
BeanPostProcessori中的方法
- postProcessBeforelnitialization():初始化前方法,表示可以利用这个方法来对Bean在初始化前进行自定义加工。
- postProcessAfterInitialization():初始化后方法,表示可以利用这个方法来对Bean在初始化后进行自定义加工。
InstantiationAwareBeanPostProcessor
BeanPostProcessor的一个子接口
- postProcessBeforelnstantiation():实例化前
- postProcessAfterInstantiation():实例化后
- postProcessProperties():属性注入后
AOP是什么?
AOP就是面向切面编程,是一种非常适合在无需修改业务代码的前提下,对某个或某些业务增加统一的功能(横向增加功能),比如日志记录、权限控制、事务管理等,能很好的使得代码解耦,提高开发效率。
Author: Mrli
Link: https://nymrli.top/2022/02/27/深入学习使用Spring/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.