Создание не простое, пожалуйста, указывайте автора в начале перепечатки: Nuggets@小西子 + ссылка на источник~
Если вы хотите узнать больше об исходном коде Spring,Нажмите, чтобы перейти к остальной части построчного анализа серии Spring
Введение
Думал об этом в эти дниbean
Как должен быть написан жизненный цикл, потому что процесс этой части действительно долгий и включает в себя многоbeanPostProcessor
Скрытые точки, многие из наших общих функций выполняются через эти спрятанные точки.
В итоге я решил начать с поста в блоге,bean
Об основном процессе жизненного цикла говорить довольно грубо (относительно). После этого, через серию сообщений в блоге, некоторые подробности основного процесса и то, как передаются некоторые общие функции.spring
СдержанныйbeanPostProcessor
Похоронен для достижения. Заинтересованные студенты могут выбрать просмотр самостоятельно.
(Из-за ограничения Nuggets на количество слов в статье, этот пост в блоге был вынужден разделить на две части:Нажмите, чтобы перейти к следующей статье)
два,Spring
Запуск контейнера
Я обнаружил, что до сих пор эта серия моихspring
Сообщение в блоге, я не говорил об этом хорошо.spring
Процесс запуска контейнера (тоже прямо приведен в первой статье)refresh
метод). Так же, как класс запуска с чистыми аннотациями, упомянутый в предыдущей статье.AnnotationConfigApplicationContext
, здесь мы снова рассматриваем:
@Test
public void test() {
// 我们平常使用AnnotationConfigApplicationContext的时候,只需要这样直接new出来就好了
applicationContext = new AnnotationConfigApplicationContext("com.xiaoxizi.spring");
// 然后就可以从容器中拿到bean对象了,说明其实new创建对象的时候,我们容器就做好启动初始化工作了~
MyAnnoClass myAnnoClass = applicationContext.getBean(MyAnnoClass.class);
System.out.println(myAnnoClass);
}
// AnnotationConfigApplicationContext的构造器
public AnnotationConfigApplicationContext(String... basePackages) {
this();
// 扫描目标包,收集并注册beanDefinition,上一篇具体讲过,这里就不赘述了
scan(basePackages);
// 这里就调用到我们大名鼎鼎的refresh方法啦
refresh();
}
Давайте посмотрим на основной метод запуска этого контейнера.refresh
, логика этого метода вAbstractApplicationContext
В классе это тоже типичный шаблонный метод:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 一些准备工作,主要是一下状态的设置事件容器的初始化
prepareRefresh();
// 获取一个beanFactory,这个方法里面调用了一个抽象的refreshBeanFactory方法
// 我们的xml就是在这个入口里解析的,具体的流程有在之前的博文分析过
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 把拿到的beanFactory做一些准备,这里其实没啥逻辑,同学们感兴趣的可以看下
// 但是这个方法也是一个protected的方法,
// 也就是说我们如果实现自己的spring启动类/或者spring团队需要写一个新的spring启动类的时候
// 是可以在beanFactory获取之后做一些事情的,算是一个钩子
prepareBeanFactory(beanFactory);
try {
// 这也是一个钩子,在处理beanFactory前允许子类做一些事情
postProcessBeanFactory(beanFactory);
// 实例化并且调用factoryPostProcessor的方法,
// 我们@Compoment等注解的收集处理主要就是在这里做的
// 有一个ConfigurationClassPostProcessor专门用来做这些注解支撑的工作
// 这里的逻辑之前也讲过了
// 那么其实我们可以说,到这里为止,我们的beanDefinition的收集(注解/xml/其他来源...)
// 、注册(注册到beanFactory的beanDefinitionMap、beanDefinitionNames)容器
// 工作基本就全部完成了
invokeBeanFactoryPostProcessors(beanFactory);
// 从这里开始,我们就要专注bean的实例化了
// 所以我们需要先实例化并注册所有的beanPostProcessor
// 因为beanPostProcessor主要就是在bean实例化过程中,做一些附加操作的(埋点)
// 这里的流程也不再讲了,感兴趣的同学可以自己看一下,
// 这个流程基本跟FactoryPostProcessor的初始化是一样的,
// 排序,创建实例,然后放入一个list --> AbstractBeanFactory#beanPostProcessors
registerBeanPostProcessors(beanFactory);
// 初始化一些国际化相关的组件,这一块我没有去详细了解过(主要是暂时用不到...)
// 之后如果有时间也可以单独拉个博文来讲吧
initMessageSource();
// 初始化事件多播器,本篇不讲
initApplicationEventMulticaster();
// 也是个钩子方法,给子类创建一下特殊的bean
onRefresh();
// 注册事件监听器,本篇不讲
registerListeners();
// !!!实例化所有的、非懒加载的单例bean
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 初始化结束,清理资源,发送事件
finishRefresh();
}
catch (BeansException ex) {
// 销毁已经注册的单例bean
destroyBeans();
// 修改容器状态
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();
}
}
}
Грубо говоря, мыspring
Запуск контейнера в основном предназначен для размещения этих нелениво загруженных синглетонов.bean
Создавайте экземпляры и управляйте ими.
три,bean
создавать экземпляр
1. Какойbean
Нужно создавать экземпляр при запуске?
простоrefresh
метод, мы виделиfinishBeanFactoryInitialization
метод используется для создания экземпляраbean
, и английский язык в исходном коде также объясняет, что он должен быть инстанцирован, поэтому оставшиеся нелениво загруженные синглтоныbean
, это действительно так? Давайте посмотрим на исходный код:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// skip .. 我把前面的非主流程的跳过了
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
// DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
// 我们之前注册beanDefinition的时候,有把所有的beanName收集到这个beanDefinitionNames容器
// 这里我们就用到了
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 循环所有的已注册的beanName
for (String beanName : beanNames) {
// 获取合并后的beanDefinition,简单来讲,我们的beanDefinition是可以存在继承关系的
// 比如xml配置从的parent属性,这种时候,我们需要结合父子beanDefinition的属性,生成一个新的
// 合并的beanDefinition,子beanDefinition中的属性会覆盖父beanDefinition的属性,
// 并且这是一个递归的过程(父还可以有父),不过这个功能用的实在不多,就不展开了,
// 同学们有兴趣可以自行看一下,这里可以就理解为拿到对应的beanDefinition就好了
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象(xml有一个abstract属性,而不是说这个类不是一个抽象类)、单例的、非懒加载的才需要实例化
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 这里是处理factoryBean的,暂时不讲,之后再专门写博文
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// !!!我们正常普通的bean会走到这个流程,这里就把这个bean实例化并且管理起来的
// 这里是获取一个bean,如果获取不到,则创建一个
getBean(beanName);
}
}
}
// 所以的bean实例化之后,还会有一些处理
for (String beanName : beanNames) {
// 获取到这个bean实例
Object singletonInstance = getSingleton(beanName);
// 如果bean实现了SmartInitializingSingleton接口
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// 会调用它的afterSingletonsInstantiated方法
// 这是最外层的一个钩子了,平常其实用的不多
// 不过@Listener的发现是在这里做的
smartSingleton.afterSingletonsInstantiated();
}
}
}
Как видите, это былонеабстрактный(xml
существует одинabstract
свойства, а не говорить, что класс не является абстрактным классом),синглтон,не ленивая загрузкаизbean
буду тамspring
Создается при запуске контейнера,spring
Чувак, твой комментарий неверен.Интересно подбирать слова) ~
2. ИспользуйтеgetBean
отbeanFactory
Получатьbean
Просто сказал, звони.getBean
Когда метод пора, я попробую его первым.spring
получить это в контейнереbean
, если вы не можете его получить, вы создадите его Теперь давайте разберемся с процессом:
public Object getBean(String name) throws BeansException {
// 调用了doGetBean
// 说一下这种方式吧,其实我们能在很多框架代码里看到这种方式
// 就是会有一个参数最全的,可以最灵活使用的方法,用来处理我们的业务
// 然后会对不同的使用方,提供一些便于使用的类似于门面的方法,这些方法会简化一些参数,使用默认值填充
// 或者实际业务可以很灵活,但是不打算完全开放给使用方的时候,也可以使用类似的模式
return doGetBean(name, null, null, false);
}
getBean->doGetBean
Это мыbeanFactory
Доступ извнеbean
Интерфейс просто говорит, что мы инициализируемspring
Когда контейнер используется, он будет использоваться для всех синглетонов.beanDefinition
перечислитьgetBean
методы создают экземпляры тех, которые они определяютbean
Вот и все, так что его логика не только дляspring
Контейнерное начальное определение, нам также нужно сделать это мышление, чтобы посмотреть на этот метод:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 转换一下beanName,暂时不看,之后统一讲
final String beanName = transformedBeanName(name);
Object bean;
// 看一下这个bean是否已经实例化了,如果实例化了这里能直接拿到
// 这个方法涉及到spring bean的3级缓存,之后会开一篇博客细讲
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 通过这个bean实例获取用户真正需要的bean实例
// 有点绕,其实这里主要是处理当前bean实现了FactoryBean接口的情况的
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 当前线程下的,循环依赖检测,如果当前bean已经在创建中,这里又进来创建了,说明是循环依赖了
// 会直接报错,代码逻辑也很简单,这里主要是一个TheadLocal持有了一个set,
// 可以认为是一个快速失败检测,和后面的全局循环依赖检测不是一个容器
// 容器是 prototypesCurrentlyInCreation
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 如果父容器不为空且当前容器没有这个beanName对应的beanDefinition
// 则尝试从父容器获取(因为当期容器已经确定没有了)
// 下面就是调用父容器的getBean了
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// 如果不是只检测类型是否匹配的话,这里要标记bean已创建(因为马上就要开始创建了)
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 拿到这个bean的所有依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// 如果依赖不为空,需要先循环实例化依赖
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(...);
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(...);
}
}
}
// 这里开始真正创建bean实例的流程了
if (mbd.isSingleton()) {
// 如果是单例的bean(当然我们启动的时候会实例化的也就是单例bean了),这里会进行创建
// 注意这里也是一个getSingleton方法,跟之前那个getSingleton方法差不多,不过这里是
// 如果获取不到就会使用这个lamdba的逻辑创建一个,
// 也就是说我的的createBean方法是真正创建bean实例的方法,这里我们之后会重点看
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 通过这个bean实例获取用户真正需要的bean实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// 如果是多例的bean
// 那么每次获取都是创建一个新的bean实例
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
// 可以看到这里直接去调用createBean了
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
// 这里逻辑还是一样的
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// spring是允许我们自定义scope的,这里是自定义scope的逻辑
// 需要注意的是,spring mvc 的 session、request那些scope也是走这里的逻辑的
// 这里感兴趣的同学可以自行看下,暂时不讲
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException(...);
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(...);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 这里是类型转换的逻辑,getBean是有可以传类型的重载方法的
// 不过我们初始化的时候不会走到这个逻辑来,感兴趣的同学可以自行看
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(...);
}
return convertedBean;
}
catch (TypeMismatchException ex) {
throw new BeanNotOfRequiredTypeException(...);
}
}
// 返回获取到的bean
return (T) bean;
}
Перейдем к синглтонуbean
Логика создания , а именно:
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ...
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
давайте посмотрим на этоgetSingleton
метод, следует отметить, что этот метод находится вDefaultSingletonBeanRegistry
В классе:
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 可以看到,我们先从singletonObjects通过beanName获取实例
// 这是不是说明singletonObjects就是spring用来存放所以单例bean的容器呢?可以说是的。
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 跳过了一个spring单例bean容器状态判断,
// 如果spring单例bean容器正在销毁时不允许继续创建单例bean的
// 创建容器之前的钩子,这里默认会把bean那么加入到一个正在创建的beanNameSet,
// 如果加入失败就代表是循环依赖了。
// 检测容器是 singletonsCurrentlyInCreation
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 这里就是调用传进来的lamdba了
// 也就是调用了createBean创建了bean实例
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 从正在创建的beanNameSet移除
afterSingletonCreation(beanName);
}
// 如果成功创建了bean实例,需要加入singletonObjects容器
// 这样下次再获取就能直接中容器中拿了
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
Как видите, этоgetSingleton
Путь заключается в том, чтобы начать сsingletonObjects
Получатьbean
Например, создайте его, если вы не можете его получить, и добавьте к нему некоторую циклическую логику обнаружения зависимостей.
3. createBean
,действительноbean
логика инициализации
мы говоримcreateBean
метод реальныйbean
Логика инициализации, но эта инициализация не только о создании экземпляра, но также включает в себя некоторую проверку, а также логику, такую как инъекция зависимости в классе, вызовы метода инициализации и т. Д. Давайте кратко посмотрим:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
// 获取bean的类型
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
// 这里对beanDefinition中的MethodOverrides做一些准备
// 主要是梳理一下所有重写方法(xml<replaced-method><lockup-method>标签对应的属性)
// 看下这些方法是否是真的有重载方法,没有重载的话会设置overloaded=false,
// 毕竟有些人配置的时候即使没有重载方法也会使用<replaced-method>标签
// (这功能我确实也没用过。。
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(...);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 给BeanPostProcessors一个机会,在我们的bean实例化之前返回一个代理对象,即完全不走spring的实例化逻辑
// 也是个BeanPostProcessors的钩子,就是循环beanPostProcessors然后调用的逻辑
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(...);
}
try {
// 这里是spring真正bean实例化的地方了
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
// 获取到了直接返回
return beanInstance;
}
// 跳过异常处理
}
3.0. doCreateBean
как создать экземплярbean
из?
только сказал,doCreateBean
Это мыspring
реальное воплощениеbean
Логика, тогда давайте посмотрим:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 调用一个BeanPostProcessor的钩子方法,这里调用的是
// MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
// 这个钩子方法是在bean实例创建之后,依赖注入之前调用的,需要注意的是
// @Autowired和@Value注解的信息收集-AutowiredAnnotationBeanPostProcessor
// @PostConstruct、@PreDestroy注解信息收集-CommonAnnotationBeanPostProcessor
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(...);
}
mbd.postProcessed = true;
}
}
// 这一部分是使用3级缓存来解决循环依赖问题的,之后再看
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 加入三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 依赖注入
populateBean(beanName, mbd, instanceWrapper);
// bean初始化-主要是调用一下初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(...);
}
}
// 这里也算是循环依赖检测的,暂时不讲
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(...);
}
}
}
}
try {
// 如果是单例bean,还会注册销毁事件
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(...);
}
return exposedObject;
}
Как видите, нашdoCreateBean
Примерно сделал 5 вещей:
- Создайте
bean
пример - перечислить
beanPostProcessor
метод захоронения - В зависимости от класса тока впрыска
bean
- Тока вызова
bean
метод инициализации - зарегистрировать текущий
bean
логика разрушения
Далее мы подробно рассмотрим эти процессы.
3.1. createBeanInstance
Создайтеbean
пример
Как вы обычно создаете экземпляр класса? это использовать конструктор напрямуюnew
выйти с одним? Или использовать фабричный метод, чтобы получить его?
очевидно,spring
Он также поддерживает эти два метода.Если учащиеся помнят синтаксический анализ тегов бобов, они также должны помнитьspring
В дополнение к созданию экземпляра с помощью конструктораbean
изconstructor-arg
Off-label, он также обеспечиваетfactory-bean
иfactory-method
свойства для настройки с использованием фабричных методов для создания экземпляровbean
.
и сказал раньшеConfigurationClassPostProcessor
когда мы говорим о@bean
При маркировке я также увидел, что для@bean
Обработка ярлыка, это новыйbeanDefinition
и поставьте текущий класс конфигурации и@Bean
Модифицированные методы запихиваются в этоbeanDefinition
изfactoryBeanName
иfactoryMethodName
Атрибуты (могут быть в воздухеConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
).
Далее давайте посмотримcreateBeanInstance
Код:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 校验
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 如果beanDefinition里有instanceSupplier,直接通过instanceSupplier拿就行了
// 这种情况我们就不重点讲了,其实跟工厂方法的方式也差不多
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 如果工厂方法不为空,就使用工厂方法实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 这里是对非单例bean做的优化,如果创建过一次了,
// spring会把相应的构造器或者工厂方法存到resolvedConstructorOrFactoryMethod字段
// 这样再次创建这个类的实例的时候就可以直接使用resolvedConstructorOrFactoryMethod创建了
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// 如果beanDefinition没有构造器信息,则通过beanPostProcessor选择一个
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 1.如果通过beanPostProcessor找到了合适的构造器
// 2.或者autowireMode==AUTOWIRE_CONSTRUCTOR(这个xml配置的时候也可以指定的)
// 3.或者有配置构造器的参数(xml配置constructor-arg标签)
// 4.获取实例化bean是直接传进来了参数
// 只要符合上面四种情况之一,我们就会通过autowireConstructor方法来实例化这个bean
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 需要构造器方式注入的bean的实例化
return autowireConstructor(beanName, mbd, ctors, args);
}
// 这里主要逻辑是兼容kotlin的,我们暂时不看
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 需要构造器方式注入的bean的实例化
return autowireConstructor(beanName, mbd, ctors, null);
}
// 不需要特殊处理的话,就直接使用无参构造器了
return instantiateBean(beanName, mbd);
}
конкретныйinstantiateUsingFactoryMethod
,autowireConstructo
Я не буду показывать вам метод здесь, потому что логика внедрения некоторых параметров более сложная, и я открою отдельный блог позже.
Фактически, после получения конкретных параметров, будь то создание конструктора или фабричный метод, это очень ясно, просто отразите вызов напрямую.
instantiateBean
Это логика получения конструктора без параметров, а затем его отражения и создания экземпляра.Логика относительно проста, и я не буду следовать ей здесь.
3.1.1. ПрохождениеdetermineConstructorsFromBeanPostProcessors
Конструктор методов
Это в основном, чтобы привести всех.determineConstructorsFromBeanPostProcessors
Этот метод, потому что большинство из нас теперь используют аннотации для объявленияbean
Да, и если вы также используете конструктор для внедрения при использовании аннотаций, то этот метод используется для получения соответствующего конструктора.
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
// 一旦拿到构造器就返回了
return ctors;
}
}
}
}
return null;
}
можно увидеть, черезbeanPostProcessor
Погребенная точка, чтобы сделать это, вот вызовSmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
, тут продавать не буду, мы реально поддерживаем метод аннотации, и логика выбора конструктора вAutowiredAnnotationBeanPostProcessor
В середине, вы чувствуете, что этот класс кажется немного знакомым?
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// ...
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// ...
}
Также звонитеAnnotationConfigUtils#registerAnnotationConfigProcessors
В методе есть инъекция ~
Как видно из названия, этоbeanPostProcessor
следует использовать для обработки@Autowired
Аннотация, хотят сказать некоторые студенты, это не аннотация внедрения свойств, какое отношение она имеет к конструктору? Затем у нас есть bean-компонент, внедренный конструктором в качестве примера:
@Service
public class ConstructorAutowiredBean {
private Student student;
@Autowired
public ConstructorAutowiredBean(Student student) {
this.student = student;
}
}
Большинство студентов, возможно, забыли,@Autowired
Его можно использовать для модификации конструктора,@Autowired
Параметры декорированного конструктора также будутspring
Получается из контейнера (может быть, это будет не совсем точно, все понимают о чем я, то есть смысл внедрения конструктора...).
Однако на самом деле мы обычно не попадаем, даже если используем внедрение конструктора.@Autowired
Аннотация тоже хороша, это на самом делеAutowiredAnnotationBeanPostProcessor
Отказоустойчивая логика при получении конструктора, посмотрим код вместе:
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
throws BeanCreationException {
// 整个方法分为了两个部分
// 第一部分是收集这个类上被@Lookup修饰的方法
// 这个注解的功能和我们xml的lookup-method标签是一样的
// 而收集部分也是一样的封装到了一个MethodOverride并且加入到beanDefinition里面去了
// 虽然这部分工作(@Lookup注解的收集工作)是应该放在bean创建之前(有MethodOverride的话会直接生成代理实例)
// 但是放在当前这个determineCandidateConstructors方法里我还是觉得不太合适
// 毕竟跟方法名的语意不符,不过好像确实没有其它合适的钩子了,可能也只能放这了
if (!this.lookupMethodsChecked.contains(beanName)) {
if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
try {
Class<?> targetClass = beanClass;
do {
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 循环处理所有的方法,获取@Lookup注解并封装信息
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
LookupOverride override = new LookupOverride(method, lookup.value());
try {
RootBeanDefinition mbd = (RootBeanDefinition)
this.beanFactory.getMergedBeanDefinition(beanName);
mbd.getMethodOverrides().addOverride(override);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(...);
}
}
});
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(...);
}
}
this.lookupMethodsChecked.add(beanName);
}
// 这里开始是选择构造器的逻辑了
// 先从缓存拿...这些也是为非单例bean设计的,这样就不用每次进来都走选择构造器的逻辑了
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
// 获取当前类的所有的构造器
rawCandidates = beanClass.getDeclaredConstructors();
}
catch (Throwable ex) {
throw new BeanCreationException(...);
}
// 这个列表存符合条件的构造器
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
Constructor<?> requiredConstructor = null;
Constructor<?> defaultConstructor = null;
// 这个primaryConstructor我们不管,是兼容kotlin的逻辑
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;
for (Constructor<?> candidate : rawCandidates) {
// 循环每个构造器
if (!candidate.isSynthetic()) {
// 这个判断是判断不是合成的构造器,同学们想了解这个Synthetic可以自行查一下
// 这边就不展开了,这个主意是和内部类有关,Synthetic的构造器是编译器自行生成的
nonSyntheticConstructors++;
}
else if (primaryConstructor != null) {
continue;
}
// 找一下构造器上有没有目标注解,说白了就是找@Autowired注解
MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
if (ann == null) {
// 如果找不到,这里认为可能是因为当前这个class是spring生成的cglib代理类
// 所以这里尝试拿一下用户的class
Class<?> userClass = ClassUtils.getUserClass(beanClass);
// 如果用户的class和之前的beanClass不一致,说明之前那个class真的是代理类了
if (userClass != beanClass) {
try {
// 这个时候去userClass拿一下对应的构造器
Constructor<?> superCtor =
userClass.getDeclaredConstructor(candidate.getParameterTypes());
// 再在用户的构造器上找一下注解
ann = findAutowiredAnnotation(superCtor);
}
catch (NoSuchMethodException ex) {
}
}
}
if (ann != null) {
// 这里是找到注解了
if (requiredConstructor != null) {
// 这个分支直接报错了,意思是之前已经如果有被@Autowired注解修饰了的构造器
// 且注解中的Required属性为true的时候,
// 就不允许再出现其他被@Autowired注解修饰的构造器了
// 说明@Autowired(required=true)在构造器上的语言是必须使用这个构造器
throw new BeanCreationException(...);
}
// 拿注解上的required属性
boolean required = determineRequiredStatus(ann);
if (required) {
if (!candidates.isEmpty()) {
// 这里也是一样的,有required的构造器,就不预约有其他被
// @Autowired注解修饰的构造器了
throw new BeanCreationException(...);
}
// requiredConstructor只能有一个
requiredConstructor = candidate;
}
// 符合条件的构造器加入列表-即有@Autowired的构造器
candidates.add(candidate);
}
else if (candidate.getParameterCount() == 0) {
// 如果构造器的参数为空,那就是默认构造器了
defaultConstructor = candidate;
}
}
if (!candidates.isEmpty()) {
// 如果被@Autowired修饰的构造器不为空
if (requiredConstructor == null) {
// 如果没有requiredConstructor,就把默认构造器加入列表
// 如果有requiredConstructor,实际上candidates中就只有一个构造器了
if (defaultConstructor != null) {
candidates.add(defaultConstructor);
}
else if (candidates.size() == 1 && logger.isInfoEnabled()) {
logger.info(...);
}
}
// 然后把candidates列表赋值给返回值
candidateConstructors = candidates.toArray(new Constructor<?>[0]);
}
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
// 如果当前类总共也只有一个构造器,并且这个构造器是需要参数的
// 那就直接使用这个构造器了
// 这就是为什么我们平常构造器注入不打@Autowired注解也可以的原因
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
}
// 以下主要是处理primaryConstructor的,我们就不读了
else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
}
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
candidateConstructors = new Constructor<?>[] {primaryConstructor};
}
else {
// 都不满足,就是空数组了
candidateConstructors = new Constructor<?>[0];
}
// 处理完之后放入缓存
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
// 之所以上面解析的时候,没找到构造器也是使用空数组而不是null
// 就是为了从缓存拿的时候,能区分究竟是没处理过(null),还是处理了但是找不到匹配的(空数组)
// 避免缓存穿透
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
Если вы можете найти подходящий конструктор, вы можете создать экземпляр объекта напрямую через отражение~
3.2. ПоbeanPostProcessor
Похоронен для сбора информационных заметок
пройти черезcreateBeanInstance
После создания экземпляра класса, но до внедрения свойств у нас естьbeanPostProcessor
Вызов метода скрытой точки:
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(...);
}
mbd.postProcessed = true;
}
}
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
Поскольку часть логики поддержки аннотаций в этом скрытом месте довольно важна, я расскажу о ней отдельно здесь.
3.2.1. CommonAnnotationBeanPostProcessor
собирать@PostConstruct
,@PreDestroy
,@Resource
Информация
CommonAnnotationBeanPostProcessor
СлишкомAnnotationConfigUtils#registerAnnotationConfigProcessors
Метод вводится, поэтому я не буду брать вас с собой, чтобы прочитать его здесь. так какCommonAnnotationBeanPostProcessor
ДостигнутоMergedBeanDefinitionPostProcessor
интерфейс, поэтому он тоже будет вызываться в этой скрытой точке.Давайте посмотрим на эту логику:
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable{
// 构造器
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
// 给两个关键字段设置了
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 这里调用了父类的方法,正真的收集`@PostConstruct`、`@PreDestroy`注解的逻辑是在这里做的
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
// 这里就是收集@Resource注解的信息啦
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
// 检查一下
metadata.checkConfigMembers(beanDefinition);
}
}
3.2.1.1 Аннотации жизненного цикла@PostConstruct
,@PreDestroy
собрать сообщение
Давайте посмотрим на реализацию родительского класса для сбора аннотаций жизненного цикла:
public class InitDestroyAnnotationBeanPostProcessor
implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable{
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 寻找生命周期元数据
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
// 对收集到的声明周期方法做一下校验处理
metadata.checkConfigMembers(beanDefinition);
}
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
// 没有开启缓存就直接拿构建生命周期元数据了
return buildLifecycleMetadata(clazz);
}
// 有开启缓存的话,就先从缓存找,找不到再构建,然后丢回缓存
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
// 构建
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
// 简单判断类上是不是一定没有initAnnotationType和destroyAnnotationType这两个注解修饰的方法
// 相当于快速失败
// 需要注意的是,当前场景下,这两个注解实例化的时候已经初始化为PostConstruct和PreDestroy了
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
// 用来储存类上所有初始化/销毁方法的容器
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
// 中间容器来储存当前类的初始化/销毁方法
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
// 循环类上的每一个方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
// 如果方法被@PostConstruct注解修饰,包装成一个LifecycleElement
LifecycleElement element = new LifecycleElement(method);
// 加入收集初始化方法的中间容器
currInitMethods.add(element);
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
// 如果方法被@PreDestroy注解修饰,包装成一个LifecycleElement
// 加入收集销毁方法的中间容器
currDestroyMethods.add(new LifecycleElement(method));
}
});
// 加入所有初始化/销毁方法的容器
// 需要注意的是,在整个循环过程中,
// 当前类的初始化方法都是加入初始化方法容器的头部
// 当前类的销毁方法都是加入销毁方法容器的尾部
// 所以可以推断,初始化方法调用的时候是从父类->子类调用
// 而销毁方法从子类->父类调用。
// 即 bean初始化->调用父类初始化方法->调用子类初始化方法->...->调用子类销毁方法->调用父类销毁方法->销毁bean
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
// 获取父类,循环处理所有父类上的初始化/销毁方法
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
// 把当前类class对象+初始化方法列表+销毁方法列表封装成一个LifecycleMetadata对象
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
}
Посмотрите на эти метаданные жизненного циклаLifecycleMetadata
Структура:
private class LifecycleMetadata {
// 目标类
private final Class<?> targetClass;
// 目标类上收集到的初始化方法
private final Collection<LifecycleElement> initMethods;
// 目标类上收集到的销毁方法
private final Collection<LifecycleElement> destroyMethods;
// 检查、校验后的初始化方法
@Nullable
private volatile Set<LifecycleElement> checkedInitMethods;
// 检查、校验后的销毁方法
@Nullable
private volatile Set<LifecycleElement> checkedDestroyMethods;
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
// 这是那个检查、校验方法
Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
for (LifecycleElement element : this.initMethods) {
// 循环处理每个初始化方法
String methodIdentifier = element.getIdentifier();
// 判断是否是标记为外部处理的初始化方法,
// 如果是外部处理的方法的话,其实spring是不会管理这些方法的
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
// 这里把当前方法注册到这个externallyManagedDestroyMethods
// 我猜想是方法签名相同的方法就不调用两次了
// 比如可能父类的方法打了@PostConstruct,子类重写之后也在方法上打了@PostConstruct
// 这两个方法都会被收集到initMethods,但是当然不应该调用多次
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
// 加入了检查后的初始化方法列表,实际调用初始化方法时也是会调用这个列表
checkedInitMethods.add(element);
}
}
// 销毁方法的处理逻辑和初始化方法一样,我直接跳过了
this.checkedInitMethods = checkedInitMethods;
this.checkedDestroyMethods = checkedDestroyMethods;
}
}
Пока что мы на самом делеCommonAnnotationBeanPostProcessor
Аннотация жизненного цикла процесса сбора завершена, в основном через штамп метода родительского класса, который должен быть@PostConstruct
,@PreDestroy
Информация о декорированном методе инкапсулирована вLifecycleMetadata
. прочитай этоInitDestroyAnnotationBeanPostProcessor
После логики возникнет ли у студентов желание реализовать собственный набор аннотаций жизненного цикла? В конце концов, напишите класс для наследования, а затем в своем собственном конструкторе классаset
немногоinitAnnotationType
,destroyAnnotationType
Вот и все!
3.2.1.2 Аннотации внедрения зависимостей@Resource
собрать сообщение
только что сказал нашfindResourceMetadata
метод используется для сбора@Resource
Для информации аннотации давайте посмотрим на логику здесь:
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
// 也是一个缓存逻辑
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
// 构建逻辑
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
// 这个方法除了收集@Resource注解之外,
// 其实还会收集@WebServiceRef和@EJB注解(如果你的项目有引入这些)
// 不过由于@WebServiceRef和@EJB我们现在基本也不用了(反正我没用过)
// 我这边就把相应的逻辑删除掉了,这样看也清晰点
// 而且这些收集逻辑也是一致的,最多只是说最后把注解信息封装到不同的子类型而已
// 快速失败检测
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
// 收集到注入元素
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
// 这里套路其实跟收集生命周期注解差不多了
// 也是循环收集父类的
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 循环处理每个属性
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (...) {...} // 其他注解的处理
else if (field.isAnnotationPresent(Resource.class)) {
// 静态属性不允许注入,当然其实@Autowired和@Value也是不允许的,
// 只是那边不会报错,只是忽略当前方法/属性而已
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException(...);
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
// 不是忽略的资源就加入容器
// ejb那些就是封装成EjbRefElement
currElements.add(new ResourceElement(field, field, null));
}
}
});
// 循环处理每个方法,比如@Resource修饰的set方法啦(当然没规定要叫setXxx)
// 这里会循环当前类声明的方法和接口的默认(default)方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 这里是处理桥接方法的逻辑,桥接方法是编译器自行生成的方法。
// 主要跟泛型相关,这里也不多拓展了
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 由于这个工具类的循环是会循环到接口的默认方法的
// 这里这个判断是处理以下场景的:
// 接口有一个default方法,而当前类重写了这个方法
// 那如果子类重写的method循环的时候,这个if块能进去
// 接下来接口的相同签名的默认method进来时,
// ClassUtils.getMostSpecificMethod(method, clazz)会返回子类中重写的那个方法
// 这是就和当前方法(接口方法)不一致,就不会再进if块收集一遍了
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (...) {...} // 其他注解的处理
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException(...);
}
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
// 原来@Resource方法注入只支持一个参数的方法(set方法)
// 这个限制估计是规范定的
// @Autowired没有这个限制
throw new IllegalStateException(...);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
// 封装了一个属性描述符,这个主要用来加载方法参数的,暂时不展开
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// 也封装成一个ResourceElement加入容器
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
// 每次都放到列表的最前面,说明是优先会注入父类的
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
// 把当前类的class和收集到的注入元素封装成一个注入元数据
return InjectionMetadata.forElements(elements, clazz);
}
Видно, что он на самом деле похож на жизненный цикл, он тоже собирает аннотационную информацию, а затем инкапсулирует ее, но сбор этого элемента инъекции должен собирать атрибуты и (set
), мы по-прежнему смотрим на эту структуру данных, как обычно:
public class InjectionMetadata {
// 目标类--属性需要注入到哪个类
private final Class<?> targetClass;
// 注入元素
private final Collection<InjectedElement> injectedElements;
// 检查后的注入元素
@Nullable
private volatile Set<InjectedElement> checkedElements;
}
public abstract static class InjectedElement {
// Member是Method和Field的父类
protected final Member member;
// 通过这个属性区分是field还是method
protected final boolean isField;
// 属性描述符,如果是method会通过这个描述符获取入参
@Nullable
protected final PropertyDescriptor pd;
@Nullable
protected volatile Boolean skip;
}
получитьInjectionMetadata
Послеmetadata.checkConfigMembers
Логика точно такая же, как и у жизненного цикла, так что это не так.
Итак, мы здесьCommonAnnotationBeanPostProcessor
Анализируется логика скрытой точки класса после создания экземпляра компонента.
3.2.2. AutowiredAnnotationBeanPostProcessor
собирать@Autowired
,@Value
Информация
AutowiredAnnotationBeanPostProcessor
Сроки регистрации на этот класс обсуждались много раз, а такжеAnnotationConfigUtils#registerAnnotationConfigProcessors
Метод инжектирован, давайте посмотрим на него прямо здесьpostProcessMergedBeanDefinition
Как метод собирает аннотационную информацию:
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
// 自动注入注解类型
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
public AutowiredAnnotationBeanPostProcessor() {
// autowiredAnnotationTypes中放入@Autowired、@Value
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 这里其实就很熟悉了,和@Resource的处理过程看起来就是一模一样的
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
// 缓存逻辑我这边就不看了,都是一模一样的
// 这个,其实连收集逻辑都基本是一致的,我们就简单过一下吧
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 处理属性
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
// 静态属性不允许注入
if (Modifier.isStatic(field.getModifiers())) {
return;
}
// @Autowrired有一个required属性需要收集一下
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 处理方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
// 静态方法不处理,忽略,相当于不生效,@Resource那边是会报错的。
return;
}
boolean required = determineRequiredStatus(ann);
// 封装一个属性描述符描述符
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
// 父类优先
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
// 封装到InjectionMetadata
return InjectionMetadata.forElements(elements, clazz);
}
}
Ах, скучно, эта логика так же проста, как@Resource
Лечение точно такое же, есть ли у студентов сомнения - такой похожий метод,spring
Зачем писать дважды?Является ли это нарушениемDRY
А как же принцип? Учащиеся думают над этим вопросом.
я не думаю, что это было нарушено
DRY
принцип, но дляjavax.inject.Inject
Разделение аннотаций пока нецелесообразно и должно быть разделено наcommon
; иcommon
Обработка различных типов аннотаций в (@EJB
,@Resource
,@WebServiceRef
)использоватьif-else
Это также не очень элегантно, и можно использовать небольшой шаблон стратегии.Однако у всех разные мнения на этот счет. Заинтересованные студенты также могут обсудить это в комментариях~
3.2.3. РезюмеCommonAnnotationBeanPostProcessor
иAutowiredAnnotationBeanPostProcessor
В основном эти дваbeanPostProcessor
Кое-что я сделал, и это тоже тесно связано с нашим обычным развитием.Вот краткое содержание.
3.2.3.1 Разделение функций
эти двоеbeanPostProcessor
Функции делятся на:
-
CommonAnnotationBeanPostProcessor
основная обработкаjdk
Соответствующие нормативные примечания,@Resource
,@PostConstruct
и т.д. аннотацииjdk
Как определено в спецификации.- Связанный с жизненным циклом коллекции
@PostConstruct
,@PreDestroy
Информация аннотаций заключена вLifecycleMetadata
- Сбор аннотаций внедрения ресурсов (наша основная задача
@Resource
) информация инкапсулируется вInjectionMetadata
- Связанный с жизненным циклом коллекции
-
AutowiredAnnotationBeanPostProcessor
основная обработкаspring
Определенный@Autowired
связанные функции-
Я должен сказать здесь, что я думаю, что этот класс также используется для работы с
javax.inject.Inject
неразумный -
Собирать аннотации, связанные с автоматической инъекцией
@Autowired
,@Value
информация упакована вInjectionMetadata
-
3.2.3.2 Использование@Resouce
все еще@Autowired
?
Итак, что мы рекомендуем использовать в нашем ежедневном процессе разработки?@Resouce
все еще@Autowired
Шерстяная ткань? Я думаю, что доброжелательный видит благожелательный, а мудрый видит мудрость.Я лишь кратко перечислю вопросы, на которые необходимо обратить внимание при использовании этих двух аннотаций:
-
@Resouce
и@Autowired
Ни один из них не может использоваться для внедрения статических свойств (путем использования аннотаций к статическим свойствам и статическим методам). - использовать
@Resouce
При внедрении статических свойств он будет выброшенIllegalStateException
Вызывает сбой текущего процесса инициализации экземпляра - при использовании
@Autowired
При внедрении статического свойства будет игнорироваться только текущее свойство.Если оно не внедрено, это не приведет к сбою процесса инициализации экземпляра. - использовать
@Resouce
При изменении метода метод может иметь только один входной параметр, и@Autowired
безлимитный -
@Resouce
принадлежатьjdk
Можно считать, что вторжение в проект нулевое;@Autowired
принадлежатьspring
спецификация, использование@Autowired
нельзя заменить другимIOC
Фреймворк (я его не заменял...)
(Из-за ограничения Nuggets на количество слов в статье, этот пост в блоге был вынужден разделить на две части:Нажмите, чтобы перейти к следующей статье)
Создание не простое, пожалуйста, указывайте автора в начале перепечатки: Nuggets@小西子 + ссылка на источник~
Если вы хотите узнать больше об исходном коде Spring,Нажмите, чтобы перейти к остальной части построчного анализа серии Spring
٩(* ఠO ఠ)=3⁼³₌₃⁼³₌₃⁼³₌₃du ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла. . .
Вот блогер-новичок Сяо Сизи, большие парни видели это, пожалуйста, поставьте лайк в левом верхнем углу~~