Skip to content

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定义的额外信息,便于理解和维护
java
public abstract class AbstractBeanDefinition 
   extends BeanMetadataAttributeAccessor
   implements BeanDefinition, Cloneable {
     
     // volatile关键字用于声明一个变量,确保其值的修改对所有线程都是立即可见的
     @Nullable
	 private volatile Object beanClass;
	 
}
java
     /**
	 * Specify the bean class name of this bean definition.
	 */
	@Override
	public void setBeanClassName(@Nullable String beanClassName) {
		this.beanClass = beanClassName;
	}
java
    /**
	 * Specify the class for this bean.
	 * @see #setBeanClassName(String)
	 */
	public void setBeanClass(@Nullable Class<?> beanClass) {
		this.beanClass = beanClass;
	}
java
     /**
	 * 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;
		}
	}
java
	/**
	* 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对象的转换过程。

uml diagram
类名特点使用场景
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:

  1. <bean/>标签
  2. @Bean注解
  3. @Component(@Service,@Controller)注解

这些,我们可以称之申明式定义Bean。

我们还可以编程式定义Bean,那就是直接通过BeanDefinition注册Bean的元配置信息,比如:

java
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();

	}
	
}
java
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();

	}
	
}
java
/**
* 此时的OrderService可以不添加@Component的注解配置信息,  
* 因为已经在BeanDefinition中定义了Bean的配置元信息
**/
public class OrderService {

	public void test() {
		System.out.println("orderService");
	}

}
java
/**
* 此时的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 实例。

java
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();

	}
}
java
@ComponentScan("cn.knowledge")
public class AppConfig {

}
java
@Component
public class UserService {

	public void test(){
		System.out.println("userService");
	}

}

AnnotatedGenericBeanDefinition

支持注解元数据:使得可以通过注解@Component, @Service, @Repository, @Controller 等注解来定义bean,并能够访问这些注解相关的元数据信息
通过扫描注解定义的Bean时,最终会被解析为ScannedGenericBeanDefinition类来存储Bean的元信息。
也可以在容器中直接使用AnnotatedGenericBeanDefinition类来解读注解定义的Bean,最终会被解析为AnnotatedGenericBeanDefinition类来存储Bean的元信息。

java
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();

	}
}
java
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接口 比如

java
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

可以解析标签

java
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, 比如:

java
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源码中,是这么定义的:

java
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的创建,比如:

java
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);

beanFactory.registerBeanDefinition("user", beanDefinition);

System.out.println(beanFactory.getBean("user"));

DefaultListableBeanFactory类继承实现结构

DefaultListableBeanFactory继承结构 它实现了很多接口,表示,它拥有很多功能:

  1. AliasRegistry:支持别名功能,一个名字可以对应多个别名
  2. BeanDefinitionRegistry:可以注册、保存、移除、获取某个BeanDefinition
  3. BeanFactory:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象
  4. SingletonBeanRegistry:可以直接注册、获取某个单例Bean
  5. SimpleAliasRegistry:它是一个类,实现了AliasRegistry接口中所定义的功能,支持别名功能
  6. ListableBeanFactory:在BeanFactory的基础上,增加了其他功能,可以获取所有BeanDefinition的beanNames,可以根据某个类型获取对应的beanNames,可以根据某个类型获取{类型:对应的Bean}的映射关系
  7. HierarchicalBeanFactory:在BeanFactory的基础上,添加了获取父BeanFactory的功能
  8. DefaultSingletonBeanRegistry:它是一个类,实现了SingletonBeanRegistry接口,拥有了直接注册、获取某个单例Bean的功能
  9. ConfigurableBeanFactory:在HierarchicalBeanFactory和SingletonBeanRegistry的基础上,添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能
  10. FactoryBeanRegistrySupport:支持了FactoryBean的功能
  11. AutowireCapableBeanFactory:是直接继承了BeanFactory,在BeanFactory的基础上,支持在创建Bean的过程中能对Bean进行自动装配
  12. AbstractBeanFactory:实现了ConfigurableBeanFactory接口,继承了FactoryBeanRegistrySupport,这个BeanFactory的功能已经很全面了,但是不能自动装配和获取beanNames
  13. ConfigurableListableBeanFactory:继承了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory
  14. AbstractAutowireCapableBeanFactory:继承了AbstractBeanFactory,实现了AutowireCapableBeanFactory,拥有了自动装配的功能
  15. DefaultListableBeanFactory:继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口和BeanDefinitionRegistry接口,所以DefaultListableBeanFactory的功能很强大

ApplicationContext

ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory更加强大

  1. HierarchicalBeanFactory:拥有获取父BeanFactory的功能
  2. ListableBeanFactory:拥有获取beanNames的功能
  3. ResourcePatternResolver:资源加载器,可以一次性获取多个资源(文件资源等等)
  4. EnvironmentCapable:可以获取运行时环境(没有设置运行时环境功能)
  5. ApplicationEventPublisher:拥有广播事件的功能(没有添加事件监听器的功能)
  6. MessageSource:拥有国际化功能

AnnotationConfigApplicationContext

AnnotationConfigApplicationContext继承实现结构

  1. ConfigurableApplicationContext
    • 继承了ApplicationContext接口,增加了
    • 添加事件监听器、
    • 添加BeanFactoryPostProcessor、
    • 设置Environment,
    • 获取ConfigurableListableBeanFactory等功能
  2. AbstractApplicationContext
    • 实现了ConfigurableApplicationContext接口
  3. GenericApplicationContext
    • 继承了AbstractApplicationContext,拥有了所有ApplicationContext的功能
    • 实现了BeanDefinitionRegistry接口,可以注册BeanDefinition
    • 类中有一个属性 DefaultListableBeanFactory beanFactory
  4. AnnotationConfigRegistry
    • 可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描
  5. AnnotationConfigApplicationContext
    • 继承了GenericApplicationContext
    • 实现了AnnotationConfigRegistry接口

ClassPathXmlApplicationContext

ClassPathXmlApplicationContext继承实现结构 它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition

国际化

java
@Bean
public MessageSource messageSource() {
	ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
	messageSource.setBasename("messages");
	return messageSource;
}

有了这个Bean,你可以在你任意想要进行国际化的地方使用该MessageSource。 同时,因为ApplicationContext也拥有国家化的功能,所以可以直接这么用:

java
context.getMessage("test", null, new Locale("en_CN"))

资源加载

ApplicationContext还拥有资源加载的功能,比如,可以直接利用ApplicationContext获取某个文件的内容:

java
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,而是自己来实现这个功能,就比较费时间了。

还比如你可以:

java
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());

获取运行时环境

java
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"));

注意,可以利用

java
@PropertySource("classpath:spring.properties")

来使得某个properties文件中的参数添加到运行时环境中

事件发布

先定义一个事件监听器

java
@Bean
public ApplicationListener applicationListener() {
	return new ApplicationListener() {
		@Override
		public void onApplicationEvent(ApplicationEvent event) {
			System.out.println("接收到了一个事件");
		}
	};
}

然后发布一个事件:

java
context.publishEvent("kkk");

类型转化

在Spring源码中,有可能需要把String转成其他类型,所以在Spring源码中提供了一些技术来更方便的做对象的类型转化,关于类型转化的应用场景, 后续看源码的过程中会遇到很多。

PropertyEditor

这其实是JDK中提供的类型转化工具类

java
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);
	}
}
java
StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
propertyEditor.setAsText("1");
User value = (User) propertyEditor.getValue();
System.out.println(value);

如何向Spring中注册PropertyEditor:

java
@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:

java
@Component
public class UserService {

	@Value("xxx")
	private User user;

	public void test() {
		System.out.println(user);
	}

}

那么test属性就能正常的完成属性赋值

ConversionService

Spring中提供的类型转化服务,它比PropertyEditor更强大

java
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;
	}
}
java
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConverter());
User value = conversionService.convert("1", User.class);
System.out.println(value);

如何向Spring中注册ConversionService:

java
@Bean
public ConversionServiceFactoryBean conversionService() {
	ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
	conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));

	return conversionServiceFactoryBean;
}

TypeConverter

整合了PropertyEditor和ConversionService的功能,是Spring内部用的

java
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接口来执行值进行笔记,从而可以进行排序。

java
public class A implements Ordered {

	@Override
	public int getOrder() {
		return 3;
	}

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}
java
public class B implements Ordered {

	@Override
	public int getOrder() {
		return 2;
	}

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}
}
java
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值。比如:

java
@Order(3)
public class A {

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}

}
java
@Order(2)
public class B {

	@Override
	public String toString() {
		return this.getClass().getSimpleName();
	}

}
java
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:

java
@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:

java
@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:

java
@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。

java
@ComponentScan(value = "com.zhouyu",
excludeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)}.)
public class AppConfig {
}

再比如以下配置,就算UserService类上没有@Component注解,它也会被扫描成为一个Bean。

java
@ComponentScan(value = "com.zhouyu",
includeFilters = {@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)})
public class AppConfig {
}

FilterType分为:

  1. ANNOTATION:表示是否包含某个注解
  2. ASSIGNABLE_TYPE:表示是否是某个类
  3. ASPECTJ:表示否是符合某个Aspectj表达式
  4. REGEX:表示是否符合某个正则表达式
  5. CUSTOM:自定义

在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter给includeFilters,表示默认情况下Spring扫描过程中会认为类上有@Component注解的就是Bean。

MetadataReader、ClassMetadata、AnnotationMetadata

在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类。

MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。比如:

java
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技术。