Spring框架(二) 底层架构核心概念解析-四万字你值得一看

感兴趣的话大家可以关注一下公众号 : 猿人刘先生 , 欢迎大家一起学习 , 一起进步 , 一起来交流吧!

本篇文章将对Spring底层的一些概念做一些简单的分析 , 也是为了方便后续在阅读源码的时候更加的方便

BeanDefintion

BeanDefintion是一个接口 , 它表示一个Bean的定义 , BeanDefintion存在很多属性来描述一个Bean的特点 , Spring在扫描完需要注册的Bean之后会进行解析 , 而解析的数据就会存入到BeanDefintion
我们在定义Bean的时候可以分为两种方式 :

申明式

申明式定义一个Bean就比如我们用的@Bean , @Component等注解 , 或者是xml标签的形式来定义一个Bean

编程式

编程式就是通过写代码的方式来定义 , 如下
首先定义一个MenberService

public class MemberService {

	public void test(){
		System.out.println("test方法被调用...");
	}

}

接着我们从Spring获取这个’Bean’ , 看是否能获取到

public class TestSpring {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		MemberService memberService = (MemberService) applicationContext.getBean("memberService");

		memberService.test();

		
	}
}

运行之后我们回发现报错了 , 报错内容如下 :

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘memberService’ available
没有找到一个名为memberService的Bean来使用

我们再用编程式的方式定义

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		// 得到一个BeanDefinition对象
		AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
		// 设置Bean的类型
		beanDefinition.setBeanClass(MemberService.class);
		// 设置Bean的作用域
		beanDefinition.setScope("prototype");

		// 当然光这样申明还是不够的 , 我们需要调用一个函数来把这个beanDefinition注册到容器中 , 在注册的时候我们可以指定一个Bean的名称
		applicationContext.registerBeanDefinition("memberService" , beanDefinition);

		MemberService memberService = (MemberService) applicationContext.getBean("memberService");

		memberService.test();

	}
}

接着运行进行测试 , 会发现这次并没有报错 , 并且也打印出来了 “test方法被调用…”
其实不难理解 , 我们通过注解的方式去定义 , 当Spring扫描完解析的时候 , 他底层也会把解析的结果封装到BeanDefinition, 我们现在不通过注解申明的方式 , 而是直接编程式的把值封装到BeanDefinition中 , 然后注册到Spring容器 , 这样我们就可以使用了

BeanDefinitionReader

现在我们介绍几种BeanDefintion的几种读取器 , 虽然在工作中用的很少 , 但是 , 它也是Spring基础设施中比较重要的一部分

AnnotatedBeanDefinitionReader

可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,如下

public class TestSpring {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		// 把某一个类转换为BeanDefinition之后 , 我们也需要将它注册到Spring容器中 , 所以需要传一个ApplicationContext对象
		AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);

		// 注册到Spring容器中
		annotatedBeanDefinitionReader.register(MemberService.class);

		MemberService memberService = (MemberService) applicationContext.getBean("memberService");

		memberService.test();

	}
}

运行测试发现控制台打印 " test方法被调用…" , 我们可以简单看一下register()方法

	public void register(Class<?>... componentClasses) {
		for (Class<?> componentClass : componentClasses) {
			registerBean(componentClass);
		}
	}
	public void registerBean(Class<?> beanClass) {
		doRegisterBean(beanClass, null, null, null, null);
	}
	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(supplier);
		// 解析@Scope注解的结果为ScopeMetadata
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		// 将类的作用域添加到数据结构中
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

我们看一下processCommonDefinitionAnnotations()方法

	public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
		processCommonDefinitionAnnotations(abd, abd.getMetadata());
	}
	// 处理@Lazy、@Primary、@DependsOn、@Role、@Description
	static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
		if (lazy != null) {
			abd.setLazyInit(lazy.getBoolean("value"));
		}
		else if (abd.getMetadata() != metadata) {
			lazy = attributesFor(abd.getMetadata(), Lazy.class);
			if (lazy != null) {
				abd.setLazyInit(lazy.getBoolean("value"));
			}
		}

		if (metadata.isAnnotated(Primary.class.getName())) {
			abd.setPrimary(true);
		}
		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
		if (dependsOn != null) {
			abd.setDependsOn(dependsOn.getStringArray("value"));
		}

		AnnotationAttributes role = attributesFor(metadata, Role.class);
		if (role != null) {
			abd.setRole(role.getNumber("value").intValue());
		}
		AnnotationAttributes description = attributesFor(metadata, Description.class);
		if (description != null) {
			abd.setDescription(description.getString("value"));
		}
	}

可以看到 , 他底层的逻辑代码和我们刚刚用编程式定义的方式差不多 , 也是创建一个BeanDefintion对象 , 然后解析注解并设置BeanDefintion的值 , 那么这个AnnotatedBeanDefinitionReader读取器在什么时候用的呢?其实是在创建AnnotationConfigApplicationContext容器对象时候用的 , 我们点进去看一下它的构造方法

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
		this();
		// 注册bean配置类
		register(componentClasses);
		// 刷新上下文
		refresh();
	}

然后看this()方法

	public AnnotationConfigApplicationContext() {
		StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
		// 额外会创建StandardEnvironment
		this.reader = new AnnotatedBeanDefinitionReader(this);
		createAnnotatedBeanDefReader.end();
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

我们就可以看到它构造了一个AnnotatedBeanDefinitionReader对象 , 其实Spring容器本身也有register()方法

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		applicationContext.register();

其实它们使用的是同一个方法 , 看一看applicationContext.register()方法的源码

	@Override
	public void register(Class<?>... componentClasses) {
		Assert.notEmpty(componentClasses, "At least one component class must be specified");
		StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
				.tag("classes", () -> Arrays.toString(componentClasses));
		this.reader.register(componentClasses);
		registerComponentClass.end();
	}
	public void register(Class<?>... componentClasses) {
		for (Class<?> componentClass : componentClasses) {
			registerBean(componentClass);
		}
	}
	public void registerBean(Class<?> beanClass) {
		doRegisterBean(beanClass, null, null, null, null);
	}

可以看到, 它们最终调用的都是doRegisterBean()方法 , 都是会把传入的类转换为一个BeanDefintion

XmlBeanDefinitionReader

既然有解析类的读取器的 , 那么也就应该有解析xml标签的 , 它就是XmlBeanDefinitionReader , 如下
首先定义一个xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	   https://www.springframework.org/schema/beans/spring-beans.xsd
	   http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
	   >
	<bean id="member" class="com.lyh.service.MemberService"/>
</beans>

然后我们通过如下的方式来获取


public class TestSpring {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext); 
		
		xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
		
		MemberService memberService = (MemberService) applicationContext.getBean("memberService");

		memberService.test();

	}
}

ClassPathBeanDefinitionScanner

前面介绍的两个是读取器 , 现在来介绍一个BeanDefinition扫描器 , 读取器 , 读取类以及xml文件然后解析成为一个BeanDefintion , 那么扫描器, 那么就是读取某个包路径下的类 , 然后进行解析 ,比如,扫描到的类上如果存在@Component 注解,那么就会把这个类解析为一个BeanDefinition , 如下

申明一个ScannerService来测试

public class ScannerService {

	public void test(){
		System.out.println("执行了ScannerService.test()方法");
	}

}

取消AppConfig.class这个入参

public class TestSpring {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

		ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
		scannerService.test();

	}
}

这样运行肯定是报错的 , 即使在ScannerService类加上了@Component注解 , 因为这里没有传配置文件进去 , 所以构造的是一个空的Spring容器
报错信息如下:

Exception in thread “main” java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@433c675d has not been refreshed yet

在这里插入代码片

它提示我们这个容器还没有刷新一下 , 加一行代码来刷新一下

public class TestSpring {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
		applicationContext.refresh();

		ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
		scannerService.test();

	}
}

发现刷新之后还是报错 , 报错信息如下 :

Exception in thread “main” org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘scannerService’ available
没有一个名为scannerService的Bean用来使用

我们现在用这个扫描器试一下

public class TestSpring {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext);
		scanner.scan("com.lyh");

		ScannerService scannerService = (ScannerService) applicationContext.getBean("scannerService");
		scannerService.test();

	}
}

发现控制台打印了 “执行了ScannerService.test()方法” , 也就是说这个扫描器生效了 , 它扫描到了ScannerService并且这个类加了@Component , 就表示这个类需要注册为一个Bean , 就会把这个类解析并放入Spring容器 , 其实比较细心的话就可以发现ClassPathBeanDefinitionScanner这个类是在之前申明AnnotatedBeanDefinitionReader读取器的时候也申明了

	public AnnotationConfigApplicationContext() {
		StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
		// 额外会创建StandardEnvironment
		this.reader = new AnnotatedBeanDefinitionReader(this);
		createAnnotatedBeanDefReader.end();
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

所以这里我们就知道了 , 我们的Spring容器它既可以去注册某一个类成为Bean ,也可以去扫描 , 当然它的内部会进行扫描 , 我们自己触发也是可以的 , 所以AnnotationConfigApplicationContext 也是有这两个功能的 , 一个是直接注册 , 一个是扫描

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
		// 需要传入一个包路径
		applicationContext.scan();

BeanDefinition子类

上面我们说到 , BeanDefinition是一个接口 , 那么重要的实现类有这么三个 :
1.GenericBeanDefinition
2.AnnotatedGenericBeanDefinition
3.ScannedGenericBeanDefinition

它们之前的父子关系是这样的
在这里插入图片描述

AnnotatedGenericBeanDefinition和ScannedGenericBeanDefinition的区别

先来看ScannedGenericBeanDefinition , 它表示是扫描出来的BeanDefinition的类型
我们来看源码 , 从刚刚scan()的源码进去

scanner.scan(“com.lyh”);

	public int scan(String... basePackages) {
		int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

		doScan(basePackages);

		// Register annotation config processors, if necessary.
		if (this.includeAnnotationConfig) {
			AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
		}

		return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
	}

再来看doScan()

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {

			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());

				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}

				// 检查Spring容器中是否已经存在该beanName
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);

					// 注册
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

再来看findCandidateComponents()

	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
			return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
		}
		else {
			return scanCandidateComponents(basePackage);
		}
	}

再来看scanCandidateComponents()


	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			// 获取basePackage下所有的文件资源
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						// excludeFilters、includeFilters判断
						if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setSource(resource);

							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}

我们可以看到这样一行代码 :
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
就表示扫描出来的BeanDefinition类型是ScannedGenericBeanDefinition

再来看AnnotatedGenericBeanDefinition
我们还是进入到AnnotationConfigApplicationContext的构造方法

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
		this();
		// 注册bean配置类
		register(componentClasses);
		// 刷新上下文
		refresh();
	}

看register()方法

	@Override
	public void register(Class<?>... componentClasses) {
		Assert.notEmpty(componentClasses, "At least one component class must be specified");
		StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
				.tag("classes", () -> Arrays.toString(componentClasses));
		this.reader.register(componentClasses);
		registerComponentClass.end();
	}

再看 this.reader.register();

public void register(Class<?>... componentClasses) {
		for (Class<?> componentClass : componentClasses) {
			registerBean(componentClass);
		}
	}

再看registerBean()

	public void registerBean(Class<?> beanClass) {
		doRegisterBean(beanClass, null, null, null, null);
	}

再看doRegisterBean()

	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		abd.setInstanceSupplier(supplier);
		// 解析@Scope注解的结果为ScopeMetadata
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		// 将类的作用域添加到数据结构中
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

我们可以看到这样一行代码 :
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
就表示扫描并解析到的BeanDefinition类型是AnnotatedGenericBeanDefinition类型

我们简单理解 , 一个扫描器 ,一个读取器 , 最终得到的都是一个BeanDefinition对象 , 但是他是进行区分的

当然还有比较重要的两个BeanDefinition子类
1.RootBeanDefinition
2.ChildBeanDefinition
他们的父子关系是这样的
在这里插入图片描述

ChildBeanDefinition和RootBeanDefinition的区别

ChildBeanDefinition基本从Spring2.5开始就很少用了 , 都是用GenericBeanDefinition来代替
RootBeanDefinition 它是常用的 , 而且用的比较多 , 因为RootBeanDefinition和Bean的生命周期有关 , 所以我们后面来讲 , 它是和合并beanDefinition有关的 , 目前为止有这个合并beanDefinition的概念即可

BeanFactory

BeanFactory它是一个接口 , 表示Bean工厂 , 它的作用就是用来创建Bean对象的 , 我们一般常用的Bean工厂是ApplicationContext , 为什么说ApplicationContext 也是Bean工厂呢?
源码中它的类是这样定义的

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

而ListableBeanFactory, HierarchicalBeanFactory都继承了BeanFactory , 所以说ApplicationContext它其实就是一个Bean工厂 , 所以ApplicationContext 他肯定拥有BeanDactory的功能 , 那么ApplicationContext和BeanFactory有什么区别呢?

其实从源码我们不难看出 , 它还继承了一些其他的接口, 比如ApplicationEventPublisher事件发布器 ,
EnvironmentCapable获取环境变量等 , 这个是BeanFactory所没有的 ,它的功能也就比BeanFactory更强大一点

DefaultListableBeanFactory

上面说到解析为BeanDefintion之后会注册到Spring容器中 , 那么什么是容器? 其实在DefaultListableBeanFactory这个类中就有体现 , 源码中是这样定义的

	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

其实说白了它就是一个map , key就是Bean的名称 , value就是解析出来的Map ,当然 , 我们也可以把Spring容器理解为单例池 , 单例池就是一个Map , 它存的就是所有的单例Bean , key也是Bean的名称 , value是Bean的实例 , 源码是这样定义的

	// 单例池
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

是在我们在使用AnnotationConfigApplicationContext的时候就有用到这个类 , 我们需要知道的是 , 在加载构造方法之前 , 它会先加载父类的构造方法 , 而在父类的构造方法中就初始化一个DefaultListableBeanFactory , 其实我们的getBean()功能就是DefaultListableBeanFactory 实现的

	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}

DefaultListableBeanFactory的功能是非常强大的 , 支持很多功能,可以通过查看DefaultListableBeanFactory的类继承实现结构来看
在这里插入图片描述

Aliasregistry

Aliasregistry ,通过类图我们可以看到DefaultListableBeanFactory也是实现了Aliasregistry接口的 ,
而Aliasregistry接口提供的就是别名注册的功能 , 如果没有实现这个接口 , 就表示一个Bean只能有一个名称 ,但是实现了这个接口 , 我们就可以给这个Bean起一个别名

singletionBeanisgtry

singletionBeanisgtry , 它提供的就是单例Bean的功能

BeanDinfinitionRegistry

BeanDinfinitionRegistry , 实现了这个接口就可以有BeanDinfinition注册的功能

HierarchicalBeanFactory

HierarchicalBeanFactory , 它可以获取父Bean工厂 , 如果实现了这个接口 , 就表示这个Bean工厂是支持父子Bean工厂的 , 也就是说如果有两个Bean工厂 , 它们是父子Bean工厂 , 如果子Bean工厂get不到Bean , 那么我们就会从父工厂去get

ListableBeanFactory

ListableBeanFactory , 它可以根据Bean的名称判断是否包含BeanDefinition , 以及获取BeanDefinition的数量 , 获取所有BeanDefinition的名称也就是Bean的名称 , 比如还可以根据指定类型获取Bean的名称 , 其实这个类提供的也就是一个展示的功能 , Bean的名称 , 数量…等

AutowireCapableBeanFactory

AutowireCapableBeanFactor,是直接继承了BeanFactory,在BeanFactory的基础上,支持 在创建Bean的过程中能对Bean进行自动装配

ConfigurableBeanFactory

在HierarchicalBeanFactory和SingletonBeanRegistry的基础上, 添加了设置父BeanFactory、类加载器(表示可以指定某个类加载器进行类的加载)、设置 Spring EL表达式解析器(表示该BeanFactory可以解析EL表达式)、设置类型转化服务(表示 该BeanFactory可以进行类型转化)、可以添加BeanPostProcessor(表示该BeanFactory支持 Bean的后置处理器),可以合并BeanDefinition,可以销毁某个Bean等等功能

AbstractAutowireCapableBeanFactory

AbstractAutowireCapableBeanFactor, 继承了AbstractBeanFactory,实现了 AutowireCapableBeanFactory,拥有了自动装配的功能

对于这些接口 , 类不明白也没关系, 着重理解BeanFactory就行 , 其实这也可以充分的体会到Spring内部这种面向接口的思想 , 在以后的工作中 ,我们也可以模仿Spring这种面向接口的设计思想 , 每一个接口都是一个功能 , 如果想拥有这个功能 , 那我们实现这个接口就行

ApplicationContext

上面有分析到,ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory 更加强大,比如:

HierarchicalBeanFactory

拥有获取父BeanFactory的功能

ListableBeanFactory

拥有获取beanNames的功能

ResourcePatternResolver

资源加载器,可以一次性获取多个资源(文件资源等等)

public class TestSpring {

	public static void main(String[] args) throws IOException {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		Resource resource = applicationContext.getResource("file://E:\\studywork\\spring-framework-5.3.10\\spring-lyh\\src\\main\\java\\com\\lyh\\service\\UserService.java");
		System.out.println(resource.contentLength());
		System.out.println(resource.getFilename());

		Resource resource1 = applicationContext.getResource("https://www.baidu.com");
		System.out.println(resource1.contentLength());
		System.out.println(resource1.getURL());

		Resource resource2 = applicationContext.getResource("classpath:spring.xml");
		System.out.println(resource2.contentLength());
		System.out.println(resource2.getURL());

		String message = applicationContext.getMessage("test", null, new Locale("en"));
		System.out.println("message : " + message);
	}
}

还可以一次性获取多个

		Resource[] resources = applicationContext.getResources("classpath:com/lyh/*.class");
		for (Resource re : resources) {
			System.out.println(re.contentLength());
			System.out.println(re.getFilename());
		}

源码中是在扫描的时候用到的 , 这一块的源码之前有详细的入口 , 不清楚的可以在本篇文章中Ctrl+f搜一下这个方法 , 这个方法就会传入一个包路径 , 然后加载资源
在这里插入图片描述
在开发中我们可以这样使用

@Component
public class MemberService implements ApplicationContextAware {


	private ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	public void test1(){
		Resource resource = applicationContext.getResource("");
		System.out.println("test1方法被调用 resource " + resource);
	}
}

EnvironmentCapable

可以获取运行时环境(没有设置运行时环境功能)

public class TestSpring {

	public static void main(String[] args){

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		// 获取操作系统层面的环境变量
		Map<String, Object> systemEnvironment = applicationContext.getEnvironment().getSystemEnvironment();
		System.out.println(systemEnvironment);

		System.out.println("=======");

		// 获取通过-d的方式指定的配置文件
		Map<String, Object> systemProperties = applicationContext.getEnvironment().getSystemProperties();
		System.out.println(systemProperties);

		System.out.println("=======");

		// 获取通过注解指定的配置文件的值 : @PropertySource("classpath:spring.properties")
		MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
		System.out.println(propertySources);

		System.out.println("=======");
		
		// 也可以指定具体的值 操作系统
		System.out.println(applicationContext.getEnvironment().getProperty("NO_PROXY"));
		// 通过-d指定的参数
		System.out.println(applicationContext.getEnvironment().getProperty("sun.jnu.encoding"));
		// 获取spring.properties配置文件的内容
		System.out.println(applicationContext.getEnvironment().getProperty("lyh"));
	}
}

ApplicationEventPublisher

拥有广播事件的功能(没有添加事件监听器的功能)
首先在Appconfig定义一个事件发布器

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

在工作中我们也可以这样用

@Component
public class MemberService implements ApplicationContextAware {


	private ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	public void test(){
		String message = applicationContext.getMessage("test", null, new Locale("en"));
		System.out.println("test方法被调用 message为 " + message);
	}

	public void test1(){
		Resource resource = applicationContext.getResource("");
		System.out.println("test1方法被调用 resource " + resource);
	}

	public void test2(){
		applicationContext.publishEvent("kkk");
		System.out.println("test2方法被调用 发布了事件");
	}
	
}

当我们调用test2()方法时就会发布一个事件

MessageSource

拥有国际化功能
我们首先在resources下新建一个文件
右键resources --> new --> resource Bundle , 然后就会出来如下图所示的界面 , 我们首先定义一个名称 : message(名称随意) , 然后添加一个英语 , 点击确认

然后就会帮我们创建出两个文件
在这里插入图片描述
我们在两个文件中指定如下内容 , 内容随意
在这里插入图片描述
在AppConfig中定义一个MessageSource

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

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

public class TestSpring {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// en对应配置文件message_en的'en'
		String message = applicationContext.getMessage("test", null, new Locale("en"));
		System.out.println(message);

	}
}

但是我们在实际开发中肯定不是以这样的方式去获取国际化资源 , 那么应该怎么做呢?

@Component
public class MemberService implements ApplicationContextAware {


	private ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	public void test(){
		String message = applicationContext.getMessage("test", null, new Locale("en"));
		System.out.println("test方法被调用 message为 " + message);
	}
}

就像这样 , 我们实现一下ApplicationContextAware接口 , 这样不就想怎么用就怎么用了吗

关于ApplicationContext我们也有两个经常使用的具体的实现类

AnnotationConfigApplicationContext

在这里插入图片描述

ConfigurableApplicationContext

继承了ApplicationContext接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor、设置Environment,获取ConfigurableListableBeanFactory等功能

AbstractApplicationContext

实现了ConfigurableApplicationContext接口 , AbstractApplicationContext是Spring应用上下文中最重要的一个类,这个抽象类中提供了几乎ApplicationContext的所有操作。主要有容器工厂的处理,事件的发送广播,监听器添加,容器初始化操作refresh方法,然后就是bean的生成获取方法接口等。主要还是提供了一些方法,复杂的操作也是没有太多。

GenericApplicationContext

继承了AbstractApplicationContext,实现了BeanDefinitionRegistry接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition,注意这个类中有一个属性(DefaultListableBeanFactory beanFactory)

AnnotationConfigRegistry

可以单独注册某个为类为BeanDefinition(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描

AnnotationConfigApplicationContext

继承了GenericApplicationContext,实现了AnnotationConfigRegistry

AnnotationConfigRegistry

拥有了以上所有的功能

ClassPathXmlApplicationContext

在这里插入图片描述
它也是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition , 并且现在用AnnotationConfigApplicationContext比较多一点 , 所以ClassPathXmlApplicationContext就不着重说了

PropertyEditor

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

定义类型转换器

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("lyh")
		private User user;

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

	}

当我们使用/@Value(“lyh”)想为user赋值时 , Spring就会去看程序员有没有定义一个类型转换器 , 可以把String转换为user, 因为我们刚刚向容器注册了一个类型转换器, 那么user属性就能正常的完成属性赋值

ConversionService

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

public class StringToUserConverter implements ConditionalGenericConverter {

	@Override
	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
		// sourceType.getType() : 带转换的类型
		// targetType.getType(): 转换后类型
		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;
	}
}
public class TestSpring {

	public static void main(String[] args){

		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内部用的 , 因为我们在实际使用的时候可能会同时定义PropertyEditor和ConversionService , 所以Spring就用SimpleTypeConverter来把两种方式都添加进去

public class TestSpring {

	public static void main(String[] args){

		SimpleTypeConverter typeConverter = new SimpleTypeConverter();
		typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
		//typeConverter.setConversionService(conversionService);
		User value = typeConverter.convertIfNecessary("1", User.class);
		System.out.println(value);
	}
}

这个类型转换器在源码中是这样体现的

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		MemberService memberService =  applicationContext.getBean("memberService" , MemberService.class);
		System.out.println(memberService);

这样我们就不用强制转换了 , 我们来看看源码 , 我们进入到doGetBean()方法

	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name, requiredType);
	}

继续进入getBean() , 此时应该到了BeanFactory的getBean();

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

然后进入到AbstractBeanFactory的getBean();

	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		return doGetBean(name, requiredType, null, false);
	}

进入到doGetBean()即可

最后会看到
return adaptBeanInstance(name, beanInstance, requiredType);
在这里插入图片描述
它首先判断当前Bean的类型是否和给定的类型相符 , 如果不同 , 就会进行类型转换 , 能不能转的过来 , 就要看有没有定义上面的这些类型转换器 , 如果可以强转, 那么就返回 , 如果不可以强转, 那么就会报异常, 类型不符 , 如果没有指定 , 就直接返回

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 LyhFactoryBean 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生命周期的。而FactoryBean只是经过了初始化后这一步 , 因为虽然是以实现FactoryBean重写方法的方式定义的Bean , 但是不能把AOP这个功能给抛弃了

​它的源码也是在doGetBean() , 如下图 , 一定要注意transformedBeanName()这个方法 , 等等我们来讲用途
在这里插入图片描述
它会判断 , 如果没有实现FactoryBean ,会直接返回 , 否则进行处理
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
到这里 , 它就会执行getObject()方法 , 然后返回 , getObject()方法也就是你自己实现了FactoryBean接口所重写的方法

然后我们再来说第一张图片的transformedBeanName()方法 , 如果实现了FactoryBean , 那么这个类也是一个Bean ,那么我们想获取这个Bean怎么获取呢?就比如上面的例子 , 我想获取LyhFactoryBean , 怎么获取呢?

public class TestSpring {

	public static void main(String[] args){

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		// 返回getObject()方法返回的Bean
		UserService userService = (UserService)applicationContext.getBean("lyhFactoryBean");
		System.out.println(userService);
		// 返回LyhFactoryBean
		LyhFactoryBean lyhFactoryBean = (LyhFactoryBean)applicationContext.getBean("&lyhFactoryBean");
		System.out.println(lyhFactoryBean);

所以transformedBeanName()方法其实是针对这种情况做了处理

ExcludeFilter和IncludeFilter

这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器。

比如以下配置,表示扫描com.lyh这个包下面的所有类,但是排除UserService类,也就是就算它上面有
@Component注解也不会成为Bean。

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

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

@ComponentScan(value = "com.lyh",
  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);
  }
 }
}

那么有人会想 , 为什么不用反射呢?
其实SimpleMetadataReaderFactory类的功能是非常强大的 , 它可以获取接口的名称 , 获取内部类的名称 , 通过一个方法的直接调用就可以 , 但是用反射获取要写不少代码 , 对于这些类的API大家可以动手来试验一下 , 更容易理解

需要注意的是SimpleMetadataReader去解析类时,使用的ASM技术。

为什么要使用ASM技术

Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。

本篇文章到这里就结束了 , 介绍了Spring一些比较重要的常用的类的基本功能 , 概念, 在阅读Spring的源码中 , 我们可以知道个所以然 , 知道大概是干什么用的 , 这样会比较方便一点

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lingering fear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值