@Autowired原理详解 :标识构造函数

在一个类中定义一个属性,正常情况下需要在此类中有对此属性赋值的代码,如setter方法,或者在构造函数中赋值,因此类和属性之间的关系已经确定下来了,类和属性间就有了一定的耦合关系。而IOC的精髓就是解耦,类中没有显式的对属性的赋值代码,同时属性的实际类型和值在运行时有系统动态的赋值,Spring对IOC做了很大的扩展,使用者可以很灵活的控制注入的对象类型及值。

Spring内IOC的最直接体现就是@Autowired注解,最常用的方式就是表示在属性上,Spring容器在启动时会将容器内类型是标识了@Autowired的属性类型或者其子类,实现类的Bean通过反射的形式赋值给此属性,或者叫注入的此类中。

Spring中对@Autowired注解的解析是通过一个叫AutowiredAnnotationBeanPostProcessor的BeanPostProcessor(Bean的后处理器)来进行的。BeanPostProcessor负责Bean的一系列处理,实例化前后,初始化前后灯阶段执行相应方法,具体方法的执行顺序如下:


BeanPostPrecessors Invoke Procedure(执行流程)1.InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(Class beanClass, String beanName);invoke before doCreateBean(),if the method returns not null,the return Object will as the Bean, avoid invoke doCreateBean() ;2.SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors(Class beanClass, String beanName);used to determine to use which Constructor to instance Bean;3.MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName);the Bean gets instantiated, modify the RootBeanDefinition ,such as adding PropertyValue etc. before populate Bean;4.SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference(Object bean, String beanName);invoke before populate Bean,used for resolve Circular Reference;5.InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Object bean, String beanName);invoke in populate Bean, but before fill in values,return false will break the opreation for filling values in Bean;6.InstantiationAwareBeanPostProcessor.postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName);invoke in populate Bean, but before fill in values,modify the PropertyValues which will be apply for the Bean,
return null will break the opreation for filling values in Bean;7.BeanPostProcessor.postProcessBeforeInitialization(Object bean, String beanName);invoked before invokeInitMethods, modify the finally Bean instance8.BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName);invoked after invokeInitMethods, modify the finally Bean instance

使用者可以自己定义自己的BeanPostProcessor,将其以Bean的形式注册到Spring容器中,Spring容器在启动时会执行其相应方法。

AutowiredAnnotationBeanPostProcessor在Spring容器初始化时会最先执行determineCandidateConstructors方法,先看起源码:

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapterimplements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {//此方法的含义是解析Bean类里构造函数上的@Autowired注解,如果有合适的标识了@Autowired的构造函数,//则在实例化此Bean时会使用此构造函数,@Import和@ComponentScan得到的Bean会如此解析,//@Bean标识方法生成的Bean不会如此public Constructor[] determineCandidateConstructors(Class beanClass, final String beanName)throws BeanCreationException {// Let's check for lookup methods here..if (!this.lookupMethodsChecked.contains(beanName)) {try {ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {@Overridepublic void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {Lookup lookup = method.getAnnotation(Lookup.class);if (lookup != null) {LookupOverride override = new LookupOverride(method, lookup.value());try {RootBeanDefinition mbd = (RootBeanDefinition) beanFactory.getMergedBeanDefinition(beanName);mbd.getMethodOverrides().addOverride(override);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(beanName,"Cannot apply @Lookup to beans without corresponding bean definition");}}}});}catch (IllegalStateException ex) {throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);}catch (NoClassDefFoundError err) {throw new BeanCreationException(beanName, "Failed to introspect bean class [" + beanClass.getName() +"] for lookup method metadata: could not find class that it depends on", err);}this.lookupMethodsChecked.add(beanName);}// Quick check on the concurrent map first, with minimal locking.Constructor[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {// Fully synchronized resolution now...synchronized (this.candidateConstructorsCache) {//对每个类的构造函数只解析一次,解析完会存储结果,以备下次服用candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {Constructor[] rawCandidates;try {rawCandidates = beanClass.getDeclaredConstructors();}catch (Throwable ex) {throw new BeanCreationException(beanName,"Resolution of declared constructors on bean Class [" + beanClass.getName() +"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);}List> candidates = new ArrayList>(rawCandidates.length);Constructor requiredConstructor = null;Constructor defaultConstructor = null;for (Constructor candidate : rawCandidates) {//查看构造函数上是否标识@Autowired注解,获取注解的属性AnnotationAttributes ann = findAutowiredAnnotation(candidate);if (ann == null) {Class userClass = ClassUtils.getUserClass(beanClass);if (userClass != beanClass) {try {Constructor superCtor =userClass.getDeclaredConstructor(candidate.getParameterTypes());//如果此构造函数是重载了父类的构造函数,则寻找父类的构造函数,查看是否标识@Autowired注解,获取注解的属性ann = findAutowiredAnnotation(superCtor);}catch (NoSuchMethodException ex) {// Simply proceed, no equivalent superclass constructor found...}}}//当构造函数上存在@Autowired注解if (ann != null) {//@Autowired默认的required = true,当有一个required = true的@Autowired标识的构造函数时,//不能有其他的构造函数再标识@Autowired,否则会报错if (requiredConstructor != null) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructor: " + candidate +". Found constructor with 'required' Autowired annotation already: " +requiredConstructor);}//@Autowired的required的属性值,true / falseboolean required = determineRequiredStatus(ann);if (required) {if (!candidates.isEmpty()) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructors: " + candidates +". Found constructor with 'required' Autowired annotation: " +candidate);}requiredConstructor = candidate;}candidates.add(candidate);} else if (candidate.getParameterTypes().length == 0) {defaultConstructor = candidate;}}if (!candidates.isEmpty()) {// Add default constructor to list of optional constructors, as fallback.当没有构造函数标识@Autowired时,设置默认的构造函数作为额外选择if (requiredConstructor == null) {if (defaultConstructor != null) {candidates.add(defaultConstructor);}  //如果没有默认的无参构造函数,且有@Autowired(required = false)的构造函数,则发出警告信else if (candidates.size() == 1 && logger.isWarnEnabled()) {logger.warn("Inconsistent constructor declaration on bean with name '" + beanName +"': single autowire-marked constructor flagged as optional - " +"this constructor is effectively required since there is no " +"default constructor to fall back to: " + candidates.get(0));}}candidateConstructors = candidates.toArray(new Constructor[candidates.size()]);}  //若只有一个构造函数,且没标识@Autowired,其参数长度>0,将其作为候选者else if (rawCandidates.length == 1 && rawCandidates[0].getParameterTypes().length > 0) {candidateConstructors = new Constructor[] {rawCandidates[0]};} //没有合适的构造函数else {candidateConstructors = new Constructor[0];}this.candidateConstructorsCache.put(beanClass, candidateConstructors);}}}return (candidateConstructors.length > 0 ? candidateConstructors : null);}}

AutowiredAnnotationBeanPostProcessor筛选@Autowired标识的构造函数的代码就是这些,筛选出这些构造函数之后,Spring使用ConstructorResolver这个类来择取合适的构造函数,流程如下:

  1. 首先对这些构造函数按修饰符优先public排序,修饰符相同再按参数的长短排序,最先解析参数最长的public修饰的构造函数,其优先级最高.
  2. 对构造函数的每一个参数解析,如果每一个参数均能从Spring容器中找到合适的Bean,则此将此构造函数作为最优解,如果容器内Bean不能满足所有参数,则解析下一个构造函数。
  3. 如果存在两个参数长度相同的构造函数,且容器内Bean均能满足参数解析,则按参数类型和Bean类型的差异性求取参数的差异权重,比如参数是接口,Bean是实现类,则差异加2,参数是集合,Bean是单个类,则转换成集合,差异加2等等,比较两个构造函数的差异权重大小,差异小的那个作为最优解。如果两个差异权重相等,则抛出含有模棱两可的构造函数的BeanCreationException。
  4. 当有了最优解的构造函数后,如果下一个构造函数的参数长度等于最优解,则解析此构造函数,如果参数长度小于最优解,则不再解析,直接忽略之后的所有构造函数。
  5. 当得到了构造函数最优解之后,将此构造函数存入此Bean的BeanDefinition中,以备下次复用,就是说只对构造函数候选者集合解析一次,下次实例化Bean的时候可以直接得到这个最优解。
  6. 以上的情况是基于Spring容器实例化Bean的情况,就是实例化时不会附带Arguments,就是不带参数,如果是使用者自己实例化Bean时,通过BeanFactory的 Object getBean(String name, Object… args) throws BeansException; T getBean(Class requiredType, Object… args) throws BeansException;方法实例化时,按照构造函数的顺序传入实例化参数,则Spring在找合适的构造函数时会忽略之前缓存的最优解,以同样的顺序解析构造函数候选者集合,看看哪些构造函数的参数适合传入的参数,找不到合适的则跑出BeanCreationException。

以上就是@Autowired注解在构造函数上的用法的原理及流程。

重点: BeanFactory的getBean()方法获取scope = singleton的Bean时,不会生成新的Bean对象, 
在scope为request及session的生命周期内,Bean的实例化只会触发一次,也就是说@Autowired的标识的构造函数不是每次调用getBean()均会触发执行。只有scope = prototype的Bean,才会每次均执行。

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部