Spring底层架构核心概念
BeanDefinition
BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点
- class:表示Bean类型
- scope:表示Bean的作用域
- lazyInit:表示Bean是否是懒加载
- initMethodMethod:表示Bean初始化要执行的方法
- destoryMethod:表示Bean销毁时要执行的方法
在Spring中,可以通过以下几种方式定义Bean
- @Bean
- @Component(@Service、@Controller)
编程式定义Bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
context.registerBeanDefinition("user", beanDefinition);
System.out.println(context.getBean("user"));
可以通过设置BeanDefinition设置一个Bean的其他属性
beanDefinition.setScope("prototype"); // 设置作用域
beanDefinition.setInitMethodName("init"); // 设置初始化方法
beanDefinition.setLazyInit(true); // 设置懒加载
BeanDefinitionReader
- 是一个接口,读取Spring配置文件中的内容,将其转换为IOC容器内部的数据结构:BeanDefinition
AnnotatedBeanDefinitionReader
- 可以直接将某个类转换为BeanDefinition,并且会解析该类上的注解
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
// 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);
System.out.println(context.getBean("user"));
- 它能解析的注解是:@Conditional、@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
XMlBeanDefinitionReader
可以解析标签
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(applicationContext.getBean("user"));
ClassPathBeanDefinitionScanner
- ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到类进行解析,比如,扫描到的类如果存在@Component注解,那么就会把该类解析为一个BeanDefinition
applicationContext.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext);
scanner.scan("com.zhouyu");
System.out.println(applicationContext.getBean("userService"));
BeanFactory
- 是一个工厂(接口),它负责生产和管理bean的一个工厂。在Spring容器中,BeanFactory是工厂的顶层接口,也是IOC容器的核心接口,一次BeanFactory中定义了管理Bean的通用方方法,如getBean和containsBean等,它的职责包括:实例化、定位、配置应用程序中的对象以及建立这些对象中的依赖。
使用场景:
- 从IOC容器中获取Bean(byName or byType)
- 检索IOC容器中是否包含指定的Bean
- 判断bean是否是单例
ApplicationContext
- 是一个接口,本质上也是一个BeanFactory
- HierarchicalBeanFactory:拥有父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源文件(文件资源等)
- EnvironmentCapable:可以获取运行时环境
- ApplicationEventPublisher:拥有广播事件的功能
- MessageSource:拥有国际化的功能
国际化
先定义一个MessageSource
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
使用
context.getMessage("test", null, new Locale("en"))
FactoryBean
- 能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似
为什么会有FactoryBean?
- 在某些情况下,实例化Bean过程比较复杂。配置方式的灵活性是受限的,这个时候采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个
org.springframework.bean.factory.FactoryBean
的工厂类接口,用户可以通过该接口定制实例化Bean的逻辑。
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Component
public class MyFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
Person person = new Person();
person.setName("Acorn");
person.setAge(12);
return person;
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Person bean = (Person) applicationContext.getBean("myFactoryBean");
System.out.println(bean);
MyFactoryBean bean1 = (MyFactoryBean) applicationContext.getBean("&myFactoryBean");
System.out.println(bean1);
FactoryBean的使用场景
- FactoryBean在Spring中最典型的应用就是用用来创建AOP的代理对象
- AOP实际上是Spring在运行时创建了一个代理对象,也就是说这个对象,是我们在运行时创建的,而不是一开始就定义好的,这很符合工厂方法模式。更形象地说,AOP代理对象通过Java的反射机制,在运行时创建了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在Spring中就是——ProxyFactoryBean。
BeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("初始化前");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("初始化后");
}
return bean;
}
}
一个BeanPostProcessor可以在任意一个Bean的初始化前和初始化之后去额外做一些用户自定义的逻辑。