zl程序教程

您现在的位置是:首页 >  .Net

当前栏目

注解@Bean解析

2023-02-18 16:35:17 时间

注解@Bean 介绍

  1)@Bean:Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中;

  2)SpringIOC 容器管理一个或者多个bean,这些bean都需要在@Configuration注解下进行创建,在一个方法上使用@Bean注解就表明这个方法需要交给Spring进行管理;

  3)@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。添加的bean的id为方法名;

  4)使用Bean时,即是把已经在xml文件中配置好的Bean拿来用,完成属性、方法的组装;比如@Autowired , @Resource,可以通过byTYPE(@Autowired)、byNAME(@Resource)的方式获取Bean;

  5)注册Bean时,@Component , @Repository , @ Controller , @Service , @Configration这些注解都是把你要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,它会和上面的@Autowired , @Resource配合到一起,把对象、属性、方法完美组装;

  6)@Configuration与@Bean结合使用:@Configuration可理解为用spring的时候xml里面的标签,@Bean可理解为用spring的时候xml里面的标签;

 

注解@Bean 基本构成

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {

    name属性的别名,在不需要其他属性时使用,也就是说value 就是默认值。
    @AliasFor("name")
    String[] value() default {};

    //此bean 的名称,或多个名称,主要的bean的名称加别名。如果未指定,则bean的名称是带注解方法的名称。如果指定了,方法的名称就会忽略,如果没有其他属性声明的话,bean的名称和别名可能通过value属性配置
    @AliasFor("value")
    String[] name() default {};

    //等同于xml中bean的autowire熟悉,不推荐使用此属性。
    @Deprecated
    Autowire autowire() default Autowire.NO;

    //等同于xml中bean标签的autowire-candidate属性。
    boolean autowireCandidate() default true;

    //在初始化期间对bean实例调用的方法的可选名称。不常用,因为该方法可以直接在Bean注释方法的主体中以编程方式调用。等同于xml bean标签中的init-method属性。
    String initMethod() default "";

    //等同于xml bean中的destory方法。
    String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;

}

 

注解@Bean的情况说明

  0.示例展示

@Configuration
public class AppConfig {

    @Bean
    public UserService userService() {
        return new UserService();
    }

}

 

  1.首先,Spring会把@Bean修饰的方法解析成BeanDefinition:

    1)如果方法不是static的,那么解析出来的BeanDefinition中:

      (1)factoryBeanName为AppConfig所对应的beanName,比如"appConfig"

      (2)factoryMethodName为对应的方法名,比如"aService"

      (3)factoryClass为AppConfig.class

    2)如果方法是static的,那么解析出来的BeanDefinition中:

      (1)factoryBeanName为null

      (2)factoryMethodName为对应的方法名,比如"aService"

      (3)factoryClass也为AppConfig.class

 

  2.在由@Bean生成的BeanDefinition中,有一个重要的属性isFactoryMethodUnique,表示 factoryMethod是不是唯一的,在普通情况下@Bean生成的BeanDefinition的 isFactoryMethodUnique为true,但是如果出现了方法重载,那么就是特殊的情况,比如

@Bean
public static AService aService(){
    return new AService();
}

@Bean
public AService aService(BService bService){
    return new AService();
}

 

  3.虽然有两个@Bean,但是肯定只会生成一个aService的Bean,那么Spring在处理@Bean时,也只会生成一个aService的BeanDefinition,比如Spring先解析到第一个@Bean,会生成一个BeanDefinition,此时isFactoryMethodUnique为true,但是解析到第二个@Bean时,会判断出来beanDefinitionMap中已经存在一个aService的BeanDefinition了,那么会把之前的这个BeanDefinition的isFactoryMethodUnique修改为false,并且不会生成新的BeanDefinition了。

  4.并且后续在根据BeanDefinition创建Bean时,会根据isFactoryMethodUnique来操作,如果为true,那就表示当前BeanDefinition只对应了一个方法,那也就是只能用这个方法来创建Bean了,但是如果isFactoryMethodUnique为false,那就表示当前BeanDefition对应了多个方法,需要和推断构造方法的逻辑一样,去选择用哪个方法来创建Bean。

 

注解@Bean 在哪里产生作用

  1.它是在哪里被设置的【包括一些其他属性其实都会在扫描流程中填充好】:在AbstractApplicationContext类#refresh方法#invokeBeanFactoryPostProcessors(beanFactory);流程中,展示:

    ConfigurationClassParser类#doProcessConfigurationClass方法

// 解析配置类中的@Bean,但并没有真正处理@Bean,只是暂时找出来
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
    configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

// 解析配置类所实现的接口中的@Bean,但并没有真正处理@Bean,只是暂时找出来
processInterfaces(configClass, sourceClass);

 

 

 

  2.产生作用的地方位于实例化步骤【doCreateBean方法的createBeanInstance(beanName, mbd, args),进入createBeanInstance】:

// @Bean对应的BeanDefinition
if (mbd.getFactoryMethodName() != null) {
    return instantiateUsingFactoryMethod(beanName, mbd, args);
}

 

  3.分析instantiateUsingFactoryMethod方法

protected BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
    // 使用factoryBean来实例化对象
    return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

//ConstructorResolver类#instantiateUsingFactoryMethod方法
//省略日志与异常
public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);

    Object factoryBean;
    Class<?> factoryClass;
    boolean isStatic;

    //通过beanDefinition获取到factoryBeanName ,实际就是@Bean注解的方法所在的configuration类
    String factoryBeanName = mbd.getFactoryBeanName();
    //表示非静态方法
    if (factoryBeanName != null) {
        if (factoryBeanName.equals(beanName)) {
            throw new BeanDefinitionStoreException(...);
        }
        factoryBean = this.beanFactory.getBean(factoryBeanName);

        // 该mbd已经创建过了【代表这个逻辑已经走过了】
        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.
        if (!mbd.hasBeanClass()) {
            throw new BeanDefinitionStoreException(...);
        }
        factoryBean = null;
        factoryClass = mbd.getBeanClass();
        isStatic = true;
    }

    Method factoryMethodToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;

    //如果在调用getBean方法时有传参,那就用传的参作为@Bean注解的方法(工厂方法)的参数, 一般懒加载的bean才会传参,启动过程就实例化的实际上都没有传参
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    else {
        Object[] argsToResolve = null;
        synchronized (mbd.constructorArgumentLock) {
            factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
            //不为空表示已经使用过工厂方法,现在是再次使用工厂方法, 一般原型模式和Scope模式采用的上,直接使用该工厂方法和缓存的参数
            if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
                // Found a cached factory method...
                argsToUse = mbd.resolvedConstructorArguments;
                if (argsToUse == null) {
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        if (argsToResolve != null) {
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
        }
    }

    // 调用getBean方法没有传参,同时也是第一次使用工厂方法
    if (factoryMethodToUse == null || argsToUse == null) {
        
        factoryClass = ClassUtils.getUserClass(factoryClass);

        // 获取configuration类的所有候选方法
        Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
        List<Method> candidateList = new ArrayList<>();
        for (Method candidate : rawCandidates) {
            // 查找到与工厂方法同名的候选方法,即有@Bean的同名方法
            if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                candidateList.add(candidate);
            }
        }

        //当与工厂方法同名的候选方法只有一个,且调用getBean方法时没有传参,且没有缓存过参数,直接通过调用实例化方法执行该候选方法
        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;
        Set<Method> ambiguousFactoryMethods = null;

        int minNrOfArgs;
        // 如果调用getBean方法时有传参,那么工厂方法最少参数个数要等于传参个数
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        else {
            //如果getBean的时候没有传参,如果BeanDefinition中有设置,则从BeanDefinition中获取
            if (mbd.hasConstructorArgumentValues()) {
                ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                resolvedValues = new ConstructorArgumentValues();
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }
            else {
                minNrOfArgs = 0;
            }
        }

        LinkedList<UnsatisfiedDependencyException> causes = 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;
                    }
                    argsHolder = new ArgumentsHolder(explicitArgs);
                }
                else {
                    // Resolved constructor arguments: type conversion and/or autowiring necessary.
                    try {
                        String[] paramNames = null;
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        if (pnd != null) {
                            paramNames = pnd.getParameterNames(candidate);
                        }
                        //当传入的参数为空,需要根据工厂方法的参数类型注入相应的bean
                        argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
                    }
                    catch (UnsatisfiedDependencyException ex) {
                        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;
                    }
                }

                //计算工厂方法的权重
                int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                        argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                // Choose this factory method if it represents the closest match.
                if (typeDiffWeight < minTypeDiffWeight) {
                    /*
                    * 当权重小时,重新设置factoryMethodToUse 和argsHolderToUse ,argsToUse ,
                    * 并把当前权重值设置为最小权重值,等待遍历的下一个候选工厂方法比对,
                    * 并且将ambiguousFactoryMethods (表示有含糊同样权重的候选方法)设置为空
                    * */
                    factoryMethodToUse = candidate;
                    argsHolderToUse = argsHolder;
                    argsToUse = argsHolder.arguments;
                    minTypeDiffWeight = typeDiffWeight;
                    ambiguousFactoryMethods = null;
                }

                /*
                * 当遍历到下一个候选方法的时候,已经设置了factoryMethodToUse 且权重值与上一次的最小权重值相等时,
                * ambiguousFactoryMethods填值,这个ambiguousFactoryMethods不为空表示有两个候选方法的最小权重相等,
                * spring无法匹配出最适合的工厂方法,如果再继续往下遍历候选器,有更小的权重值,
                * 那ambiguousFactoryMethods会再次被设置为空
                * */
                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;
            }
            List<String> argTypes = new ArrayList<>(minNrOfArgs);
            if (explicitArgs != null) {
                for (Object arg : explicitArgs) {
                    argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
                }
            }
            else if (resolvedValues != null) {
                Set<ValueHolder> valueHolders = 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(...);
        }
        //返回类型不能为void
        else if (void.class == factoryMethodToUse.getReturnType()) {
            throw new BeanCreationException(...);
        }
        //存在含糊的两个工厂方法,不知选哪个
        else if (ambiguousFactoryMethods != null) {
            throw new BeanCreationException(...);
        }

        if (explicitArgs == null && argsHolderToUse != null) {
            mbd.factoryMethodToIntrospect = factoryMethodToUse;
            argsHolderToUse.storeCache(mbd, factoryMethodToUse);
        }
    }

    //去实例化
    bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
    return bw;
}