目录
我们只测试IOC容器,因此只需要引入spring-context即可
junit
junit
RELEASE
test
com.github.javafaker
javafaker
1.0.2
org.springframework
spring-context
RELEASE
/**
* 测试spring的ioc容器
*/
public class TestSpringIOC {
@Test
public void test(){
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("ioc/services.xml","ioc/daos.xml");
// retrieve configured instance
UserService service = context.getBean("userService", UserService.class);
// use configured instance
System.out.println();
System.out.println("测试注入-------------------------------------------------");
List userList = service.findUsers(20);
userList.stream().forEach(System.out::println);
AwareTestService awareTestService = (AwareTestService)context.getBean("awareTestService");
System.out.println();
System.out.println("测试Aware-------------------------------------------------");
awareTestService.test();
AwareTestService awareTestServiceAlias = (AwareTestService)context.getBean("awareTestServiceAlias");
System.out.println();
System.out.println("测试bean别名---------------------------------------------------");
System.out.println(awareTestServiceAlias == awareTestService);//true
}
}
测试用例里面引入了两个配置文件:services.xml和daos.xml,看看里面写了啥(引用到的类文末有代码清单)
初始化 before--实例化的bean对象之前:com.spring.dao.impl.UserDaoImpl@3cb1ffe6 userDao
初始化 after...实例化的bean对象之后:com.spring.dao.impl.UserDaoImpl@3cb1ffe6 userDao
初始化 before--实例化的bean对象之前:com.spring.service.impl.UserServiceImpl@43bd930a userService
初始化 after...实例化的bean对象之后:com.spring.service.impl.UserServiceImpl@43bd930a userService
初始化 before--实例化的bean对象之前:com.spring.service.impl.AwareTestServiceImpl@33723e30 awareTestService
初始化 after...实例化的bean对象之后:com.spring.service.impl.AwareTestServiceImpl@33723e30 awareTestService
测试注入-------------------------------------------------
User{name='范烨霖', age=17, phone='17647798623', location='瓦房店'}
User{name='尹擎苍', age=56, phone='17314101961', location='泸州'}
...
测试Aware-------------------------------------------------
Spring中的6大自动注入aware接口
true
...
测试bean别名---------------------------------------------------
true
xml文件里面配置了bean,那么Spring是怎么将这些bean初始化到IOC容器的呢?IOC容器具体是什么呢?
开局一张图
抽象的bean定义reader,不管你是从哪里读取,是从XML,还是注解读取,都提供统一的接口对外暴露读取bean定义的接口,单独抽象了这一层出来屏蔽掉XML或者注解读取
抽象应用上下文,应用了模板方法模式,下面简称应用上下文或上下文
抽象Bean工厂,运用模板方法模式,下面简称bean工厂或工厂
[图片上传失败…(image-87e039-1615555942316)]
当前容器运行的环境,里面包含了一些JDK的系统属性等等,可以通过实现EnvironmentAware接口拿到当前的容器环境
里面有一方法postProcessBeanFactory,顾名思义这是在工厂生产bean之前对工厂本身调用的回调函数,千万要和BeanPostProcessor区分开来
里面有俩方法postProcessBeforeInitialization和postProcessAfterInitialization,大腿想一想这应该是在bean初始化之前和初始化之后要调用的回调函数
用大腿想一下这玩意儿应该是注册事件用的,在容器初始化的不同阶段调回调函数
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml");
就这么一句话就初始化了Spring的IOC容器,怎么初始化的?
这方法
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
ClassPathXmlApplicationContext一看就是AbstractApplicationContext的子类,这里用了模板方法,其他的各种ApplicationContext公用AbstractApplicationContext中的通用方法,其他要自己实现的子类去实现即可 ,super(parent)这句话不断往父类调,调到AbstractApplicationContext为止,此时加载AbstractApplicationContext并且初始化其中的一些成员变量,比如容器ID,一些Map,一些锁之类的东西
题外话: AbstractApplicationContext中的一些锁是这么定义的,取名叫XXXmonitor,实际上就是个空对象,拿给容器启动关闭的时候配合syncronized使用,这也说明了java中的syncronized,锁的就是对象
/** Synchronization monitor for the "refresh" and "destroy". */
private final Object startupShutdownMonitor = new Object();
引入配置就这句话,接收classpath下面的xml文件路径
setConfigLocations(configLocations);
这句话没啥好说的就赋个值,需要注意的是里面初始化了容器环境,就下面这句话,是在AbstractApplicationContext定义的
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
重点来了,refresh是在AbstractApplicationContext中定义的,字面叫刷新,刷新啥?人家源码里面注释都说了:加载或者刷新可能从XML文件,properties文件,数据库等文件的配置并持久化,说白了就是根据配置实例化bean,这里面又有很多步骤,不是简简单单实例化三个字可以表述清楚的
源码在此,别人每句话都写上了注释,我们挨个来看
synchronized (this.startupShutdownMonitor) {
// 3.1 Prepare this context for refreshing.
prepareRefresh();
// 3.2 Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3.3 Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// 3.4 Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 3.5 Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// 3.6 Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 3.7 Initialize message source for this context.
initMessageSource();
// 3.8 Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 3.9 Initialize other special beans in specific context subclasses.
onRefresh();
// 3.10 Check for listener beans and register them.
registerListeners();
// 3.11 Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 3.12 Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
刷新之前的准备工作,准备啥?准备了容器启动时间,容器状态标志位的设置,初始化一些装事件监听器的容器,这些没啥说的,看源码就知道
注意:此处有一个回调函数,说的很清楚,准备的时候子类可以干点事情,干子类自己的事情,当然我们这个子类ClassPathXmlApplicationContext比较懒,它啥也没干
protected void initPropertySources() {
// For subclasses: do nothing by default.
}
这个是重点,重量级角色BeanFactory登上历史舞台,看注释:告诉子类让子类刷新内部的BeanFactory,啥意思?就是说这个BeanFactory你子类去实现,我(容器上下文)不管你子类new的啥工厂,反正你给我new好了,用的时候我调用模板方法你子类返回给我,我做一些公共的方法即可,这也是面向接口编程的好处,我不持有具体的引用
具体是那个类在new工厂?看下面
AbstractRefreshableApplicationContext.refreshBeanFactory()在new这个工厂,这个AbstractRefreshableApplicationContext是ClassPathXmlApplicationContext的父类,看到了吧,它就是一层包一层,一层实现一点点功能,然后组合嵌套起来实现大功能
...
DefaultListableBeanFactory beanFactory = createBeanFactory(); //new一工厂
beanFactory.setSerializationId(getId());//工厂的序列化id和上下文的id是一样的,getId()就是上下文的id
customizeBeanFactory(beanFactory);//
loadBeanDefinitions(beanFactory);//重点来了,此处才在通过XML文件读取成bean的定义
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
...
AbstractRefreshableApplicationContext#createBeanFactory()方法
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
我们可以看到new了一个DefaultListableBeanFactory工厂,loadBeanDefinitions将XML文件读取成bean定义,此时才真正开始读取XML文件,真正的读取是在XmlBeanDefinitionReader#doLoadBeanDefinitions和doRegisterBeanDefinitions方法中进行的,Spring中,凡是doXXX都是真正干活的方法,怎么读取的具体请看源码,大多都是一些很繁琐的细节,只要知道在这里读取就OK
配置工厂的标准上下文特征,例如上下文的类加载器和后处理器。这啥意思,就是说这个工厂我现在要准备在上下文用了,你给我初始化一些东西,初始化啥?就是把spring的一些内部对象给放到了bean工厂里面,可见,上下文需要的一些bean也是放在bean工厂里面的
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
看一下DefaultListableBeanFactory这个bean工厂的源码,里面一堆一堆的map,map用来干啥?用来注册一堆一堆不同类型的bean,具体你看每个map上面的注释,大概就能猜到它是干啥用的
总之,这个方法完善了bean工厂,给bean工厂放入了一些自己需要的资源,我们来看下DefaultListableBeanFactory里面都有些啥成员变量
//TODO
预处理什么?谁来预处理?,这就是个空方法,留给具体的上下文实现,注释写的很清楚,这是留给具体上下文即子类来实现的,代码运行到这里
说明bean工厂已经初始化好了,但是还没有实例化bean,子类可以在这里注册一些特殊的BeanPostProcessors
所以预处理什么? 抽象上下文的子类想对bean工厂做点什么你可以做,做啥你子类自己应该知道
谁来预处理?当然是抽象上下文的子类来做,当然ClassPathXmlApplicationContext比较懒,他啥也没做
什么叫调用bean工厂的处理?就是说在bean工厂配置好后,bean实例化之前对bean工厂本身要做的一些配置,就在这里进行,你可以看到一堆一堆的Processors,Processors顾名思义就是处理器嘛
看下抽象上下文的addBeanFactoryPostProcessor方法,就是往抽象上下文里面不断装BeanFactoryPostProcessor,当然你也可以拿到抽象上下文实例去往里面装自己的BeanFactoryPostProcessor,明白了么。框架的东西就是到处给提供了很多扩展,你可以往里面加自己的逻辑处理
这是抽象上下文里面进行处理的,看看具体处理了啥,目标方法为PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());,这就是个静态方法嘛,你可以理解成工具方法
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
//对BeanDefinitionRegistry做了个特殊处理
if (beanFactory instanceof BeanDefinitionRegistry) {
...
} else {
// Invoke factory processors registered with the context instance.
//对于已经注册了的BeanFactoryPostProcessors,挨个开始应用
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List priorityOrderedPostProcessors = new ArrayList<>();
List orderedPostProcessorNames = new ArrayList<>();
List nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
仔细看看上面的源码,都有注释的,沉下心去看是个人肯定能看懂的:
顾名思义,注册BeanPostProcessors,大胆猜想一些,就是把BeanPostProcessors放到bean工厂的map里面去,注意这里是在注册,而不是执行,看方法前面都有个register
BeanPostProcessors是啥,看它接口的定义,俩方法:postProcessBeforeInitialization、postProcessAfterInitialization,一个是在bean被初始化之前调用,一个是在bean初始化之后调用,说白了就是回调函数,一定要和BeanFactoryPostProcessors区分开来,前者是针对bean的,后者是针对bean工厂的,名字里面都有个Factory嘛,已经很明显了
就一句话PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);,里面的逻辑和invokeBeanFactoryPostProcessors差不多,也是把processors分为了带优先级的,带顺序的和不带顺序的,还有一种叫做内部的,把这几种放入bean工厂的map里面,再次强调,此时只是注册,还没有开始执行!!!
其实,BeanPostProcessors运用了责任链的设计模式。重写自己的processors参考代码MyBeanPostProcessor,然后在xml文件里面注册这个bean,当然不注册也可以手动在context里面添加,不管怎么样只要能放到bean工厂里面的map就行了
多说一句:
啥消息源?这是spring为了支持国际化,具体参考https://blog.csdn.net/SLN2432713617/article/details/94592813
怎么去初始化?有就不管,没有就创建一个嘛,刚开始明显没有,所以创建了一个SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster是个啥?就是一个事件广播器,啥叫广播器?就是广播一个事件,所有的监听器都去响应这个事件,监听器就是ApplicationListener,注册监听器就是registerListeners做的事情
这又是一个回调方法,前面有一个postProcessBeanFactory也是拿给子类回调的,不细说了
注册监听器,不是注册给上下文,是注册给广播器,getApplicationEventMulticaster拿到的就是事件广播器,是在initApplicationEventMulticaster中初始化的,说白了就是放在了事件广播器的map里面
也就是说,有事件产生的时候,广播器挨个通知所有的监听器,让他们执行相应的动作,怎么通知?一个for循环挨个执行下就好了
上面铺垫了这么久,现在终于可以开始初始化所有bean了,再次强调,是初始化所有非懒加载!!的bean,用递归的来初始化bean以及bean里面的依赖!
核心是反射,里面有一堆一堆的判断条件,还有条件很深的递归,跟代码很容易就晕了,下面演示了空构造方法,里面依赖有一个bean的实例化,即userService,userService里面依赖了userDao
完成刷新,此处有处理器回调和事件回调
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
比如,可以做一些在容器刷新完成后的事件:参考ContextRefreshApplicationListener.java
这个就没啥好说的,不用的东西清理掉而已
protected void resetCommonCaches() {
ReflectionUtils.clearCache();
AnnotationUtils.clearCache();
ResolvableType.clearCache();
CachedIntrospectionResults.clearClassLoader(getClassLoader());
}
最简单的办法就是写一个BeanPostProcessor打断点观察调用堆栈,参考com.spring.config.MyBeanPostProcessor
postProcessBeforeInitialization:10, MyBeanPostProcessor
applyBeanPostProcessorsBeforeInitialization:416, AbstractAutowireCapableBeanFactory
initializeBean:1788, AbstractAutowireCapableBeanFactory
doCreateBean:595, AbstractAutowireCapableBeanFactory
createBean:517, AbstractAutowireCapableBeanFactory
lambda$doGetBean$0:323, AbstractBeanFactory
getObject:-1, 690339675
getSingleton:226, DefaultSingletonBeanRegistry
doGetBean:321, AbstractBeanFactory
getBean:202, AbstractBeanFactory
preInstantiateSingletons:895, DefaultListableBeanFactory
finishBeanFactoryInitialization:878, AbstractApplicationContext
refresh:550, AbstractApplicationContext
postProcessAfterInitialization:17, MyBeanPostProcessor
applyBeanPostProcessorsAfterInitialization:431, AbstractAutowireCapableBeanFactory
initializeBean:1800, AbstractAutowireCapableBeanFactory
doCreateBean:595, AbstractAutowireCapableBeanFactory
createBean:517, AbstractAutowireCapableBeanFactory
lambda$doGetBean$0:323, AbstractBeanFactory
getObject:-1, 690339675
getSingleton:226, DefaultSingletonBeanRegistry
doGetBean:321, AbstractBeanFactory
getBean:202, AbstractBeanFactory
preInstantiateSingletons:895, DefaultListableBeanFactory
finishBeanFactoryInitialization:878, AbstractApplicationContext
refresh:550, AbstractApplicationContext
通过观察堆栈,最后的公共调用堆栈为AbstractAutowireCapableBeanFactory.initializeBean,拿出来看看长啥样
看到了吧,在调用invokeInitMethods之前调用applyBeanPostProcessorsBeforeInitialization,之后调用applyBeanPostProcessorsAfterInitialization
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
...
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {...}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
...
return wrappedBean;
}
需要注意的是,如果A依赖B,那么B的postProcessBeforeInitialization和postProcessAfterInitialization会先调用,然后B创建并返回,此时A的Before…和After…才会调用,也就是说,从最深层开始调用
初始化bean工厂 > 通过BeanDefinitionReader从不同的来源读取配置文件 > 执行针对bean工厂本身的BeanFactoryPostProcessor > 通过反射递归实例化bean(过程中调用BeanPostProcessor) > 建立整个应用上下文 > 一些后续工作(清除缓存,发布事件之类)
所谓IOC容器,其实就是一个Map
/** Cache of singleton objects: bean name --> bean instance */
private final Map singletonObjects = new ConcurrentHashMap(64);
public interface UserDao {
List findUsers(int howMany);
}
public class UserDaoImpl implements UserDao {
@Override
public List findUsers(int howMany) {
List list = new ArrayList<>();
Faker faker = new Faker(new Locale("zh-CN"));
for (int i = 0; i < howMany; i++) {
User user = new User();
user.setName(faker.name().fullName());
user.setAge(faker.number().numberBetween(0,100));
user.setPhone(faker.phoneNumber().cellPhone());
user.setLocation(faker.address().city());
list.add(user);
}
return list;
}
}
public interface UserService {
List findUsers();
List findUsers(int howMany);
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
/*如果是配置文件注入要使用setter*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public List findUsers() {
return userDao.findUsers(10);
}
@Override
public List findUsers(int howMany) {
return userDao.findUsers(howMany);
}
}
public interface AwareTestService extends EnvironmentAware, EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware,ApplicationContextAware {
void test();
}
/**
* spring框架提供了多个*Aware接口,用于辅助Spring Bean编程访问Spring容器。
* 通过实现这些接口,可以增强Spring Bean的功能,将一些特殊的spring内部bean暴露给业务应用。
*
*/
public class AwareTestServiceImpl implements AwareTestService {
ApplicationContext applicationContext;
ApplicationEventPublisher applicationEventPublisher;
StringValueResolver stringValueResolver;
Environment environment;
MessageSource messageSource;
ResourceLoader resourceLoader;
public void test(){
System.out.println("Spring中的6大自动注入aware接口");
System.out.println(this.applicationContext.containsBean("awareTestService"));
System.out.println(this.environment.getProperty("java.home"));
System.out.println(this.stringValueResolver.resolveStringValue("${java.runtime.version}"));
System.out.println(this.resourceLoader.getResource("classpath:src/main/resources/ioc/services.xml"));
System.out.println(this.applicationEventPublisher);
System.out.println(this.messageSource.getMessage("Message", null, "not exist", Locale.JAPAN));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.stringValueResolver = resolver;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化 before--实例化的bean对象之前:"+bean+"\t"+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化 after...实例化的bean对象之后:"+bean+"\t"+beanName);
return bean;
}
}
public class User {
private String name;
private int age;
private String phone;
private String location;
...
}