IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring源码分析-BeanDefinition -> 正文阅读

[Java知识库]Spring源码分析-BeanDefinition

Spring源码分析系列

Spring源码分析-启动流程浅析
Spring源码分析-Spring源码分析-BeanDefinition


前言

BeanDefinition相当于Bean meta信息,后续创建Bean对象都需要依据BeanDefinition,因此这里需要介绍一下

一、BeanDefinition

BeanDefinition是一个接口,接口定义如下:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	/**
	 * 单例bean
	 */
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	/**
	 * 原型bean
	 */
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


	/**
	 * bean的Role属性 现在基本废弃
	 */
	int ROLE_APPLICATION = 0;
	int ROLE_SUPPORT = 1;
	int ROLE_INFRASTRUCTURE = 2;


	// Modifiable attributes
	// 设置父BeanDefinition名称
	void setParentName(@Nullable String parentName);
	@Nullable String getParentName();

	/**
	 * bean全类名称
	 */
	void setBeanClassName(@Nullable String beanClassName);
	@Nullable String getBeanClassName();

	/**
	 * 设置bean的作用域 单例 或者 原型
	 */
	void setScope(@Nullable String scope);
	@Nullable String getScope();

	/**
	 * 懒加载模式
	 */
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();

	/**
	 * Set the names of the beans that this bean depends on being initialized.
	 * The bean factory will guarantee that these beans get initialized first.
	 */
	void setDependsOn(@Nullable String... dependsOn);
	@Nullable String[] getDependsOn();

	/**
	 * Set whether this bean is a candidate for getting autowired into some other bean.
	 * <p>Note that this flag is designed to only affect type-based autowiring.
	 * It does not affect explicit references by name, which will get resolved even
	 * if the specified bean is not marked as an autowire candidate. As a consequence,
	 * autowiring by name will nevertheless inject a bean if the name matches.
	 */
	void setAutowireCandidate(boolean autowireCandidate);

	/**
	 * Return whether this bean is a candidate for getting autowired into some other bean.
	 */
	boolean isAutowireCandidate();

	/**
	 * 设置当前bean为主要的, @Primary
	 */
	void setPrimary(boolean primary);
	boolean isPrimary();

	/**
	 * Specify the factory bean to use, if any.
	 * This the name of the bean to call the specified factory method on.
	 * @see #setFactoryMethodName
	 */
	void setFactoryBeanName(@Nullable String factoryBeanName);
	@Nullable String getFactoryBeanName();

	/**
	 * Specify a factory method, if any. This method will be invoked with
	 * constructor arguments, or with no arguments if none are specified.
	 * The method will be invoked on the specified factory bean, if any,
	 * or otherwise as a static method on the local bean class.
	 * @see #setFactoryBeanName
	 * @see #setBeanClassName
	 */
	void setFactoryMethodName(@Nullable String factoryMethodName);

	/**
	 * Return a factory method, if any.
	 */
	@Nullable
	String getFactoryMethodName();

	/**
	 * Return the constructor argument values for this bean.
	 * <p>The returned instance can be modified during bean factory post-processing.
	 * @return the ConstructorArgumentValues object (never {@code null})
	 */
	ConstructorArgumentValues getConstructorArgumentValues();

	/**
	 * Return if there are constructor argument values defined for this bean.
	 * @since 5.0.2
	 */
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	/**
	 * Return the property values to be applied to a new instance of the bean.
	 * <p>The returned instance can be modified during bean factory post-processing.
	 * @return the MutablePropertyValues object (never {@code null})
	 */
	MutablePropertyValues getPropertyValues();

	/**
	 * Return if there are property values defined for this bean.
	 * @since 5.0.2
	 */
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	/**
	 * Set the name of the initializer method.
	 * @since 5.1
	 */
	void setInitMethodName(@Nullable String initMethodName);

	/**
	 * Return the name of the initializer method.
	 * @since 5.1
	 */
	@Nullable String getInitMethodName();

	/**
	 * Set the name of the destroy method.
	 * @since 5.1
	 */
	void setDestroyMethodName(@Nullable String destroyMethodName);

	/**
	 * Return the name of the destroy method.
	 * @since 5.1
	 */
	@Nullable String getDestroyMethodName();

	void setRole(int role);
	int getRole();

	/**
	 * Set a human-readable description of this bean definition.
	 * @since 5.1
	 */
	void setDescription(@Nullable String description);

	/**
	 * Return a human-readable description of this bean definition.
	 */
	@Nullable String getDescription();


	// Read-only attributes

	/**
	 * Return a resolvable type for this bean definition,
	 * based on the bean class or other specific metadata.
	 * <p>This is typically fully resolved on a runtime-merged bean definition
	 * but not necessarily on a configuration-time definition instance.
	 * @return the resolvable type (potentially {@link ResolvableType#NONE})
	 * @since 5.2
	 * @see ConfigurableBeanFactory#getMergedBeanDefinition
	 */
	ResolvableType getResolvableType();

	/**
	 * 是否为单例
	 */
	boolean isSingleton();

	/**
	 * 是否为原型
	 */
	boolean isPrototype();

	/**
	 * Return whether this bean is "abstract", that is, not meant to be instantiated.
	 */
	boolean isAbstract();

	/**
	 * Return a description of the resource that this bean definition
	 * came from (for the purpose of showing context in case of errors).
	 */
	@Nullable String getResourceDescription();

	/**
	 * Return the originating BeanDefinition, or {@code null} if none.
	 * <p>Allows for retrieving the decorated bean definition, if any.
	 * <p>Note that this method returns the immediate originator. Iterate through the
	 * originator chain to find the original BeanDefinition as defined by the user.
	 */
	@Nullable BeanDefinition getOriginatingBeanDefinition();

}

BeanDefinition接口中注入比较详细,大家可以参考源码。主要包括如下属性:bean的作用域,bean是否为Primary,bean是否需要FactoryBean,Init/Destroy方法等。

二、AbstractBeanDefinition

spring代码优秀之处,基本上所有的接口,它都会提供一个实现类,而这个实现类往往都是抽象的(Abstract)。我们接下来看一下AbstractBeanDefinition做了哪些工作

2.1、核心字段

@Nullable
private volatile Object beanClass; //bean name
@Nullable
private String scope = SCOPE_DEFAULT; //作用域  SCOPE_SINGLETON
private boolean abstractFlag = false; //是否为抽象
@Nullable
private Boolean lazyInit;
private int autowireMode = AUTOWIRE_NO; //自动注入
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
@Nullable
private String[] dependsOn;
private boolean autowireCandidate = true;
//是否为主要的, 在按照类型给属性注入时,若出现冲突则查看是否存在@Primary注解 当存在这个注解则字段为true
private boolean primary = false;
@Nullable
private String factoryBeanName; //工厂bean名字
@Nullable
private String factoryMethodName; //工厂方法名字
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
@Nullable
private MutablePropertyValues propertyValues;
private MethodOverrides methodOverrides = new MethodOverrides();
@Nullable
private String initMethodName;
@Nullable
private String destroyMethodName;

看到这里不知道大家是否感觉到,这个数据结构很像spring.xml中配置项,不错,这个类(接口)就是spring.xml文件抽像模型。

2.2、核心方法

/**
 * Specify the class for this bean.
 * @see #setBeanClassName(String)
 */
public void setBeanClass(@Nullable Class<?> beanClass) {
	this.beanClass = beanClass;
}

/**
 * Specify the bean class name of this bean definition.
 */
@Override
public void setBeanClassName(@Nullable String beanClassName) {
	this.beanClass = beanClassName;
}

public String getBeanClassName() {
	Object beanClassObject = this.beanClass;
	if (beanClassObject instanceof Class) {
		return ((Class<?>) beanClassObject).getName();
	}
	else {
		return (String) beanClassObject;
	}
}

public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
	String className = getBeanClassName();
	if (className == null) {
		return null;
	}
	Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
	this.beanClass = resolvedClass;
	return resolvedClass;
}

2.2、BeanDefinition扫描

AbstractBeanDefinition并没有提供注册的功能,所以注册是在外部实现的,这也体现了一种设计模式:单一职责模式。
在上一篇介绍Spring源码分析-启动流程浅析中有提到会进行包扫描,这个扫描过程其实就是注册BeanDefinition。

在这里插入图片描述

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) {
		//扫描组件 返回的类型是BeanDefinition,实际是ScannedGenericBeanDefinition
		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) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			if (checkCandidate(beanName, candidate)) {//判断registry中是否存在BeanDefinition 如果没有则创建
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				definitionHolder =
						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);
				registerBeanDefinition(definitionHolder, this.registry);//注册BeanDefinition
			}
		}
	}
	return beanDefinitions;
}

2.3、BeanDefinition注册

在注解场景下,入口类AnnotationConfigApplicationContext继承GenericApplicationContext,在GenericApplicationContext中有一个属性用于保存BeanDefinition

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    //DefaultListableBeanFactory, 默认Bean工厂,用于产生bean对象
	private final DefaultListableBeanFactory beanFactory;
...
}

DefaultListableBeanFactory核心字段

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

	/** Map from dependency type to corresponding autowired value. */
	private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

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

	/** Map from bean name to merged BeanDefinitionHolder. */
	private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);

	/** Map of singleton and non-singleton bean names, keyed by dependency type. */
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

	/** Map of singleton-only bean names, keyed by dependency type. */
	private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

	/** List of bean definition names, in registration order. 保存bean definition name */
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

	/** List of names of manually registered singletons, in registration order. */
	private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
...
}

通过上面的源码可知,这些map,list就是用于存与BeanDefinition相关的内容,下面是注册BeanDefinition核心方法

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {//表示已经存在BeanDefinition
        if (!isAllowBeanDefinitionOverriding()) {//是否允许覆盖已经存在BeanDefinition
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean '" + beanName +
                        "' with a framework-generated bean definition: replacing [" +
                        existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                        "' with a different definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean '" + beanName +
                        "' with an equivalent definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);//覆盖
    }
    else {//BeanDefinition不存在
        if (hasBeanCreationStarted()) {// 非启动流程注册beanDefinition, 例如动态注册
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);//放到map中
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                removeManualSingletonName(beanName);
            }
        }
        else {//启动注册阶段
            // Still in startup registration phase
            this.beanDefinitionMap.put(beanName, beanDefinition);//放到map中
            this.beanDefinitionNames.add(beanName); //保存注册的beanName
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
        clearByTypeCache();
    }
}

2.4、动态注册Bean

public class UserService {
    private Map<String, User> map = new ConcurrentHashMap<>();

    public UserService() {
        System.out.println("UserService init....");
    }

    public User getUser(String name) {
        return map.get(name);
    }

    public void addUser(User user) {
        map.put(user.getUsername(), user);
    }
}

public class WApp {
    public static void main(String[] args) {
        GenericApplicationContext context = new AnnotationConfigApplicationContext("com.worker");
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(UserService.class);
        context.registerBeanDefinition("userService", beanDefinition); //动态注册BeanDefinition

		//获取bean时,如果bean不存在则去查找是否存在BeanDefinition,如果存在则根据BeanDefinition实例化Bean
        System.out.println(context.getBean("userService"));
    }
}

总结

总体来说,BeanDefinition相关的内容不是很复杂,只要知道BeanDefinition的作用以及包扫描的作用即可。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 18:48:07  更:2022-01-30 18:50:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:52:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码