注解@Bean解析
注解@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; }