Spring核心概念
BeanDefinition
BeanDefinition作为Bean的元数据载体,封装了Bean的所有配置信息(如类名、作用域、初始化方法、属性值等),相当于一个蓝图,告诉Spring如何创建和管理这个Bean。
| 属性名 | 描述 | 作用 |
|---|---|---|
| beanClass | 指定bean类的全限定名 | 用于通过读取指定路径下的类文件 |
| beanClass | 指定bean的类型 | 用于通过反射创建bean实例 |
| scope | 定义bean的作用域 singleton, prototype request, session等 | 决定bean是单例还是每次请求都创建新实例 |
| lazyInit | 标识是否延迟初始化 | 控制bean是否应该延迟初始化 |
| factoryBeanName | 如果使用工厂方法创建bean,则指定工厂bean的名字 | 配合factoryMethodName使用来指定创建bean的工厂bean |
| factoryMethodName | 如果使用工厂方法创建bean,则指定工厂方法的名字 | 配合factoryBeanName使用来指定创建bean的方法 |
| propertyValues | 包含所有设置到bean上的属性值 | 用于注入依赖或设置bean的属性值 |
| constructorArgumentValues | 包含传递给bean构造函数的所有参数值 | 用于指定构造函数注入时需要的参数 |
| initMethodName | 指定bean初始化后要调用的方法名 | 在bean的所有属性设置完成后调用,进行一些初始化操作 |
| destroyMethodName | 指定bean销毁前要调用的方法名 | 在容器关闭时调用,进行资源清理等操作 |
| role | 定义bean的角色 ROLE_APPLICATION ROLE_SUPPORT ROLE_INFRASTRUCTURE | 表示bean的角色,有助于理解其用途 |
| description | 对bean定义的描述 | 提供关于bean定义的额外信息,便于理解和维护 |
public abstract class AbstractBeanDefinition
extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// volatile关键字用于声明一个变量,确保其值的修改对所有线程都是立即可见的
@Nullable
private volatile Object beanClass;
} /**
* Specify the bean class name of this bean definition.
*/
@Override
public void setBeanClassName(@Nullable String beanClassName) {
this.beanClass = beanClassName;
} /**
* Specify the class for this bean.
* @see #setBeanClassName(String)
*/
public void setBeanClass(@Nullable Class<?> beanClass) {
this.beanClass = beanClass;
} /**
* Return the current bean class name of this bean definition.
*/
@Override
@Nullable
public String getBeanClassName() {
Object beanClassObject = this.beanClass;
if (beanClassObject instanceof Class) {
return ((Class<?>) beanClassObject).getName();
}
else {
return (String) beanClassObject;
}
} /**
* Return the specified class of the bean definition (assuming it is resolved already).
**/
public Class<?> getBeanClass() throws IllegalStateException {
Object beanClassObject = this.beanClass;
if (beanClassObject == null) {
throw new IllegalStateException("No bean class specified on bean definition");
}
if (!(beanClassObject instanceof Class)) {
throw new IllegalStateException(
"Bean class name [" + beanClassObject + "] has not been resolved into an actual Class");
}
return (Class<?>) beanClassObject;
}BeanDefinition的beanClass属性
BeanDefinition的beanClass属性为Object类型
beanClass起初存储的是一个字符串值,值为目标bean类的全限定名(Fully Qualified Name)。
一旦beanClass被设置为某个具体的Class<?>对象,它允许Spring容器直接使用反射来创建该类型的实例,而不需要再经过类名到Class对象的转换过程。
| 类名 | 特点 | 使用场景 |
|---|---|---|
| RootBeanDefinition | 继承自AbstractBeanDefinition,用于描述最基础和完整的bean定义信息。不依赖于父bean定义。 | 适用于需要明确指定bean所有属性值的情况,特别是在XML配置或编程式注册bean定义时。 |
| ConfigurationClassBeanDefinition | 继承自RootBeanDefinition,主要用于处理基于@Configuration类的bean定义,支持嵌套配置类等高级特性。 | 当使用@Configuration注解进行Java配置时自动使用,简化了基于配置类的bean管理。 |
| ClassDerivedBeanDefinition | 继承自RootBeanDefinition,主要用于从工厂方法创建的bean定义,帮助推断实际类型。 | 在需要通过工厂方法动态创建bean,并且需要类型推断的情况下使用。 |
| ChildBeanDefinition | 继承自AbstractBeanDefinition,允许一个bean继承另一个bean的定义,可以覆盖某些特定的属性。 | 当多个bean共享一些共同的配置但又需要在某些方面有所区别时非常有用。 |
| GenericBeanDefinition | 继承自AbstractBeanDefinition,提供了一种通用的bean定义方式,可以动态设置或修改各种bean属性,如作用域、初始化方法等。 | 适用于几乎所有场景,尤其是那些需要在运行时根据条件动态调整bean配置的情况。 |
| ScannedGenericBeanDefinition | 继承自GenericBeanDefinition,专门用于组件扫描过程中发现的bean定义,提供了对扫描到的注解元数据的支持。 | 在使用组件扫描(例如@ComponentScan)自动检测候选组件时使用,便于自动注册和管理组件。 |
| AnnotatedGenericBeanDefinition | 继承自GenericBeanDefinition,特别设计用来处理带有注解的类,支持注解元数据访问。 | 在基于注解的配置场景下使用,特别是当需要编程式地注册带注解的bean定义时。 |
在Spring中,我们经常会通过以下几种方式来定义Bean:
<bean/>标签@Bean注解@Component(@Service,@Controller)注解
这些,我们可以称之申明式定义Bean。
我们还可以编程式定义Bean,那就是直接通过BeanDefinition注册Bean的元配置信息,比如:
public class ServeApplication {
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 在容器中注册BeanDefinition
// 使用BeanDefinitionBuilder构建BeanDefinition,使用的是 GenericBeanDefinition 类
AbstractBeanDefinition beanDefinitionOfOrderService = BeanDefinitionBuilder.genericBeanDefinition(OrderService.class)
.setScope(BeanDefinition.SCOPE_SINGLETON) // 设置作用域为 单例
.setInitMethodName("test") // 设置初始化方法
.setLazyInit(false) // 设置非懒加载, 默认也是非懒加载
.getBeanDefinition();
applicationContext.registerBeanDefinition("orderService", beanDefinitionOfOrderService);
applicationContext.refresh();
OrderService orderService = applicationContext.getBean(OrderService.class);
System.out.println(orderService);
orderService.test();
}
}public class Test {
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 在容器中注册BeanDefinition
// 直接 new AnnotatedGenericBeanDefinition,解读UserService.class
AnnotatedGenericBeanDefinition annotatedGenericBeanDefinitionOfUserService = new AnnotatedGenericBeanDefinition(UserService.class);
// 如果UserService类中未添加@Component等配置元信息,需要自行定义,否则在getBean时无法获取 NoSuchBeanDefinition
// annotatedGenericBeanDefinitionOfUserService.setBeanClass(UserService.class);
// annotatedGenericBeanDefinitionOfUserService.setInitMethodName("test");
// annotatedGenericBeanDefinitionOfUserService.setLazyInit(true);
applicationContext.registerBeanDefinition("userService", annotatedGenericBeanDefinitionOfUserService);
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(userService);
userService.test();
}
}/**
* 此时的OrderService可以不添加@Component的注解配置信息,
* 因为已经在BeanDefinition中定义了Bean的配置元信息
**/
public class OrderService {
public void test() {
System.out.println("orderService");
}
}/**
* 此时的UserService仍然需要添加@Component,
* 因为只是在AnnotatedGenericBeanDefinition的构造方法中传入了UserService.class,
* 构造方法内部还是会解读UserService.class文件内容,获取对应Bean的配置元信息,
* 并解析为AnnotatedGenericBeanDefinition对象存储起来
**/
@Component
public class UserService {
public void test(){
System.out.println("userService");
}
}和编程式事务类似,通过,@Bean,@Component等申明式方式所定义的Bean,最终都会被Spring解析为对应的BeanDefinition对象,并放入Spring容器中。
RootBeanDefinition
直接实现 BeanDefinition 接口,不依赖于父 Bean 定义。适用于定义独立的、完整的 Bean 配置。 当需要明确指定一个 Bean 的所有属性值时使用,特别是在 XML 配置或编程式注册 Bean 定义时。
ConfigurationClassBeanDefinition
ConfigurationClassBeanDefinition 主要用于处理基于 @Configuration 注解的类的 Bean 定义。这些配置类通常包含用 @Bean 注解的方法,这些方法定义了如何创建和配置 Spring 容器中的 Beans。
ClassDerivedBeanDefinition
ClassDerivedBeanDefinition 是 Spring 中的一个内部类,主要用于从工厂方法创建的 Bean 定义过程中帮助推断实际返回对象的类型。它继承自 AbstractBeanDefinition 并实现了 BeanDefinition 接口。
GenericBeanDefinition
自 Spring 2.5 引入以来,逐渐成为最常用的 Bean 定义方式,因为它提供了极大的灵活性。 支持动态更改 Bean 的各种属性,如作用域、自动装配模式等。 由于其灵活性和通用性,它被广泛应用于基于注解的配置、Java 配置以及其他需要程序化定义 Bean 的场景中。
ScannedGenericBeanDefinition
基于注解的配置支持:ScannedGenericBeanDefinition 特别适合于处理那些通过注解(如 @Component, @Service, @Repository, @Controller 等)标注的类。这些类在被扫描后,会根据它们的注解和类信息生成对应的 ScannedGenericBeanDefinition 实例。
package cn.knowledge;
import cn.knowledge.service.UserService;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ServeApplication {
public static void main(String[] args) {
// 扫描, 创建非懒加载的单例Bean 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
/**
* 打印
* Generic bean:
* class [cn.knowledge.service.UserService];
* scope=singleton;
* abstract=false;
* lazyInit=null;
* autowireMode=0;
* dependencyCheck=0;
* autowireCandidate=true;
* primary=false;
* factoryBeanName=null;
* factoryMethodName=null;
* initMethodName=null;
* destroyMethodName=null;
*/
BeanDefinition userServiceBeanDefinition = applicationContext.getBeanDefinition("userService");
System.out.println(userServiceBeanDefinition);
/**
* 打印 class org.springframework.context.annotation.ScannedGenericBeanDefinition
*/
Class<? extends BeanDefinition> beanDefinitionClass = userServiceBeanDefinition.getClass();
System.out.println(beanDefinitionClass);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
}
}@ComponentScan("cn.knowledge")
public class AppConfig {
}@Component
public class UserService {
public void test(){
System.out.println("userService");
}
}AnnotatedGenericBeanDefinition
支持注解元数据:使得可以通过注解@Component, @Service, @Repository, @Controller 等注解来定义bean,并能够访问这些注解相关的元数据信息通过扫描注解定义的Bean时,最终会被解析为ScannedGenericBeanDefinition类来存储Bean的元信息。也可以在容器中直接使用AnnotatedGenericBeanDefinition类来解读注解定义的Bean,最终会被解析为AnnotatedGenericBeanDefinition类来存储Bean的元信息。
package cn.knowledge;
import cn.knowledge.service.UserService;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ServeApplication {
public static void main(String[] args) {
// 扫描, 创建非懒加载的单例Bean 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 直接向 ApplicationContext 中注册注解定义的Bean对象,生成 AnnotatedGenericBeanDefination
AnnotatedGenericBeanDefinition annotatedGenericBeanDefinitionOfUserService = new AnnotatedGenericBeanDefinition(UserService.class);
applicationContext.registerBeanDefinition("userService", annotatedGenericBeanDefinitionOfUserService);
applicationContext.refresh();
/**
* 打印
* Generic bean: class [cn.knowledge.service.UserService];
* scope=;
* abstract=false;
* lazyInit=null;
* autowireMode=0;
* dependencyCheck=0;
* autowireCandidate=true;
* primary=false;
* factoryBeanName=null;
* factoryMethodName=null;
* initMethodName=null;
* destroyMethodName=null
*/
userServiceOfBeanDefinition = applicationContext.getBeanDefinition("userService");
System.out.println(userServiceOfBeanDefinition);
/**
* 打印 class org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
*/
beanDefinitionClassOfUserService = userServiceOfBeanDefinition.getClass();
System.out.println(beanDefinitionClassOfUserService);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
}
}package cn.knowledge.service;
@Component
public class UserService {
public void test(){
System.out.println("userService");
}
}ChildBeanDefinition
BeanDefinitionReader
BeanDefinitionReader接口设计的初衷主要为了从特定资源(如XML文件、Groovy脚本等)读取bean定义的方法,其核心方法是loadBeanDefinitions,用于从特定资源加载和注册bean定义。
AnnotatedBeanDefinitionReader
然而,AnnotatedBeanDefinitionReader 类设计的目的是支持基于注解的bean定义注册过程,它提供了更便捷的方法来手动注册带有特定注解的类,如@Component, @Service, @Repository, @Controller等类,而不是从外部资源读取配置信息,它的职责与典型的BeanDefinitionReader实现(例如XmlBeanDefinitionReader或GroovyBeanDefinitionReader)有所不同,可以直接把某个类的配置信息解析并转换为BeanDefinition,因此,AnnotatedBeanDefinitionReader 类并未实现BeanDefinitionReader接口 比如
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
// 将User.class解析为BeanDefinition
annotatedBeanDefinitionReader.register(User.class);
System.out.println(context.getBean("user"));WARNING
注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
XmlBeanDefinitionReader
可以解析标签
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(context.getBean("user"));ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似, 它可以进行扫描,扫描某个包路径,对扫描到的类进行解析, 比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition, 比如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("com.zhouyu");
System.out.println(context.getBean("userService"));BeanDefinitionRegistry
BeanFactory
BeanFactory表示Bean工厂,所以很明显,BeanFactory会负责创建Bean,并且提供获取Bean的API。
而ApplicationContext是BeanFactory的一种,在Spring源码中,是这么定义的:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
...
}首先,在Java中,接口是可以多继承的, ApplicationContext继承了ListableBeanFactory和HierarchicalBeanFactory, 而ListableBeanFactory和HierarchicalBeanFactory都继承至BeanFactory, 所以我们可以认为ApplicationContext继承了BeanFactory, ApplicationContext也是BeanFactory的一种,拥有BeanFactory支持的所有功能, 不过ApplicationContext比BeanFactory更加强大, ApplicationContext还基础了其他接口,也就表示ApplicationContext还拥有其他功能, 比如MessageSource表示国际化,ApplicationEventPublisher表示事件发布,EnvironmentCapable表示获取环境变量,等等, 关于ApplicationContext后面再详细讨论。
在Spring的源码实现中,当我们new一个ApplicationContext时,其底层会new一个BeanFactory出来, 当使用ApplicationContext的某些方法时,比如getBean(),底层调用的是BeanFactory的getBean()方法。
在Spring源码中,BeanFactory接口存在一个非常重要的实现类是:DefaultListableBeanFactory,也是非常核心的。 所以,我们可以直接来使用DefaultListableBeanFactory,而不用使用ApplicationContext的某个实现类来进行Bean的创建,比如:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanFactory.registerBeanDefinition("user", beanDefinition);
System.out.println(beanFactory.getBean("user"));DefaultListableBeanFactory类继承实现结构
它实现了很多接口,表示,它拥有很多功能:
- AliasRegistry:支持别名功能,一个名字可以对应多个别名
- BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
- BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
- SingletonBeanRegistry:可以直接注册、获取某个单例Bean
- SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
- ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
- HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
- DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
- ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
- FactoryBeanRegistrySupport:支持了FactoryBean的功能
- AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配
- AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和获取beanNames
- ConfigurableListableBeanFactory:继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory
- AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能
- DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大
ApplicationContext
ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory更加强大
- HierarchicalBeanFactory:拥有获取父BeanFactory的功能
- ListableBeanFactory:拥有获取beanNames的功能
- ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
- EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
- ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
- MessageSource:拥有国际化功能
AnnotationConfigApplicationContext

- ConfigurableApplicationContext
- 继承了ApplicationContext接口,增加了
- 添加事件监听器、
- 添加BeanFactoryPostProcessor、
- 设置Environment,
- 获取ConfigurableListableBeanFactory等功能
- AbstractApplicationContext
- 实现了ConfigurableApplicationContext接口
- GenericApplicationContext
- 继承了AbstractApplicationContext,拥有了所有ApplicationContext的功能
- 实现了BeanDefinitionRegistry接口,可以注册BeanDefinition
- 类中有一个属性 DefaultListableBeanFactory beanFactory
- AnnotationConfigRegistry
- 可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
- AnnotationConfigApplicationContext
- 继承了GenericApplicationContext
- 实现了AnnotationConfigRegistry接口
ClassPathXmlApplicationContext
它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition
国际化
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。 同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:
context.getMessage("test", null, new Locale("en_CN"))资源加载
ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework-5.3.10\\tuling\\src\\main\\java\\com\\zhouyu\\service\\UserService.java");
System.out.println(resource.contentLength());你可以想想,如果你不使用ApplicationContext,而是自己来实现这个功能,就比较费时间了。
还比如你可以:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Resource resource = context.getResource("file://D:\\IdeaProjects\\spring-framework-5.3.10\\tuling\\src\\main\\java\\com\\zhouyu\\service\\UserService.java");
System.out.println(resource.contentLength());
System.out.println(resource.getFilename());
Resource resource1 = context.getResource("https://www.baidu.com");
System.out.println(resource1.contentLength());
System.out.println(resource1.getURL());
Resource resource2 = context.getResource("classpath:spring.xml");
System.out.println(resource2.contentLength());
System.out.println(resource2.getURL());获取运行时环境
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Map<String, Object> systemEnvironment = context.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);
System.out.println("=======");
Map<String, Object> systemProperties = context.getEnvironment().getSystemProperties();
System.out.println(systemProperties);
System.out.println("=======");
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);
System.out.println("=======");
System.out.println(context.getEnvironment().getProperty("NO_PROXY"));
System.out.println(context.getEnvironment().getProperty("sun.jnu.encoding"));
System.out.println(context.getEnvironment().getProperty("zhouyu"));注意,可以利用
@PropertySource("classpath:spring.properties")来使得某个properties文件中的参数添加到运行时环境中
事件发布
先定义一个事件监听器
@Bean
public ApplicationListener applicationListener() {
return new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("接收到了一个事件");
}
};
}然后发布一个事件:
context.publishEvent("kkk");类型转化
在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。
PropertyEditor
这其实是JDK中提供的类型转化工具类
public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
User user = new User();
user.setName(text);
this.setValue(user);
}
}StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);如何向Spring中注册PropertyEditor:
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
Map<Class<?>, Class<? extends PropertyEditor>> propertyEditorMap = new HashMap<>();
// 表示StringToUserPropertyEditor可以将String转化成User类型,在Spring源码中,如果发现当前对象是String,而需要的类型是User,就会使用该PropertyEditor来做类型转化
propertyEditorMap.put(User.class, StringToUserPropertyEditor.class);
customEditorConfigurer.setCustomEditors(propertyEditorMap);
return customEditorConfigurer;
}假设现在有如下Bean:
@Component
public class UserService {
@Value("xxx")
private User user;
public void test() {
System.out.println(user);
}
}那么test属性就能正常的完成属性赋值
ConversionService
Spring中提供的类型转化服务,它比PropertyEditor更强大
public class StringToUserConverter implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(String.class, User.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
User user = new User();
user.setName((String)source);
return user;
}
}DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User value = conversionService.convert("1", User.class);
System.out.println(value);如何向Spring中注册ConversionService:
@Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
return conversionServiceFactoryBean;
}TypeConverter
整合了PropertyEditor和ConversionService的功能,是Spring内部用的
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
//typeConverter.setConversionService(conversionService);
User value = typeConverter.convertIfNecessary("1", User.class);
System.out.println(value);OrderComparator
OrderComparator是Spring所提供的一种比较器,可以用来根据@Order注解或实现Ordered接口来执行值进行笔记,从而可以进行排序。
public class A implements Ordered {
@Override
public int getOrder() {
return 3;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}public class B implements Ordered {
@Override
public int getOrder() {
return 2;
}
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}public class Main {
public static void main(String[] args) {
A a = new A(); // order=3
B b = new B(); // order=2
OrderComparator comparator = new OrderComparator();
System.out.println(comparator.compare(a, b)); // 1
List list = new ArrayList<>();
list.add(a);
list.add(b);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // B,A
}
}另外,Spring中还提供了一个OrderComparator的子类:AnnotationAwareOrderComparator,它支持用@Order来指定order值。比如:
@Order(3)
public class A {
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}@Order(2)
public class B {
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}public class Main {
public static void main(String[] args) {
A a = new A(); // order=3
B b = new B(); // order=2
AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
System.out.println(comparator.compare(a, b)); // 1
List list = new ArrayList<>();
list.add(a);
list.add(b);
// 按order值升序排序
list.sort(comparator);
System.out.println(list); // B,A
}
}BeanPostProcessor
BeanPostProcess表示Bena的后置处理器,我们可以定义一个或多个BeanPostProcessor,比如通过一下代码定义一个BeanPostProcessor:
@Component
public class ZhouyuBeanPostProcessor 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的初始化之前以及初始化之后去额外的做一些用户自定义的逻辑,当然,我们可以通过判断beanName来进行针对性处理(针对某个Bean,或某部分Bean)。
我们可以通过定义BeanPostProcessor来干涉Spring创建Bean的过程。
BeanFactoryPostProcessor
BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程。比如,我们可以这样定义一个BeanFactoryPostProcessor:
@Component
public class ZhouyuBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("加工beanFactory");
}
}我们可以在postProcessBeanFactory()方法中对BeanFactory进行加工。
FactoryBean
上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean:
@Component
public class ZhouyuFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
UserService userService = new UserService();
return userService;
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
}通过上面这段代码,我们自己创造了一个UserService对象,并且它将成为Bean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入。
有同学可能会想到,通过@Bean也可以自己生成一个对象作为Bean,那么和FactoryBean的区别是什么呢?其实在很多场景下他俩是可以替换的,但是站在原理层面来说的,区别很明显,@Bean定义的Bean是会经过完整的Bean生命周期的。
ExcludeFilter和IncludeFilter
这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器。
比如以下配置,表示扫描com.zhouyu这个包下面的所有类,但是排除UserService类,也就是就算它上面有@Component注解也不会成为Bean。
@ComponentScan(value = "com.zhouyu",
excludeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)}.)
public class AppConfig {
}再比如以下配置,就算UserService类上没有@Component注解,它也会被扫描成为一个Bean。
@ComponentScan(value = "com.zhouyu",
includeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)})
public class AppConfig {
}FilterType分为:
- ANNOTATION:表示是否包含某个注解
- ASSIGNABLE_TYPE:表示是否是某个类
- ASPECTJ:表示否是符合某个Aspectj表达式
- REGEX:表示是否符合某个正则表达式
- CUSTOM:自定义
在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下Spring扫描过程中会认为类上有@Component注解的就是Bean。
MetadataReader、ClassMetadata、AnnotationMetadata
在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。
MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:
public class Test {
public static void main(String[] args) throws IOException {
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
// 构造一个MetadataReader
MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.zhouyu.service.UserService");
// 得到一个ClassMetadata,并获取了类名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// 获取一个AnnotationMetadata,并获取类上的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
System.out.println(annotationType);
}
}
}需要注意的是,SimpleMetadataReader去解析类时,使用的ASM技术。
为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。

