技术标签: spring # Spring源码分析 学习 java 源码分析 后端
上一节我们看到正对不同作用域Bean的加载,但是Bean的核心创建我们还没有说,下面我们来看看Bean的核心加载也就是CreateBean与DoCreateBean方法的核心实现
AbstractAutowireCapableBeanFactory
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 确保此时的 bean 已经被解析了
// 如果获取的class 属性不为null,则克隆该 BeanDefinition
// 主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
// 验证和准备覆盖方法
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
// AOP 的功能就是基于这个地方
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 执行真正创建 bean 的过程
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
// 确保此时的 bean 已经被解析了
// 如果获取的class 属性不为null,则克隆该 BeanDefinition
// 主要是因为该动态解析的 class 无法保存到到共享的 BeanDefinition
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
// 验证和准备覆盖方法
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exists.
//检测是否存在方法注入,并循环预处理方法注入
// Check that lookup methods exist and determine their overloaded status.
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
// 统计注入的方法个数
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException(
"Invalid method override: no method with name '" + mo.getMethodName() +
"' on class [" + getBeanClassName() + "]");
}
// 如果为1,则将注入方法标记为未重载
// 注意:当有多个重载方法时,为了确定调用哪个具体的方法,Spring对重载方法的参数解析是很复杂的
// 所以,如果注入方法没有被重载这里就将其标记,省去了对方法参数的解析过程,直接调用即可
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
mo.setOverloaded(false);
}
}
在真正调用doCreate方法创建bean的实例前使用了这样一个方法resolveBeforeInstantiation (beanName, mbd)对BeanDefinigiton中的属性做些前置处理,当经过前置处理后返回的结果如果不为空,那么会直接略过后续的Bean的创建而直接返回结果。这一特性虽然很容易被忽略,但是却起着至关重要的作用,我们熟知的AOP功能就是基于这里的判断的
try {
// 给 BeanPostProcessors 一个机会用来返回一个代理类而不是真正的类实例
// AOP 的功能就是基于这个地方
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 如果没有被解析
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// synthetic表示合成,如果某些Bean式合成的,那么则不会经过BeanPostProcessor的处理
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors())
// 确定目标类型
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 在实例化之前应用 Bean 后处理器
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 初始化后应用 Bean 后处理器
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
此方法中最吸引我们的无疑是两个方法applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInitialization。
两个方法实现的非常简单,无非是对后处理器中的所有InstantiationAwareBeanPostProcessor类型的后处理器进行postProcessBeforeInstantiation方法和BeanPostProcessor的postProcessAfterInitialization方法的调用。(后面生命周期详细讲解)
参考文章:spring bean扩展点:后处理器 BeanPostProcessor_postprocessbeforeinstantiation
如果没有代理对象,就只能走常规的路线进行 bean 的创建了,该过程有 doCreateBean() 实现
当经历过resolveBeforeInstantiation方法后,程序有两个选择,如果创建了代理或者说重写了InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法并在方法postProcess BeforeInstantiation中改变了bean,则直接返回就可以了,否则需要进行常规bean的创建。
AbstractAutowireCapableBeanFactory
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
BeanWrapper instanceWrapper = null;
// 单例模型,则从未完成的 FactoryBean 缓存中删除
if (mbd.isSingleton()) {
anceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 包装的实例对象
final Object bean = instanceWrapper.getWrappedInstance();
// 包装的实例对象的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 检测是否有后置处理
// 如果有后置处理,则允许后置处理修改 BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// applyMergedBeanDefinitionPostProcessors
// 后置处理修改 BeanDefinition
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 解决单例模式的循环依赖
// 单例模式 & 运行循环依赖&当前单例 bean 是否正在被创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 提前将创建的 bean 实例加入到ectFactory 中
// 这里是为了后期避免循环依赖
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
/*
* 开始初始化 bean 实例对象
*/
Object exposedObject = bean;
try {
// 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
// 则会递归初始依赖 bean
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
/**
* 循环依赖处理
*/
if (earlySingletonExposure) {
// 获取 earlySingletonReference
Object earlySingletonReference = getSingleton(beanName, false);
// 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
if (earlySingletonReference != null) {
// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
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(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
// 注册 bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
我们来总结一下上面函数的大体步骤:
我们依次来看看呗
在详细介绍之前,我们先了解BeanWrapper这个类的作用
BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器,由于BeanWrapper接口是PropertyAccessor的子接口,因此其也可以设置以及访问被包装对象的属性值。
BeanWrapper大部分情况下是在spring ioc内部进行使用,通过BeanWrapper,spring ioc容器可以用统一的方式来访问bean的属性。用户很少需要直接使用BeanWrapper进行编程。
// BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
BeanWrapper instanceWrapper = null;
// 单例模型,则从未完成的 FactoryBean 缓存中删除
if (mbd.isSingleton()) {
anceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
参考博客:Spring IoC 依赖注入(四)构造器或工厂注入
// 使用合适的实例化策略来创建新的实例:工厂方法、Spring IoC 依赖注入(四)构造器或工厂注入 - binarylei - 博客园构造函数自动注入、简单初始化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
AbstractAutowireCapableBeanFactory
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 1.1 确保此时beanClassName已经加载,当然注解驱动时不会设置beanClassName属性
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 1.2 校验beanClass允许访问
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException();
}
// 2. Supplier创建对象
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// ========= 工厂方法实例化 =========
// 3. 工厂方法实例化,包括实例化工厂和静态工厂
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// ========= 构造器实例化 =========
// 4. 快速实例化对象,所谓的快速实例化,实际上是说使用缓存
boolean resolved = false;
boolean autowireNecessary = false;
// 4.1 args: 外部化参数,只能当无外部参数时才使用缓存。不推荐使用外部化参数
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 4.2 是否使用缓存,其中autowireNecessary表示是否使用有参构造器
// 无参时肯定不会解析,为false。有参时会解析,为true
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 4.3 使用缓存,其中autowireNecessary表示是否使用有参构造器
if (resolved) {
if (autowireNecessary) {
// 4.4 有参构造器实例化
return autowireConstructor(beanName, mbd, null, null);
} else {
// 4.5 无参构造器实例化
return instantiateBean(beanName, mbd);
}
}
// 5. 到此,只能老老实实的解析,当然解析后会将解析后的构造器或参数缓存起来
// 5.1 是否指定了构造器,ibp#determineCandidateConstructors
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 5.2 构造器实例化
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 5.3 不用管,默认都是 null。
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 5.4 无参构造器实例化
return instantiateBean(beanName, mbd);
}
首先我们了解一下Spring创建Bean的方式:
Spring创建对象的主要方式有
createBean() -> resolveBeforeInstantiation()
createBean() -> doCreateBean() -> createBeanInstance() -> obtainFromSupplier()
createBean() -> doCreateBean() -> createBeanInstance() -> instantiateUsingFactoryMethod()
createBean() -> doCreateBean() -> createBeanInstance() -> instantiateBean()
下面我们一一来看一看
我们先来写一个案例,这种用法比较偏门
User
package com.shu.supplier;
/**
* @description:
* @author: shu
* @createDate: 2023/8/31 14:11
* @version: 1.0
*/
public class User {
private String name;
public User() {
System.out.println("User 无参构造函数");
}
public User(String name) {
this.name = name;
System.out.println("User 有参构造函数");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("User setName");
}
public void init() {
System.out.println("User init");
}
public void destroy() {
System.out.println("User destroy");
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
CreateSupplier
package com.shu.supplier;
/**
* @description:
* @author: shu
* @createDate: 2023/8/31 14:11
* @version: 1.0
*/
public class CreateSupplier {
public static User createUser() {
User xiaomi = new User("xiaomi");
System.out.println("CreateSupplier createUser:"+xiaomi);
return xiaomi;
}
}
SupplierBeanFactoryPostProcessor
package com.shu.supplier;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
/**
* @description:
* @author: shu
* @createDate: 2023/8/31 14:12
* @version: 1.0
*/
public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanDefinition;
genericBeanDefinition.setInstanceSupplier(CreateSupplier::createUser);
genericBeanDefinition.setBeanClass(User.class);
}
}
配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.shu.supplier.User"></bean>
<bean id="supplierBeanFactoryPostProcessor" class="com.shu.supplier.SupplierBeanFactoryPostProcessor"></bean>
</beans>
测试
import com.shu.supplier.User;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
/**
* @description:
* @author: shu
* @createDate: 2023/7/29 23:05
* @version: 1.0
*/
public class AplTest {
/**
* 测试FactoryBean
*/
@Test
public void factoryBeanTestSupplier() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("supplier.xml");
User user = applicationContext.getBean(User.class);
System.out.println(user.getName());
}
}
下面我们来具体分析看看呗
AbstractAutowireCapableBeanFactory
// 如果获取getInstanceSupplier不为空,参考:genericBeanDefinition.setInstanceSupplier(CreateSupplier::createUser);
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
下面进入obtainFromSupplier进行看看,那么回到这个方法中,主体就是调用get()这个方法获取实例
protected BeanWrapper obtainFromSupplier(Supplier instanceSupplier, String beanName) {
Object instance;
// 获得原当前线程正在创建的 Bean 的名称
String outerBean = this.currentlyCreatedBean.get();
// 设置当前线程正在创建的 Bean 的名称
this.currentlyCreatedBean.set(beanName);
try {
//调用 Supplier 的 get(),返回一个实例对象
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
// 设置原当前线程正在创建的 Bean 的名称到当前线程变量中
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
// 未创建 Bean 对象,则创建 NullBean 空对象
if (instance == null) {
instance = new NullBean();
}
//将实例对象封装成 BeanWrapper 对象
BeanWrapper bw = new BeanWrapperImpl(instance);
//初始化这个 BeanWrapper 对象
initBeanWrapper(bw);
return bw;
}
过程如下:
调用 Supplier 接口的 get(),返回 instance 实例对象
将 instance 封装成 BeanWrapper 对象 bw
对 bw 进行初始化,设置 ConversionService 类型转换器,并注册自定义的属性编辑器
然后再进行实例化
AbstractAutowireCapableBeanFactory
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
知识回顾:
静态工厂实例化
在定义一个用静态工厂方法创建的Bean时,使用 class 属性来指定包含 static 工厂方法的类,并使用名为 factory-method 的属性来指定工厂方法本身的名称。你应该能够调用这个方法(有可选的参数,如后文所述)并返回一个活的对象,随后该对象被视为通过构造函数创建的。
package com.shu.factory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* @description: 静态工厂, 用于书写创建复杂对象的代码
* @author: shu
* @createDate: 2023/7/21 20:14
* @version: 1.0
*/
public class StaticConnectionFactory {
public static Connection getConnection(){
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/auth?useSSL=false", "root", "123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
<bean id="db" class="com.shu.factory.StaticConnectionFactory" factory-method="getConnection"/>
/**
* 静态工厂实例化bean
*/
@Test
public void test8(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Object db = context.getBean("db");
System.out.println("db = " + db);
}
实例工厂方法进行实例化
与 通过静态工厂方法进行的实例化 类似,用实例工厂方法进行的实例化从容器中调用现有 bean 的非静态方法来创建一个新的 bean。要使用这种机制,请将 class 属性留空,并在 factory-bean 属性中指定当前(或父代或祖代)容器中的一个 Bean 的名称,该容器包含要被调用来创建对象的实例方法。用 factory-method 属性设置工厂方法本身的名称。
package com.shu.factory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionFactory {
public Connection getConnection(){
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/auth?useSSL=false", "root", "123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
<bean id="connFactory" class="com.shu.factory.ConnectionFactory"></bean>
<bean id="conn" factory-bean="connFactory" factory-method="getConnection"/>
@Test
public void test10() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Object conn = context.getBean("conn");
System.out.println("conn = " + conn);
}
让我们回到代码部分
AbstractAutowireCapableBeanFactory
//如果配置了 `factory-method` 工厂方法,则调用该方法来创建一个实例对象
// 通过 @Bean 标注的方法会通过这里进行创建
if (mbd.getFactoryMethodName() != null) {
// 这个过程非常复杂,你可以理解为:
// 找到最匹配的 Method 工厂方法,获取相关参数(依赖注入),然后通过调用该方法返回一个实例对象(反射机制)
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
通过 factoryMethodName 工厂方法创建一个实例对象,例如 XML 配置的 factory-method 属性或者 @Bean 标注的方法都会解析成 factoryMethodName 属性
这个过程非常复杂,你可以理解为去找到最匹配的 Method 工厂方法,获取相关入参(依赖注入),然后调用该方法返回一个实例对象(反射机制)
AbstractAutowireCapableBeanFactory
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
创建 ConstructorResolver 对象,然后调用其 instantiateUsingFactoryMethod(…) 方法,如下:
// ConstructorResolver.java
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 构造 BeanWrapperImpl 对象
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化 BeanWrapperImpl,设置 ConversionService 类型转换器,并注册自定义的属性编辑器
this.beanFactory.initBeanWrapper(bw);
// -------------------------获取工厂方法的相关信息-------------------------
//获取工厂方法的相关信息
// 工厂方法所在类对应的 Bean(静态方法不会有)
Object factoryBean;
// 工厂方法所在类的 Class 对象
Class factoryClass;
// 是否为 static 修饰的静态方法
boolean isStatic;
// 获取工厂方法所在类对应的 Bean 的名称(静态方法不会有)
String factoryBeanName = mbd.getFactoryBeanName();
//非静态方法
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 获取工厂方法所在类对应的 Bean,不然无法调用工厂方法
factoryBean = this.beanFactory.getBean(factoryBeanName);
// 如果是单例模式,已经存在对应的 Bean,则抛出重复创建的异常
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
//静态方法
else {
// It's a static factory method on the bean class.
// 静态方法没有找到对应的 Class 对象无法被调用,则抛出异常
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
// -------------------------尝试获取工厂方法对象和入参-------------------------
//尝试获取工厂方法对象和参数
// 工厂方法对象
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
// 方法参数
Object[] argsToUse = null;
//如果方法入参指定了参数,则直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
//否则,尝试从 RootBeanDefinition 中获取已解析出来的工厂方法和入参
else {
Object[] argsToResolve = null;
// 因为可能前面解析了,会临时缓存,避免再次解析
synchronized (mbd.constructorArgumentLock) {
// 加锁
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
// 如果工厂方法被解析了,那么参数也可能解析过
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 没有解析过的参数,则尝试从 RootBeanDefinition 中获取未被解析过的参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果获取到了未被解析过的入参,则进行解析
if (argsToResolve != null) {
// 处理参数值,类型转换,例如给定方法 A(int, int),配置了 A("1"、"2") 两个参数,则会转换为 A(1, 1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
// -------------------------找到所有匹配的工厂方法-------------------------
//如果上一步没有找到工厂方法对象或方法入参集合,则需要进行接下来的解析过程,首先找到所有匹配的工厂方法
if (factoryMethodToUse == null || argsToUse == null) {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
//获取工厂方法所在的类的实例 Class 对象,因为可能是 Cglib 提升过的子类
factoryClass = ClassUtils.getUserClass(factoryClass);
//获取工厂方法所在的类中所有方法对象
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
//找到这个类中匹配的工厂方法
ListcandidateList = new ArrayList<>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic // 是否和 `isStatic` 匹配
&& mbd.isFactoryMethod(candidate)) {
// 和定义的工厂方法的名称是否相等
candidateList.add(candidate);
}
}
//如果只有一个匹配的方法,且这个方法没有给指定的入参,且本身也没有定义参数,且这个方法没有定义入参
// 则直接调用这个方法创建一个实例对象(反射机制),并返回
if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidateList.get(0);
if (uniqueCandidate.getParameterCount() == 0) {
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// -------------------------开始找最匹配的工厂方法-------------------------
//开始找最匹配的工厂方法
// 将匹配的工厂方法转换成数组
Method[] candidates = candidateList.toArray(new Method[0]);
// 将匹配的方法进行排序,public 方法优先,入参个数多的优先
AutowireUtils.sortFactoryMethods(candidates);
// 用于承载解析后的方法参数值
ConstructorArgumentValues resolvedValues = null;
// 是否是构造器注入
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
// 匹配方法的集合
SetambiguousFactoryMethods = null;
// -------------------------确定方法参数的入参数量-------------------------
//确定方法参数的入参数量,匹配的方法的入参数量要多余它
// 方法的参数数量的最小值
int minNrOfArgs;
//如果当前方法指定了入参,则使用其个数作为最小值
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
//否则,从 RootBeanDefinition 解析出方法的参数个数作为最小值
else {
// We don't have arguments passed in programmatically, so we need to resolve the
// arguments specified in the constructor arguments held in the bean definition.
// RootBeanDefinition 定义了参数值
if (mbd.hasConstructorArgumentValues()) {
// 方法的参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析定义的参数值,放入 `resolvedValues` 中,并返回参数个数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
minNrOfArgs = 0;
}
}
// 记录 UnsatisfiedDependencyException 异常的集合
LinkedListcauses = null;
// 遍历匹配的方法
for (Method candidate : candidates) {
// 方法体的参数
Class[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
// -------------------------解析出工厂方法的入参-------------------------
//解析出工厂方法的入参
// 保存参数的对象
ArgumentsHolder argsHolder;
//如果当前方法指定了入参,则直接使用
if (explicitArgs != null) {
// Explicit arguments given -> arguments length must match exactly.
// 显示给定参数,参数长度必须完全匹配
if (paramTypes.length != explicitArgs.length) {
continue;
}
// 根据参数创建参数持有者 ArgumentsHolder 对象
argsHolder = new ArgumentsHolder(explicitArgs);
}
//否则,通过**依赖注入**获取入参
else {
// Resolved constructor arguments: type conversion and/or autowiring necessary.
// 为提供参数,解析构造参数
try {
String[] paramNames = null;
// 获取 ParameterNameDiscoverer 参数名称探测器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
// 获取方法的参数名称
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
// 解析出方法的入参,参数值会被依赖注入
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
// 若发生 UnsatisfiedDependencyException 异常,添加到 causes 中。
if (logger.isTraceEnabled()) {
logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next overloaded factory method.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// -------------------------根据权重获取最匹配的方法-------------------------
//因为会遍历所有匹配的方法,所以需要进行权重的判断,拿到最优先的那个
// 判断解析构造函数的时候是否以宽松模式还是严格模式,默认为 true
// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
// 宽松模式:使用具有"最接近的模式"进行匹配
// typeDiffWeight:类型差异权重
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this factory method if it represents the closest match.
// 代表最匹配的结果,则选择作为符合条件的方法
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
// Find out about ambiguity: In case of the same type difference weight
// for methods with the same number of parameters, collect such candidates
// and eventually raise an ambiguity exception.
// However, only perform that check in non-lenient constructor resolution mode,
// and explicitly ignore overridden methods (with the same parameter signature).
// 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项
// 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写方法(具有相同的参数签名)
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterCount() &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
// 查找到多个可匹配的方法
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<>();
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
//没有找到对应的工厂方法,则抛出异常
if (factoryMethodToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
ListargTypes = new ArrayList<>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else if (resolvedValues != null) {
SetvalueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
//将解析出来的工厂方法和入参缓存,设置到 RootBeanDefinition 中,因为整个过程比较复杂,避免再次解析
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
Assert.state(argsToUse != null, "Unresolved factory method arguments");
//调用工厂方法创建一个实例对象(反射机制),并设置到 `bw` 中
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;
}
// 构造 BeanWrapperImpl 对象
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化 BeanWrapperImpl,设置 ConversionService 类型转换器,并注册自定义的属性编辑器
this.beanFactory.initBeanWrapper(bw);
// 获取工厂方法所在类对应的 Bean 的名称(静态方法不会有)
String factoryBeanName = mbd.getFactoryBeanName();
//非静态方法
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 获取工厂方法所在类对应的 Bean,不然无法调用工厂方法
factoryBean = this.beanFactory.getBean(factoryBeanName);
// 如果是单例模式,已经存在对应的 Bean,则抛出重复创建的异常
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
//静态方法
else {
// It's a static factory method on the bean class.
// 静态方法没有找到对应的 Class 对象无法被调用,则抛出异常
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
:::warning
这一步找到了三个对象:factoryBean(工厂方法所在类对应的 Bean,静态方法不会有)、factoryClass(工厂方法所在类的 Class 对象)、isStatic(是否为静态方法)。所以想要通过工厂方法获取一个 Bean,则需要方法所在类对应的 Bean 先初始化,然后才能调用这个方法创建 Bean;而静态方法就不用,因为它可以根据所在类的 Class 对象就能调用这个方法创建 Bean,这就是两者的区别。
:::
//如果方法入参指定了参数,则直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
//否则,尝试从 RootBeanDefinition 中获取已解析出来的工厂方法和入参
else {
Object[] argsToResolve = null;
// 因为可能前面解析了,会临时缓存,避免再次解析
synchronized (mbd.constructorArgumentLock) {
// 加锁
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
// 如果工厂方法被解析了,那么参数也可能解析过
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 没有解析过的参数,则尝试从 RootBeanDefinition 中获取未被解析过的参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果获取到了未被解析过的入参,则进行解析
if (argsToResolve != null) {
// 处理参数值,类型转换,例如给定方法 A(int, int),配置了 A("1"、"2") 两个参数,则会转换为 A(1, 1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
:::warning
这一步尝试获取两个对象:factoryMethodToUse(对应的工厂方法 Method)、argsToUse(工厂方法的入参集合)
:::
// -------------------------找到所有匹配的工厂方法-------------------------
//如果上一步没有找到工厂方法对象或方法入参集合,则需要进行接下来的解析过程,首先找到所有匹配的工厂方法
if (factoryMethodToUse == null || argsToUse == null) {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
//获取工厂方法所在的类的实例 Class 对象,因为可能是 Cglib 提升过的子类
factoryClass = ClassUtils.getUserClass(factoryClass);
//获取工厂方法所在的类中所有方法对象
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
//找到这个类中匹配的工厂方法
ListcandidateList = new ArrayList<>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic // 是否和 `isStatic` 匹配
&& mbd.isFactoryMethod(candidate)) {
// 和定义的工厂方法的名称是否相等
candidateList.add(candidate);
}
}
//如果只有一个匹配的方法,且这个方法没有给指定的入参,且本身也没有定义参数,且这个方法没有定义入参
// 则直接调用这个方法创建一个实例对象(反射机制),并返回
if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidateList.get(0);
if (uniqueCandidate.getParameterCount() == 0) {
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// -------------------------开始找最匹配的工厂方法-------------------------
//开始找最匹配的工厂方法
// 将匹配的工厂方法转换成数组
Method[] candidates = candidateList.toArray(new Method[0]);
// 将匹配的方法进行排序,public 方法优先,入参个数多的优先
AutowireUtils.sortFactoryMethods(candidates);
// 用于承载解析后的方法参数值
ConstructorArgumentValues resolvedValues = null;
// 是否是构造器注入
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
// 匹配方法的集合
SetambiguousFactoryMethods = null;
// -------------------------确定方法参数的入参数量-------------------------
//确定方法参数的入参数量,匹配的方法的入参数量要多余它
// 方法的参数数量的最小值
int minNrOfArgs;
//如果当前方法指定了入参,则使用其个数作为最小值
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
//否则,从 RootBeanDefinition 解析出方法的参数个数作为最小值
else {
// We don't have arguments passed in programmatically, so we need to resolve the
// arguments specified in the constructor arguments held in the bean definition.
// RootBeanDefinition 定义了参数值
if (mbd.hasConstructorArgumentValues()) {
// 方法的参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析定义的参数值,放入 `resolvedValues` 中,并返回参数个数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
minNrOfArgs = 0;
}
}
// 记录 UnsatisfiedDependencyException 异常的集合
LinkedListcauses = null;
:::warning
这一步会找到这个方法的入参,依赖注入的方式
:::
// -------------------------根据权重获取最匹配的方法-------------------------
//因为会遍历所有匹配的方法,所以需要进行权重的判断,拿到最优先的那个
// 判断解析构造函数的时候是否以宽松模式还是严格模式,默认为 true
// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
// 宽松模式:使用具有"最接近的模式"进行匹配
// typeDiffWeight:类型差异权重
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this factory method if it represents the closest match.
// 代表最匹配的结果,则选择作为符合条件的方法
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
// Find out about ambiguity: In case of the same type difference weight
// for methods with the same number of parameters, collect such candidates
// and eventually raise an ambiguity exception.
// However, only perform that check in non-lenient constructor resolution mode,
// and explicitly ignore overridden methods (with the same parameter signature).
// 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项
// 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写方法(具有相同的参数签名)
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterCount() &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
// 查找到多个可匹配的方法
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<>();
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
会缓存这几个数据:resolvedConstructorOrFactoryMethod(已经解析出来的工厂方法)、constructorArgumentsResolved(方法入参已经解析出来了 true)、resolvedConstructorArguments(解析出来的入参)
//没有找到对应的工厂方法,则抛出异常
if (factoryMethodToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
ListargTypes = new ArrayList<>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else if (resolvedValues != null) {
SetvalueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
//将解析出来的工厂方法和入参缓存,设置到 RootBeanDefinition 中,因为整个过程比较复杂,避免再次解析
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
Assert.state(argsToUse != null, "Unresolved factory method arguments");
//调用工厂方法创建一个实例对象(反射机制),并设置到 `bw` 中
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;
上面整个过程非常复杂,这里进行简单概括:
当你用构造函数的方法创建一个Bean时,所有普通的类都可以被Spring使用并与之兼容。也就是说,被开发的类不需要实现任何特定的接口,也不需要以特定的方式进行编码。只需指定Bean类就足够了。然而,根据你对该特定Bean使用的IoC类型,你可能需要一个默认(空)构造函数。
package com.shu.pojo;
/**
* @description:
* @author: shu
* @createDate: 2023/7/20 23:34
* @version: 1.0
*/
public class User {
private String name;
public User() {
System.out.println("User的无参构造");
}
public User(String name) {
this.name = name;
System.out.println("User的有参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("User的setName方法");
}
public void show() {
System.out.println("name=" + name);
}
}
<!-- 无参构造 -->
<bean id="user" class="com.shu.pojo.User"/>
/**
* 构造函数实例化bean
*/
@Test
public void test6(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
user.show();
}
有参构造
介绍有参构造之前我们需要了解依赖注入的概念?
基于构造函数的 DI 是通过容器调用带有许多参数的构造函数来完成的,每个参数代表一个依赖。
<!-- 有参构造 -->
<bean id="user2" class="com.shu.pojo.User">
<constructor-arg name="name" value="shu"/>
</bean>
package com.shu.pojo;
/**
* @description:
* @author: shu
* @createDate: 2023/7/20 23:34
* @version: 1.0
*/
public class User {
private String name;
public User() {
System.out.println("User的无参构造");
}
public User(String name) {
this.name = name;
System.out.println("User的有参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("User的setName方法");
}
public void show() {
System.out.println("name=" + name);
}
}
基于 Setter 的 DI 是通过容器在调用无参数的构造函数或无参数的 static 工厂方法来实例化你的 bean 之后调用 Setter 方法来实现的。简单来说就是调用了你的set发放,完成赋值,这也决定我们需要编写Set方法的实现,当然这也是我们Spring中常用的实例化
<bean id="user" class="com.shu.pojo.User">
<property name="name" value="shu"/>
</bean>
下面我们来具体看看代码部分
AbstractAutowireCapableBeanFactory
// ========= 构造器实例化 =========
// 4. 快速实例化对象,所谓的快速实例化,实际上是说使用缓存
boolean resolved = false;
boolean autowireNecessary = false;
// 4.1 args: 外部化参数,只能当无外部参数时才使用缓存。不推荐使用外部化参数
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 4.2 是否使用缓存,其中autowireNecessary表示是否使用有参构造器
// 无参时肯定不会解析,为false。有参时会解析,为true
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 4.3 使用缓存,其中autowireNecessary表示是否使用有参构造器
if (resolved) {
if (autowireNecessary) {
// 4.4 有参构造器实例化
return autowireConstructor(beanName, mbd, null, null);
} else {
// 4.5 无参构造器实例化
return instantiateBean(beanName, mbd);
}
}
// 5. 到此,只能老老实实的解析,当然解析后会将解析后的构造器或参数缓存起来
// 5.1 是否指定了构造器,ibp#determineCandidateConstructors
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 5.2 构造器实例化
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 5.3 不用管,默认都是 null。
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 5.4 无参构造器实例化
return instantiateBean(beanName, mbd);
}
我们可以看到上面代码的两个关键方法有参实例化与无参实例化
这个过程和上一个方法一样非常复杂,不过差不太多,你可以理解为去找到当前 Bean 的构造方法,获取相关入参(构造器注入),然后调用该构造方法返回一个实例对象(反射机制)
AbstractAutowireCapableBeanFactory
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
创建 ConstructorResolver 对象,然后调用其 autowireConstructor(…) 方法
ConstructorResolver
// ConstructorResolver.java
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor[] chosenCtors, @Nullable Object[] explicitArgs) {
// 构造 BeanWrapperImpl 对象
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化 BeanWrapperImpl,设置 ConversionService 类型转换器,并注册自定义的属性编辑器
this.beanFactory.initBeanWrapper(bw);
// -------------------------尝试获取构造方法和入参-------------------------
//尝试获取构造方法和入参
// 构造方法
Constructor constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
// 构造方法的入参集合
Object[] argsToUse = null;
//如果当前方法入参指定了参数,则直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
//否则,尝试从 RootBeanDefinition 中获取已解析出来的构造方法和入参
else {
// 因为可能前面解析了,会临时缓存,避免再次解析
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
// 如果构造方法被解析了,那么参数也可能解析过
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 没有解析过的参数,则尝试从 RootBeanDefinition(合并后)中获取未被解析过的参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果获取到了未被解析过的入参
if (argsToResolve != null) {
// 处理参数值,类型转换,例如给定方法 A(int, int),配配置了 A("1"、"2") 两个参数,则会转换为 A(1, 1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// -------------------------开始获取构造方法和入参-------------------------
//如果上一步没有找到构造方法或入参集合,找到所有匹配的工厂方法,首先找到所有匹配的构造方法
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
//获取所有的构造方法,如果当前方法指定了构造方法的集合,则使用这个集合
Constructor[] candidates = chosenCtors;
if (candidates == null) {
Class beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
//如果构造方法只有一个,且当前方法的入参没有指定参数,且本身也没有定义参数,且这个构造方法没有定义入参
// 则直接调用这个构造方法创建一个实例对象(反射机制),并返回
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Constructor uniqueCandidate = candidates[0];
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// Need to resolve the constructor.
// 是否是构造器注入
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
// 用于承载解析后的方法参数值
ConstructorArgumentValues resolvedValues = null;
// -------------------------确定构造方法的入参数量-------------------------
//确定构造参数的入参数量,匹配的方法的入参数量要多余它
// 方法的参数数量的最小值
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
// 从 RootBeanDefinition 解析出方法的参数个数作为最小值
else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
//将所有的构造方法进行排序,public 方法优先,入参个数多的优先
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor> ambiguousConstructors = null;
LinkedListcauses = null;
// 遍历所有构造函数
for (Constructor candidate : candidates) {
// 获取该构造方法的参数类型
Class[] paramTypes = candidate.getParameterTypes();
// 如果前面已经找到匹配的构造方法和入参,则直接结束循环
if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
// 如果这个构造方法的参数个数小于入参数量,则跳过
if (paramTypes.length < minNrOfArgs) {
continue;
}
// -------------------------解析出构造方法的入参-------------------------
//解析出构造方法的入参
// 保存参数的对象
ArgumentsHolder argsHolder;
//通过**依赖注入**获取入参
if (resolvedValues != null) {
try {
// 获取构造方法的参数名称(@ConstructorProperties 注解)
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
// 没有获取到则通过 ParameterNameDiscoverer 参数探测器获取参数名称
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
// 解析出方法的入参,参数值会被依赖注入
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
//如果当前方法的入参指定了参数,如果个数相等则直接使用
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
// -------------------------根据权重获取最匹配的方法-------------------------
//因为会遍历所有匹配的方法,所以需要进行权重的判断,拿到最优先的那个
// 判断解析构造函数的时候是否以宽松模式还是严格模式,默认为 true
// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
// 宽松模式:使用具有"最接近的模式"进行匹配
// typeDiffWeight:类型差异权重
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
// 代表最匹配的结果,则选择作为符合条件的方法
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
//没有找到对应的构造方法,则抛出异常
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
//将解析出来的工厂方法和入参缓存,设置到 RootBeanDefinition 中,因为整个过程比较复杂,避免再次解析
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
//调用这个构造方法返回一个实例对象(反射机制),并设置到 `bw` 中
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
详细的步骤参考上面的工厂创建的解析,我们这里总结一下’
上**面整个过程非常复杂,这里进行简单概括:**
兜底方法,如果构造方法找不到(或者已经解析出来的构造方法),则直接使用默认的构造方法(或者已经解析出来的构造方法),返回一个实例对象
AbstractAutowireCapableBeanFactory
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
// 安全模式
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction) () ->
// 获得 InstantiationStrategy 对象,并使用它,创建 Bean 对象
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
// 获得 InstantiationStrategy 对象,并使用它,创建 Bean 对象
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
可以看到会通过 CglibSubclassingInstantiationStrategy#instantiate(…) 方法创建一个实例对象,该方法如下
SimpleInstantiationStrategy
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
//没有 MethodOverride 对象,也就是没有需要覆盖或替换的方法,则直接使用反射机制进行实例化即可
if (!bd.hasMethodOverrides()) {
Constructor constructorToUse;
synchronized (bd.constructorArgumentLock) {
//尝试从 RootBeanDefinition 获得已经解析出来的构造方法 `resolvedConstructorOrFactoryMethod`
constructorToUse = (Constructor) bd.resolvedConstructorOrFactoryMethod;
//没有解析出来的构造方法,则获取默认的构造方法
if (constructorToUse == null) {
final Class clazz = bd.getBeanClass();
// 如果是接口,抛出 BeanInstantiationException 异常
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
// 从 clazz 中,获得构造方法
if (System.getSecurityManager() != null) {
// 安全模式
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
// 标记 resolvedConstructorOrFactoryMethod 属性
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//通过这个构造方法实例化一个对象(反射机制)
return BeanUtils.instantiateClass(constructorToUse);
}
//否则,通过 CGLIB 生成一个子类对象
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
过程大致如下:
到这我们就介绍完了Bean的创建,基础知识参考:Spring 的基本介绍_长安不及十里的博客-程序员宅基地
下面回到doCreatBean方法中
AbstractAutowireCapableBeanFactory
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
找到所有实现了MergedBeanDefinitionPostProcessor的实例 ,然后访问其postProcessMergedBeanDefinition()方法。这里主要是为了后面填充Bean属性做一些前置准备。
由于篇幅原因我们下篇文章详细解决下面的流程
文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr
文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc
文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8
文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束
文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求
文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname
文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立
文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码
文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词
文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限
文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定
文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland