当前位置: 首页 > news >正文

深圳网站设计必选成都柚米科技09做移动登录网页模板免费下载

深圳网站设计必选成都柚米科技09做,移动登录网页模板免费下载,宝塔面板wordpress安装,网站建设psd模板前言 源码在我github的guide-spring仓库中#xff0c;可以克隆下来 直接执行。 我们本文主要来介绍依赖注入的使用示例及其原理 依赖注入 什么是依赖注入 依赖注入#xff08;Dependency Injection#xff0c;简称DI#xff09;是一种设计模式#xff0c;它用于实现对…前言 源码在我github的guide-spring仓库中可以克隆下来 直接执行。 我们本文主要来介绍依赖注入的使用示例及其原理 依赖注入 什么是依赖注入 依赖注入Dependency Injection简称DI是一种设计模式它用于实现对象之间的松散耦合。在依赖注入中一个对象不再负责创建或查找它所依赖的对象而是将这些依赖关系通过外部传递进来外部指的就是 IoC 容器IoC 容器负责对象的创建、管理和注入我们也常说 DI 是实现 IoC 的一种具体技术。这种方式有助于提高代码的可维护性、可测试性同时降低了组件之间的耦合度。 依赖注入的方式 注入的方式有以下几种 setter方法注入构造器注入字段注入方法注入接口回调注入 setter方法和构造器注入方式 其中setter方法注入和构造器注入在xml配置手动注入时比较常见使用方法可以参考下面的示例代码 xml 配置 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:utilhttp://www.springframework.org/schema/utilxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdbean iduser classcom.markus.spring.ioc.overview.domain.User!-- 属性注入 --property nameid value1/property nameusername valuemarkus zhang//beanbean iduser-by-constructor classcom.markus.spring.ioc.overview.domain.User!-- 构造器注入 --constructor-arg index0 value2/constructor-arg index1 valueluna//bean /beans Java 代码 package com.markus.spring.dependency.injection;import com.markus.spring.ioc.overview.domain.User; import org.springframework.context.support.ClassPathXmlApplicationContext;/*** author: markus* date: 2023/12/24 10:57 AM* Description: setter方法和构造器注入 示例* Blog: https://markuszhang.com* Its my honor to share what Ive learned with you!*/ public class SetterAndConstructorInjectionDemo {public static void main(String[] args) {ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(classpath:/META-INF/dependency-inject.xml);User user context.getBean(user, User.class);System.out.println(user);User userByConstructor context.getBean(user-by-constructor, User.class);System.out.println(userByConstructor);context.close();} }控制台 接口回调注入 字段和方法注入的方式我们放在下面的自动绑定来说。接下来先把接口回调的注入方式介绍一下。 准备一个Java Bean 我们在原本 User 这个 Java Bean 的基础上让其实现 BeanNameAware 接口并重写其 setBeanName 方法这样就可以在 IoC 创建该 Bean 的时候完成 beanName 属性值的回调注入。 package com.markus.spring.ioc.overview.domain;import org.springframework.beans.factory.BeanNameAware;import javax.annotation.PostConstruct; import javax.annotation.PreDestroy;/*** Author: zhangchenglong06* Date: 2023/11/27* Description:*/ public class User implements BeanNameAware {private Long id;private String username;private String beanName;public User() {System.out.println(开始初始化);}public User(Long id, String username) {this.id id;this.username username;}Overridepublic void setBeanName(String name) {this.beanName name;} } 编写一个示例代码 package com.markus.spring.dependency.injection;import com.markus.spring.ioc.overview.domain.User; import org.springframework.context.support.ClassPathXmlApplicationContext;/*** author: markus* date: 2023/12/24 11:06 AM* Description: 接口回调注入 示例* Blog: https://markuszhang.com* Its my honor to share what Ive learned with you!*/ public class InterfaceCallbackInjectionDemo {public static void main(String[] args) {ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(classpath:/META-INF/dependency-inject.xml);User user context.getBean(user, User.class);System.out.println(User Bean Name is [ user.getBeanName() ]);context.close();} }控制台 手动注入的弊端 前面我们了解通过属性注入、构造器注入的使用方式看似比较简单、方便但试想如果有注入集合场景的时候我们通过手动注入应该如何实现呢下面来掩饰一下 xml配置 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:utilhttp://www.springframework.org/schema/utilxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdbean iduser classcom.markus.spring.ioc.overview.domain.User!-- 属性注入 --property nameid value1/property nameusername valuemarkus zhang//beanbean iduser-by-constructor classcom.markus.spring.ioc.overview.domain.User!-- 构造器注入 --constructor-arg index0 value2/constructor-arg index1 valueluna//beanbean iduser-list-holder classcom.markus.spring.ioc.overview.domain.UserListHolderproperty nameuserslistref beanuser/ref beanuser-by-constructor/!-- 依次增加 --/list/property/bean /beans 示例代码 package com.markus.spring.dependency.injection;import com.markus.spring.ioc.overview.domain.User; import com.markus.spring.ioc.overview.domain.UserListHolder; import org.springframework.context.support.ClassPathXmlApplicationContext;/*** author: markus* date: 2023/12/24 10:57 AM* Description: setter方法和构造器注入 示例* Blog: https://markuszhang.com* Its my honor to share what Ive learned with you!*/ public class SetterAndConstructorInjectionDemo {public static void main(String[] args) {ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(classpath:/META-INF/dependency-inject.xml);UserListHolder userListHolder context.getBean(user-list-holder, UserListHolder.class);System.out.println(userListHolder);context.close();} } 控制台 我们的目的就是将容器中的所有 User 类型的 Bean 注入到 UserListHolder 中试想如果容器中不断的增加新的 User 类型的 Bean那么通过手动注入的方式则会每次都需要去修改 UserListHolder 这个 Bean这非常的不便下面我们就来介绍下 Spring 框架提供的 自动绑定Autowiring特性。 自动绑定 使用和优点 我们先来看下官方对于自动绑定的说明原文链接 上面解释了自动装配的功能以及其优势和自动绑定的方式。大致意思是说Spring IoC 容器可以自动绑定协作 Bean 之间的关系。我们可以让 Spring 通过查找 ApplicationContext 中的内容将其自动解析注入到你的 Bean 中。自动装配有以下优点 自动装配可以显著减少手动配置需要的属性或者构造器的参数自动装配可以随着对象的发展自动更新配置例如如果需要向类中添加依赖项则无需修改配置即可满足该依赖项。 也给出了基于 XMl 配置元信息场景下如何使用自动绑定以及自动绑定的几种模式 no : 默认状态无自动绑定byName : 通过属性名进行自动绑定byType : 通过类型进行自动绑定constructor : 和 byType 相似不同的是 constructor 是应用与构造器参数上 我们回到上面在手动注入的弊端中所提到的例子我们通过自动绑定稍加改造即可完成即便容器中增加多少或者删除多少 User 类型的 Bean 配置都不需要更改 UserListHolder 的配置完成其内容的自动更新。 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:utilhttp://www.springframework.org/schema/utilxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdbean iduser classcom.markus.spring.ioc.overview.domain.User!-- 属性注入 --property nameid value1/property nameusername valuemarkus zhang//beanbean iduser-by-constructor classcom.markus.spring.ioc.overview.domain.User!-- 构造器注入 --constructor-arg index0 value2/constructor-arg index1 valueluna//beanbean iduser-list-holder classcom.markus.spring.ioc.overview.domain.UserListHolderautowirebyType !--通过类型 自动绑定-- !-- property nameusers-- !-- list-- !-- ref beanuser/-- !-- ref beanuser-by-constructor/-- !-- lt;!ndash; 依次增加 ndash;gt;-- !-- /list-- !-- /property--/bean /beans 再次执行下上面的程序依然正常执行。 我们通过自定绑定可以注入很多类型包括数组、集合、Map以及外部化配置下面我们用 Autowired 和 Value 注解完成这些功能。 package com.markus.spring.dependency.injection;import com.markus.spring.ioc.overview.domain.User; import com.markus.spring.ioc.overview.domain.UserHolder; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*;import java.util.Collection; import java.util.Map; import java.util.Optional;/*** Author: zhangchenglong06* Date: 2023/12/18* Description: Autowired 注解注入示例*/ Configuration PropertySource(classpath:/META-INF/application.properties) public class AtAutowiredAnnotationInjectionDemo {Autowiredprivate OptionalUser optionalUser;Autowiredprivate ObjectFactoryUser userObjectFactory;/*** Autowired 注入流程* 1. 先按照名称查找* 2. 再按照类型查找*/Autowiredprivate User user1;Autowiredprivate CollectionUser users;Autowiredprivate MapString, User userMap;Autowiredprivate User[] userArrays;private User userFromMethodInjection;Autowiredpublic void setUserFromMethodInjection(User user) {this.userFromMethodInjection user;}Autowiredprivate UserHolder userHolder;Value(${my_site})private String mySite;public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();context.register(AtAutowiredAnnotationInjectionDemo.class);context.refresh();AtAutowiredAnnotationInjectionDemo demo context.getBean(AtAutowiredAnnotationInjectionDemo.class);System.out.println(demo.optionalUser : demo.optionalUser.get());System.out.println(demo.userObjectFactory : demo.userObjectFactory.getObject());System.out.println(demo.user : demo.user1);System.out.println(demo.users : demo.users);System.out.println(demo.userMap : demo.userMap);System.out.print(demo.userArrays : [ );for (User userArray : demo.userArrays) {System.out.print(userArray.getBeanName() );}System.out.println(]);System.out.println(demo.userFromMethodInjection : demo.userFromMethodInjection);System.out.println(demo.userHolder : demo.userHolder);System.out.println(demo.mySite : demo.mySite);context.close();}Bean(user1)public User user1() {User user new User();user.setId(1L);user.setUsername(Markus Zhang);return user;}Bean(user2)Primarypublic User user2() {User user new User();user.setId(2L);user.setUsername(Luna);return user;}Beanpublic UserHolder userHolder(Autowired User user) {UserHolder userHolder new UserHolder();userHolder.setUser(user);return userHolder;} } 我们来看下控制台 缺点 一项技术的落地有它顺应时代的诉求也一定会有它的局限性我们通过官网来叙述下 自动绑定Autowiring 有什么限制或者缺点原文链接 上面大概描述了 自动绑定的缺点和官方给你的建议 缺点 显示注入比自动绑定优先级更高它总会覆盖自动绑定的属性不能注入简单属性例如原语类型 String、int等这是框架设计的限制(ps: 不过这些类型我们可以通过 Value 实现前面给出了例子)自动绑定没有显示绑定精确尽管 Spring 已经很小心地处理以避免歧义但还是会有意想不到的结果绑定信息不会以可视化的形式展示出来多个 BeanDefinition 的情况下在注入 集合、数组、Map等场景时问题不大但是在注入单个 Bean 时可能会产生问题如果 Spring 在进行注入时找不到唯一 Bean 则会抛出异常 建议 避免使用自动绑定采用显示绑定如果某个 Bean 不想被注入到其他 Bean 中则可通过 autowired-candidate 属性设置为 false 来跳过注入在注入单个 Bean 的场景中我们可以把目标 Bean 的 primary 属性设置为 true通过注解驱动实现更精细粒度的控制 依赖注入原理 Bean 生命周期 在说依赖注入前我们先来整体看下 Spring Bean 的生命周期然后再来说依赖注入发生在哪个阶段接着再去对应源码处解析其原理 上图是 Bean 整个生命周期图我们放大来看构造器注入和 setter 方法注入所在的环节: 构造器注入 我们把 Spring 源码拷贝出来: // org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Nullable Object[] args) {// ... 其他流程省略// Candidate constructors for autowiring?Constructor?[] ctors determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors ! null || mbd.getResolvedAutowireMode() AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}// No special handling: simply use no-arg constructor.return instantiateBean(beanName, mbd); }可以看到 Spring 在判断是否进行 构造器注入 的条件有以下几种满足其一即可: 构造器列表不为空BeanDefinition 的 autowireMode 设置为 AUTOWIRE_CONSTRUCTORBeanDefinition 指定了构造器参数args 参数不为空ps: 这个通常为空 否则不进行特殊处理直接使用无参构造器进行实例化通过 cglib 或者 jdk 动态代理这块不进行细节介绍了。 下面我们进入到 autowireConstructor 方法看看里面做了什么: public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,Nullable Constructor?[] chosenCtors, Nullable Object[] explicitArgs) {BeanWrapperImpl bw new BeanWrapperImpl();this.beanFactory.initBeanWrapper(bw);Constructor? constructorToUse null;ArgumentsHolder argsHolderToUse null;Object[] argsToUse null;if (explicitArgs ! null) {argsToUse explicitArgs;}else {// ... 其他细节忽略// 需要去解析构造器boolean autowiring (chosenCtors ! null ||mbd.getResolvedAutowireMode() AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);ConstructorArgumentValues resolvedValues null;int minNrOfArgs;if (explicitArgs ! null) {minNrOfArgs explicitArgs.length;}else {ConstructorArgumentValues cargs mbd.getConstructorArgumentValues();resolvedValues new ConstructorArgumentValues();minNrOfArgs resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}// 以参数个数的多少对构造器进行排序顺序从多到少AutowireUtils.sortConstructors(candidates);int minTypeDiffWeight Integer.MAX_VALUE;SetConstructor? ambiguousConstructors null;LinkedListUnsatisfiedDependencyException causes null;// 遍历 构造器找到最合适的构造器进行实例化for (Constructor? candidate : candidates) {int parameterCount candidate.getParameterCount();if (constructorToUse ! null argsToUse ! null argsToUse.length parameterCount) {// 找到了最适合的构造器后面不需要再找了break;}if (parameterCount minNrOfArgs) {continue;}ArgumentsHolder argsHolder;Class?[] paramTypes candidate.getParameterTypes();if (resolvedValues ! null) {// ... 省略细节// 核心方法是解析当前候选构造器参数对应的参数值argsHolder createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring, candidates.length 1);// ... 省略细节}// ... 省略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;}// ... }// ... 省略其他细节}bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));return bw;}总结一下 获取候选构造器集合对构造器集合进行排序根据参数数量从多到少进行排序遍历构造器集合依次解析构造器的参数对应的值核心方法 createArgumentArray解析出值以后通过反射计算出类型差异权重Spring 设计出来的一个算法有兴趣的可以了解下 org.springframework.util.MethodInvoker#getTypeDifferenceWeight如果差异结果最匹配就选择这个构造器进行实例化 我们再深入到createArgumentArray方法中去看下 private ArgumentsHolder createArgumentArray(String beanName, RootBeanDefinition mbd, Nullable ConstructorArgumentValues resolvedValues,BeanWrapper bw, Class?[] paramTypes, Nullable String[] paramNames, Executable executable,boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {// ... 省略细节for (int paramIndex 0; paramIndex paramTypes.length; paramIndex) {if (valueHolder ! null) {// ... 省略细节}else {// ... 省略细节try {// 核心在这依次解析构造器中的参数值Object autowiredArgument resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);args.rawArguments[paramIndex] autowiredArgument;args.arguments[paramIndex] autowiredArgument;args.preparedArguments[paramIndex] autowiredArgumentMarker;args.resolveNecessary true;}catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);}}// ... 省略细节}// ... 省略细节return args;} 我们可以看到createArgumentArray方法中主要做的事情就是遍历构造器的参数依次解析其参数值我们再往下看一下resolveAutowiredArgument方法看下它是如何解析出具体值的。 protected Object resolveAutowiredArgument(MethodParameter param, String beanName,Nullable SetString autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {// ... 省略细节try {// 这块就是最最最最最最最核心的函数了我们在揭幕到这return this.beanFactory.resolveDependency(new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);}// ... 省略细节}可以看到 依赖注入实现原理中最最最最核心的函数 org.springframework.beans.factory.config.AutowireCapableBeanFactory#resolveDependency(xxx) 露出水面了我们这里先不深入解析点到为止。 总结一下构造器注入发生在 Bean 生命周期中 实例化 Bean 阶段也就是 createBeanInstance 函数中这个函数主要目的就是选择出 Bean 对象中最合适的构造器完成对 Bean 的实例化在选择构造器的过程中会有一步判断 用户是否选择进行构造器自动绑定的逻辑如果用户选择了构造器自动绑定那么 Spring 框架会通过反射获取该类的所有构造器选择出最适合的构造器进行实例化。而在选择构造器的过程中会对构造器的参数进行解析解析出来以后通过对比差异Spring 实现了一套类型与参数值的差异算法有兴趣的同学可以深入了解下org.springframework.util.MethodInvoker#getTypeDifferenceWeight来决定最终用来实例化的构造器。而在解析参数值时我们探究到 resolveDependency这个函数通过这个函数可以解析出来当前参数所对应的值。 构造器注入原理就如上所述了。 setter方法注入 同样我们也先把实现setter方法注入的入口函数先拷贝出来 // org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean protected void populateBean(String beanName, RootBeanDefinition mbd, Nullable BeanWrapper bw) {// ... 省略细节PropertyValues pvs (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);int resolvedAutowireMode mbd.getResolvedAutowireMode();if (resolvedAutowireMode AUTOWIRE_BY_NAME || resolvedAutowireMode AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (resolvedAutowireMode AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (resolvedAutowireMode AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}pvs newPvs;}// ... 省略细节 }我们省略其他的细节重点看下这个函数里面对于自动绑定的处理可以看到框架通过判断 BeanDefinition 的 autowiredMode 属性来决定执行 autowireByName 还是 autowireByType 函数。 autowiredByName protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {String[] propertyNames unsatisfiedNonSimpleProperties(mbd, bw);// 获取属性名for (String propertyName : propertyNames) {if (containsBean(propertyName)) {// 通过属性名称进行依赖查找Object bean getBean(propertyName);pvs.add(propertyName, bean);registerDependentBean(propertyName, beanName);if (logger.isTraceEnabled()) {logger.trace(Added autowiring by name from bean name beanName via property propertyName to bean named propertyName );}}else {if (logger.isTraceEnabled()) {logger.trace(Not autowiring property propertyName of bean beanName by name: no matching bean found);}}} }autowiredByType protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {TypeConverter converter getCustomTypeConverter();if (converter null) {converter bw;}SetString autowiredBeanNames new LinkedHashSet(4);String[] propertyNames unsatisfiedNonSimpleProperties(mbd, bw);for (String propertyName : propertyNames) {try {PropertyDescriptor pd bw.getPropertyDescriptor(propertyName);// Dont try autowiring by type for type Object: never makes sense,// even if it technically is a unsatisfied, non-simple property.if (Object.class ! pd.getPropertyType()) {MethodParameter methodParam BeanUtils.getWriteMethodParameter(pd);// Do not allow eager init for type matching in case of a prioritized post-processor.boolean eager !(bw.getWrappedInstance() instanceof PriorityOrdered);DependencyDescriptor desc new AutowireByTypeDependencyDescriptor(methodParam, eager);// 解析依赖值Object autowiredArgument resolveDependency(desc, beanName, autowiredBeanNames, converter);if (autowiredArgument ! null) {pvs.add(propertyName, autowiredArgument);}for (String autowiredBeanName : autowiredBeanNames) {registerDependentBean(autowiredBeanName, beanName);if (logger.isTraceEnabled()) {logger.trace(Autowiring by type from bean name beanName via property propertyName to bean named autowiredBeanName );}}autowiredBeanNames.clear();}}catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);}} }通过类型注入中我们也看到了这个核心函数resolveDependency通过其将属性参数值解析出来并完成注入。 总结一下setter方法注入有两种方式一是通过名称注入二是通过类型注入。在通过名称注入的方式中框架采用依赖查找完成在通过类型注入的方式中框架采用解析依赖完成。 依赖来源 前面我们解释了构造器注入和setter方法注入两种方式的原理追溯到底层我们发现两者都会通过org.springframework.beans.factory.config.AutowireCapableBeanFactory#resolveDependency(xxx)这个函数获取解析后的参数值setter方法通过名称注入的时候采用的依赖查找除外。 这里我们可以得到一个结论依赖注入的来源主要来源于 getBean(xxx) 和 resolveDependency(xxx) 两处接下来我们将深入探究这两个来源。 getBean(xxx)的来源 getBean就是依赖查找追溯getBean(xxx)的来源等价于追溯依赖查找的来源。 依赖查找的来源包括 BeanDefinition 用户配置Spring 内建 单例对象 用户使用 API 注册Spring 内建 用户配置的 BeanDefinition 元信息我们就不介绍了对于 Spring 内建 BeanDefinition 的注册如下图所示 org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 我们再来看下 Spring 内建单例对象 org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory org.springframework.context.support.AbstractApplicationContext#initMessageSource org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster org.springframework.context.support.AbstractApplicationContext#initLifecycleProcessor 最终依赖查找的来源这两项 org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinitionorg.springframework.beans.factory.config.SingletonBeanRegistry#registerSingleton resolveDependency(xxx)的来源 针对 resolveDependency 依赖来源我们直接从这个入口开始 // org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency public Object doResolveDependency(DependencyDescriptor descriptor, Nullable String beanName,Nullable SetString autowiredBeanNames, Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint ConstructorResolver.setCurrentInjectionPoint(descriptor);try {// 针对 Value 注解的使用场景例如 Value(${xxx:defaultValue})Object value getAutowireCandidateResolver().getSuggestedValue(descriptor);if (value ! null) {if (value instanceof String) {String strVal resolveEmbeddedValue((String) value);BeanDefinition bd (beanName ! null containsBean(beanName) ?getMergedBeanDefinition(beanName) : null);value evaluateBeanDefinitionString(strVal, bd);}TypeConverter converter (typeConverter ! null ? typeConverter : getTypeConverter());try {return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());}catch (UnsupportedOperationException ex) {// A custom TypeConverter which does not support TypeDescriptor resolution...return (descriptor.getField() ! null ?converter.convertIfNecessary(value, type, descriptor.getField()) :converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));}}// 解析 字段类型为 Array、Collection、Map等的场景Object multipleBeans resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);if (multipleBeans ! null) {return multipleBeans;}// 按照类型从 数据源中进行 查找MapString, Object matchingBeans findAutowireCandidates(beanName, type, descriptor);if (matchingBeans.isEmpty()) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}return null;}String autowiredBeanName;Object instanceCandidate;// 当有多个 匹配到的 Bean 情况决定选择哪个作为首选的 Bean 进行注入if (matchingBeans.size() 1) {autowiredBeanName determineAutowireCandidate(matchingBeans, descriptor);if (autowiredBeanName null) {if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);}else {// In case of an optional Collection/Map, silently ignore a non-unique case:// possibly it was meant to be an empty collection of multiple regular beans// (before 4.3 in particular when we didnt even look for collection beans).return null;}}instanceCandidate matchingBeans.get(autowiredBeanName);}else {// We have exactly one match.Map.EntryString, Object entry matchingBeans.entrySet().iterator().next();autowiredBeanName entry.getKey();instanceCandidate entry.getValue();}if (autowiredBeanNames ! null) {autowiredBeanNames.add(autowiredBeanName);}if (instanceCandidate instanceof Class) {instanceCandidate descriptor.resolveCandidate(autowiredBeanName, type, this);}Object result instanceCandidate;if (result instanceof NullBean) {if (isRequired(descriptor)) {raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);}result null;}if (!ClassUtils.isAssignableValue(type, result)) {throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());}return result;}finally {ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);} }总结一下这个函数主要做了一下事情 解析字段被 Value 标注时做一个解析并返回解析的过程是如果有显示的属性配置则采用配置值没有配置则采用默认值解析字段为数组、集合或者Map的场景从数据源中按照类型查找出来并设置到当前字段中去解析字段非上述情况时从数据源中同样按照类型查找出来并选择出首选的依赖返回。 上面说的数据源比较神秘我们就深入到 determineAutowireCandidate 方法来一探究竟解开其神秘的面纱 protected MapString, Object findAutowireCandidates(Nullable String beanName, Class? requiredType, DependencyDescriptor descriptor) {// 按照类型从容器中查找相关的候选 Bean 名称String[] candidateNames BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());MapString, Object result new LinkedHashMap(candidateNames.length);// 从 可解析依赖 中 查找是否有该 类型的 依赖如果有也被考虑进 resultfor (Map.EntryClass?, Object classObjectEntry : this.resolvableDependencies.entrySet()) {Class? autowiringType classObjectEntry.getKey();if (autowiringType.isAssignableFrom(requiredType)) {Object autowiringValue classObjectEntry.getValue();autowiringValue AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);if (requiredType.isInstance(autowiringValue)) {result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);break;}}}// 根据候选的 Bean 名称通过其 BeanDefinition 判断是否可以加入到 resultfor (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) isAutowireCandidate(candidate, descriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}// 结果为空if (result.isEmpty()) {// 判断字段不是多 Bean 的场景boolean multiple indicatesMultipleBeans(requiredType);// Consider fallback matches if the first pass failed to find anything...DependencyDescriptor fallbackDescriptor descriptor.forFallbackMatch();for (String candidate : candidateNames) {if (!isSelfReference(beanName, candidate) isAutowireCandidate(candidate, fallbackDescriptor) (!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {addCandidateEntry(result, candidate, descriptor, requiredType);}}// 还为空 并且 字段不为多 Bean 的场景if (result.isEmpty() !multiple) {// Consider self references as a final pass...// but in the case of a dependency collection, not the very same bean itself.for (String candidate : candidateNames) {if (isSelfReference(beanName, candidate) (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) isAutowireCandidate(candidate, fallbackDescriptor)) {addCandidateEntry(result, candidate, descriptor, requiredType);}}}}return result; }总结一下这个函数主要做了以下事情 先从 IoC 容器中查找指定类型的候选 Bean 集合实例化一个 MapString,Object 的集合result用来存储该类型对应的 候选依赖从 可解析依赖 里查找符合条件的候选并添加进 result 中从 候选 Bean 集合中找到 非自引用候选Bean 指向 当前Bean 或者 候选Bean 的 工厂Bean 执行当前Bean、并且BeanDefinition#autowire-candidate为true的候选Bean加入到result中结果为空的兜底经符合一定条件的候选 Bean 加入到 result 中将 result 返回得到最终的依赖源 综上我们可以得出一个结论依赖注入的来源包括两方面分别如下 依赖查找的来源可解析依赖 resolvableDependencies源码位于 org.springframework.beans.factory.support.DefaultListableBeanFactory#resolvableDependencies 本文总结 本篇我们介绍了依赖注入的使用方式和其注入原理并追根溯源定位的依赖的来源分析了依赖查找的来源以及依赖注入的来源。大家可以结合本篇文章进入到源码进行研读印象会更深刻。针对 Autowired 注解的使用和原理分析我放在了另一篇一文搞懂Spring Autowired注解的使用及其原理有兴趣的也可以去了解阅读下。
http://www.pierceye.com/news/52767/

相关文章:

  • nodejs做的网站深圳网站公司哪家好
  • 做类似58类型网站网页设计图片排版模板
  • 百度网站托管内蒙古网站备案怎么做
  • 做简历做得好的网站wordpress 企业站 模板
  • seo外链高质量网站kkday是哪里做的网站
  • 洛阳电商网站建设免费申请二级域名
  • 哈尔滨做网站的oeminc大芬地铁站附近做网站
  • 金融网站织梦模板专门看广告的网站
  • 东台网站网站建设商标设计怎么收费
  • 引擎优化seo陕西seo顾问服务
  • 河北城乡建设学校官方网站重庆seo俱乐部联系方式
  • 佛山网站的建设wordpress环境
  • 哈尔滨网站建设公司oemincwordpress更换域名2017
  • 虚拟体验网站收费下载的wordpress网站
  • 傻瓜式建设网站的软件域名备案服务
  • c 网站开发引擎厦门营销型网站建设
  • 建设网站报价单海南省建设网站的公司电话号码
  • 网站有收录就会排名吗网站建设域名和空间
  • 如何推广我的网站营业推广策划
  • 网站推广工作如何做有哪些好的模板网站
  • 网站的推广等内容手机首页设计
  • 怎么做 代刷网站网站流量分成
  • dw做网站基础行政单位门户网站建设规定
  • 温州做网站软件螺旋钢管网站建设
  • 网站备案信息核验单填写怎么创建网页快捷方式
  • wordpress下载站用什么模板百度识图在线入口
  • 福州高端品牌网站建设外包做一个网站一般费用
  • 云服务器可以放几个网站网站流量seo
  • 大连网站化妆品网站优化
  • 网站 一般 用什么空间网站制作 flash 修改